diff --git a/pyproject.toml b/pyproject.toml index a7fed2ee4..37e15dca6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ testpaths = [ ] [tool.black] -line-length = 200 +line-length = 500 [tool.isort] -line_length = 200 +line_length = 500 diff --git a/release-1.1.2-schemas-fixup/oscal_assessment-plan_schema.json b/release-1.1.2-schemas-fixup/oscal_assessment-plan_schema.json index 2ab0fa94c..407496dc6 100644 --- a/release-1.1.2-schemas-fixup/oscal_assessment-plan_schema.json +++ b/release-1.1.2-schemas-fixup/oscal_assessment-plan_schema.json @@ -2504,13 +2504,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user" - ] + "$ref": "#/definitions/AssessmentSubjectValidValues" } ] }, @@ -2578,14 +2572,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user", - "resource" - ] + "$ref": "#/definitions/SelectSubjectByIdValidValues" } ] }, @@ -2632,14 +2619,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user", - "resource" - ] + "$ref": "#/definitions/SubjectReferenceValidValues" } ] }, @@ -3055,13 +3035,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "ssp-statement-issue", - "control-objective", - "mitigation", - "finding", - "historic" - ] + "$ref": "#/definitions/ObservationTypeValidValues" } ] } @@ -3640,14 +3614,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "open", - "investigating", - "remediating", - "deviation-requested", - "deviation-approved", - "closed" - ] + "$ref": "#/definitions/RiskStatusValidValues" } ] }, @@ -3695,16 +3662,7 @@ "$ref": "#/definitions/URIDatatype" }, { - "enum": [ - "http://fedramp.gov", - "http://fedramp.gov/ns/oscal", - "http://csrc.nist.gov/ns/oscal", - "http://csrc.nist.gov/ns/oscal/unknown", - "http://cve.mitre.org", - "http://www.first.org/cvss/v2.0", - "http://www.first.org/cvss/v3.0", - "http://www.first.org/cvss/v3.1" - ] + "$ref": "#/definitions/NamingSystemValidValues" } ] }, @@ -4042,6 +4000,66 @@ "http://fedramp.gov", "http://fedramp.gov/ns/oscal" ] + }, + "SelectSubjectByIdValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user", + "resource" + ] + }, + "AssessmentSubjectValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user" + ] + }, + "NamingSystemValidValues": { + "enum": [ + "http://fedramp.gov", + "http://fedramp.gov/ns/oscal", + "http://csrc.nist.gov/ns/oscal", + "http://csrc.nist.gov/ns/oscal/unknown", + "http://cve.mitre.org", + "http://www.first.org/cvss/v2.0", + "http://www.first.org/cvss/v3.0", + "http://www.first.org/cvss/v3.1" + ] + }, + "SubjectReferenceValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user", + "resource" + ] + }, + "ObservationTypeValidValues": { + "enum": [ + "ssp-statement-issue", + "control-objective", + "mitigation", + "finding", + "historic" + ] + }, + "RiskStatusValidValues": { + "enum": [ + "open", + "investigating", + "remediating", + "deviation-requested", + "deviation-approved", + "closed" + ] } }, "properties": { diff --git a/release-1.1.2-schemas-fixup/oscal_assessment-results_schema.json b/release-1.1.2-schemas-fixup/oscal_assessment-results_schema.json index 26a72bf0b..3810ebf36 100644 --- a/release-1.1.2-schemas-fixup/oscal_assessment-results_schema.json +++ b/release-1.1.2-schemas-fixup/oscal_assessment-results_schema.json @@ -1743,259 +1743,6 @@ ], "additionalProperties": false }, - "oscal-ar-oscal-ar:result": { - "title": "Assessment Result", - "description": "Used by the assessment results and POA&M. In the assessment results, this identifies all of the assessment observations and findings, initial and residual risks, deviations, and disposition. In the POA&M, this identifies initial and residual risks, deviations, and disposition.", - "$id": "#assembly_oscal-ar_result", - "type": "object", - "properties": { - "uuid": { - "title": "Results Universally Unique Identifier", - "description": "A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this set of results in this or other OSCAL instances. The locally defined UUID of the assessment result can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.", - "$ref": "#/definitions/UUIDDatatype" - }, - "title": { - "title": "Results Title", - "description": "The title for this set of results.", - "type": "string" - }, - "description": { - "title": "Results Description", - "description": "A human-readable description of this set of test results.", - "type": "string" - }, - "start": { - "title": "start field", - "description": "Date/time stamp identifying the start of the evidence collection reflected in these results.", - "$ref": "#/definitions/DateTimeWithTimezoneDatatype" - }, - "end": { - "title": "end field", - "description": "Date/time stamp identifying the end of the evidence collection reflected in these results. In a continuous motoring scenario, this may contain the same value as start if appropriate.", - "$ref": "#/definitions/DateTimeWithTimezoneDatatype" - }, - "props": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_property" - } - }, - "links": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_link" - } - }, - "local-definitions": { - "title": "Local Definitions", - "description": "Used to define data objects that are used in the assessment plan, that do not appear in the referenced SSP.", - "type": "object", - "properties": { - "components": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-implementation-common_system-component" - } - }, - "inventory-items": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-implementation-common_inventory-item" - } - }, - "users": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-implementation-common_system-user" - } - }, - "assessment-assets": { - "$ref": "#assembly_oscal-assessment-common_assessment-assets" - }, - "tasks": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_task" - } - } - }, - "additionalProperties": false - }, - "reviewed-controls": { - "$ref": "#assembly_oscal-assessment-common_reviewed-controls" - }, - "attestations": { - "type": "array", - "minItems": 1, - "items": { - "title": "Attestation Statements", - "description": "A set of textual statements, typically written by the assessor.", - "type": "object", - "properties": { - "responsible-parties": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_responsible-party" - } - }, - "parts": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_assessment-part" - } - } - }, - "required": [ - "parts" - ], - "additionalProperties": false - } - }, - "assessment-log": { - "title": "Assessment Log", - "description": "A log of all assessment-related actions taken.", - "type": "object", - "properties": { - "entries": { - "type": "array", - "minItems": 1, - "items": { - "title": "Assessment Log Entry", - "description": "Identifies the result of an action and/or task that occurred as part of executing an assessment plan or an assessment event that occurred in producing the assessment results.", - "type": "object", - "properties": { - "uuid": { - "title": "Assessment Log Entry Universally Unique Identifier", - "description": "A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference an assessment event in this or other OSCAL instances. The locally defined UUID of the assessment log entry can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.", - "$ref": "#/definitions/UUIDDatatype" - }, - "title": { - "title": "Action Title", - "description": "The title for this event.", - "type": "string" - }, - "description": { - "title": "Action Description", - "description": "A human-readable description of this event.", - "type": "string" - }, - "start": { - "title": "Start", - "description": "Identifies the start date and time of an event.", - "$ref": "#/definitions/DateTimeWithTimezoneDatatype" - }, - "end": { - "title": "End", - "description": "Identifies the end date and time of an event. If the event is a point in time, the start and end will be the same date and time.", - "$ref": "#/definitions/DateTimeWithTimezoneDatatype" - }, - "props": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_property" - } - }, - "links": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_link" - } - }, - "logged-by": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_logged-by" - } - }, - "related-tasks": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_related-task" - } - }, - "remarks": { - "$ref": "#field_oscal-metadata_remarks" - } - }, - "required": [ - "uuid", - "start" - ], - "additionalProperties": false - } - } - }, - "required": [ - "entries" - ], - "additionalProperties": false - }, - "observations": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_observation" - } - }, - "risks": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_risk" - } - }, - "findings": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_finding" - } - }, - "remarks": { - "$ref": "#field_oscal-metadata_remarks" - } - }, - "required": [ - "uuid", - "title", - "description", - "start", - "reviewed-controls" - ], - "additionalProperties": false - }, - "oscal-ar-oscal-ar:import-ap": { - "title": "Import Assessment Plan", - "description": "Used by assessment-results to import information about the original plan for assessing the system.", - "$id": "#assembly_oscal-ar_import-ap", - "type": "object", - "properties": { - "href": { - "title": "Assessment Plan Reference", - "description": "A resolvable URL reference to the assessment plan governing the assessment activities.", - "$ref": "#/definitions/URIReferenceDatatype" - }, - "remarks": { - "$ref": "#field_oscal-metadata_remarks" - } - }, - "required": [ - "href" - ], - "additionalProperties": false - }, "oscal-ar-oscal-assessment-common:import-ssp": { "title": "Import System Security Plan", "description": "Used by the assessment plan and POA&M to import information about the system.", @@ -2708,13 +2455,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user" - ] + "$ref": "#/definitions/AssessmentSubjectValidValues" } ] }, @@ -2782,14 +2523,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user", - "resource" - ] + "$ref": "#/definitions/SelectSubjectByIdValidValues" } ] }, @@ -2836,14 +2570,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user", - "resource" - ] + "$ref": "#/definitions/SubjectReferenceValidValues" } ] }, @@ -3259,13 +2986,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "ssp-statement-issue", - "control-objective", - "mitigation", - "finding", - "historic" - ] + "$ref": "#/definitions/ObservationTypeValidValues" } ] } @@ -3844,14 +3565,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "open", - "investigating", - "remediating", - "deviation-requested", - "deviation-approved", - "closed" - ] + "$ref": "#/definitions/RiskStatusValidValues" } ] }, @@ -3899,16 +3613,7 @@ "$ref": "#/definitions/URIDatatype" }, { - "enum": [ - "http://fedramp.gov", - "http://fedramp.gov/ns/oscal", - "http://csrc.nist.gov/ns/oscal", - "http://csrc.nist.gov/ns/oscal/unknown", - "http://cve.mitre.org", - "http://www.first.org/cvss/v2.0", - "http://www.first.org/cvss/v3.0", - "http://www.first.org/cvss/v3.1" - ] + "$ref": "#/definitions/NamingSystemValidValues" } ] }, @@ -4156,6 +3861,259 @@ ], "additionalProperties": false }, + "oscal-ar-oscal-ar:result": { + "title": "Assessment Result", + "description": "Used by the assessment results and POA&M. In the assessment results, this identifies all of the assessment observations and findings, initial and residual risks, deviations, and disposition. In the POA&M, this identifies initial and residual risks, deviations, and disposition.", + "$id": "#assembly_oscal-ar_result", + "type": "object", + "properties": { + "uuid": { + "title": "Results Universally Unique Identifier", + "description": "A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this set of results in this or other OSCAL instances. The locally defined UUID of the assessment result can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.", + "$ref": "#/definitions/UUIDDatatype" + }, + "title": { + "title": "Results Title", + "description": "The title for this set of results.", + "type": "string" + }, + "description": { + "title": "Results Description", + "description": "A human-readable description of this set of test results.", + "type": "string" + }, + "start": { + "title": "start field", + "description": "Date/time stamp identifying the start of the evidence collection reflected in these results.", + "$ref": "#/definitions/DateTimeWithTimezoneDatatype" + }, + "end": { + "title": "end field", + "description": "Date/time stamp identifying the end of the evidence collection reflected in these results. In a continuous motoring scenario, this may contain the same value as start if appropriate.", + "$ref": "#/definitions/DateTimeWithTimezoneDatatype" + }, + "props": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_property" + } + }, + "links": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_link" + } + }, + "local-definitions": { + "title": "Local Definitions", + "description": "Used to define data objects that are used in the assessment plan, that do not appear in the referenced SSP.", + "type": "object", + "properties": { + "components": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-implementation-common_system-component" + } + }, + "inventory-items": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-implementation-common_inventory-item" + } + }, + "users": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-implementation-common_system-user" + } + }, + "assessment-assets": { + "$ref": "#assembly_oscal-assessment-common_assessment-assets" + }, + "tasks": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_task" + } + } + }, + "additionalProperties": false + }, + "reviewed-controls": { + "$ref": "#assembly_oscal-assessment-common_reviewed-controls" + }, + "attestations": { + "type": "array", + "minItems": 1, + "items": { + "title": "Attestation Statements", + "description": "A set of textual statements, typically written by the assessor.", + "type": "object", + "properties": { + "responsible-parties": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_responsible-party" + } + }, + "parts": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_assessment-part" + } + } + }, + "required": [ + "parts" + ], + "additionalProperties": false + } + }, + "assessment-log": { + "title": "Assessment Log", + "description": "A log of all assessment-related actions taken.", + "type": "object", + "properties": { + "entries": { + "type": "array", + "minItems": 1, + "items": { + "title": "Assessment Log Entry", + "description": "Identifies the result of an action and/or task that occurred as part of executing an assessment plan or an assessment event that occurred in producing the assessment results.", + "type": "object", + "properties": { + "uuid": { + "title": "Assessment Log Entry Universally Unique Identifier", + "description": "A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference an assessment event in this or other OSCAL instances. The locally defined UUID of the assessment log entry can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.", + "$ref": "#/definitions/UUIDDatatype" + }, + "title": { + "title": "Action Title", + "description": "The title for this event.", + "type": "string" + }, + "description": { + "title": "Action Description", + "description": "A human-readable description of this event.", + "type": "string" + }, + "start": { + "title": "Start", + "description": "Identifies the start date and time of an event.", + "$ref": "#/definitions/DateTimeWithTimezoneDatatype" + }, + "end": { + "title": "End", + "description": "Identifies the end date and time of an event. If the event is a point in time, the start and end will be the same date and time.", + "$ref": "#/definitions/DateTimeWithTimezoneDatatype" + }, + "props": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_property" + } + }, + "links": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_link" + } + }, + "logged-by": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_logged-by" + } + }, + "related-tasks": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_related-task" + } + }, + "remarks": { + "$ref": "#field_oscal-metadata_remarks" + } + }, + "required": [ + "uuid", + "start" + ], + "additionalProperties": false + } + } + }, + "required": [ + "entries" + ], + "additionalProperties": false + }, + "observations": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_observation" + } + }, + "risks": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_risk" + } + }, + "findings": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_finding" + } + }, + "remarks": { + "$ref": "#field_oscal-metadata_remarks" + } + }, + "required": [ + "uuid", + "title", + "description", + "start", + "reviewed-controls" + ], + "additionalProperties": false + }, + "oscal-ar-oscal-ar:import-ap": { + "title": "Import Assessment Plan", + "description": "Used by assessment-results to import information about the original plan for assessing the system.", + "$id": "#assembly_oscal-ar_import-ap", + "type": "object", + "properties": { + "href": { + "title": "Assessment Plan Reference", + "description": "A resolvable URL reference to the assessment plan governing the assessment activities.", + "$ref": "#/definitions/URIReferenceDatatype" + }, + "remarks": { + "$ref": "#field_oscal-metadata_remarks" + } + }, + "required": [ + "href" + ], + "additionalProperties": false + }, "Base64Datatype": { "description": "Binary data encoded using the Base 64 encoding algorithm as defined by RFC4648.", "type": "string", @@ -4246,6 +4204,66 @@ "http://fedramp.gov", "http://fedramp.gov/ns/oscal" ] + }, + "SelectSubjectByIdValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user", + "resource" + ] + }, + "AssessmentSubjectValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user" + ] + }, + "NamingSystemValidValues": { + "enum": [ + "http://fedramp.gov", + "http://fedramp.gov/ns/oscal", + "http://csrc.nist.gov/ns/oscal", + "http://csrc.nist.gov/ns/oscal/unknown", + "http://cve.mitre.org", + "http://www.first.org/cvss/v2.0", + "http://www.first.org/cvss/v3.0", + "http://www.first.org/cvss/v3.1" + ] + }, + "SubjectReferenceValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user", + "resource" + ] + }, + "ObservationTypeValidValues": { + "enum": [ + "ssp-statement-issue", + "control-objective", + "mitigation", + "finding", + "historic" + ] + }, + "RiskStatusValidValues": { + "enum": [ + "open", + "investigating", + "remediating", + "deviation-requested", + "deviation-approved", + "closed" + ] } }, "properties": { diff --git a/release-1.1.2-schemas-fixup/oscal_poam_schema.json b/release-1.1.2-schemas-fixup/oscal_poam_schema.json index 4fce96481..3ecd13e73 100644 --- a/release-1.1.2-schemas-fixup/oscal_poam_schema.json +++ b/release-1.1.2-schemas-fixup/oscal_poam_schema.json @@ -1744,162 +1744,6 @@ ], "additionalProperties": false }, - "oscal-poam-oscal-poam:local-definitions": { - "title": "Local Definitions", - "description": "Allows components, and inventory-items to be defined within the POA&M for circumstances where no OSCAL-based SSP exists, or is not delivered with the POA&M.", - "$id": "#assembly_oscal-poam_local-definitions", - "type": "object", - "properties": { - "components": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-implementation-common_system-component" - } - }, - "inventory-items": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-implementation-common_inventory-item" - } - }, - "assessment-assets": { - "$ref": "#assembly_oscal-assessment-common_assessment-assets" - }, - "remarks": { - "$ref": "#field_oscal-metadata_remarks" - } - }, - "additionalProperties": false - }, - "oscal-poam-oscal-poam:poam-item": { - "title": "POA&M Item", - "description": "Describes an individual POA&M item.", - "$id": "#assembly_oscal-poam_poam-item", - "type": "object", - "properties": { - "uuid": { - "title": "POA&M Item Universally Unique Identifier", - "description": "A machine-oriented, globally unique identifier with instance scope that can be used to reference this POA&M item entry in this OSCAL instance. This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.", - "$ref": "#/definitions/UUIDDatatype" - }, - "title": { - "title": "POA&M Item Title", - "description": "The title or name for this POA&M item .", - "type": "string" - }, - "description": { - "title": "POA&M Item Description", - "description": "A human-readable description of POA&M item.", - "type": "string" - }, - "props": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_property" - } - }, - "links": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-metadata_link" - } - }, - "related-findings": { - "type": "array", - "minItems": 1, - "items": { - "title": "Related Finding", - "description": "Relates the finding to referenced finding(s).", - "type": "object", - "properties": { - "finding-uuid": { - "title": "Finding Universally Unique Identifier Reference", - "description": "A machine-oriented identifier reference to a finding defined in the list of findings.", - "$ref": "#/definitions/UUIDDatatype" - } - }, - "required": [ - "finding-uuid" - ], - "additionalProperties": false - } - }, - "related-observations": { - "type": "array", - "minItems": 1, - "items": { - "title": "Related Observation", - "description": "Relates the finding to a set of referenced observations that were used to determine the finding.", - "type": "object", - "properties": { - "observation-uuid": { - "title": "Observation Universally Unique Identifier Reference", - "description": "A machine-oriented identifier reference to an observation defined in the list of observations.", - "$ref": "#/definitions/UUIDDatatype" - } - }, - "required": [ - "observation-uuid" - ], - "additionalProperties": false - } - }, - "related-risks": { - "type": "array", - "minItems": 1, - "items": { - "title": "Associated Risk", - "description": "Relates the finding to a set of referenced risks that were used to determine the finding.", - "type": "object", - "properties": { - "risk-uuid": { - "title": "Risk Universally Unique Identifier Reference", - "description": "A machine-oriented identifier reference to a risk defined in the list of risks.", - "$ref": "#/definitions/UUIDDatatype" - } - }, - "required": [ - "risk-uuid" - ], - "additionalProperties": false - } - }, - "remarks": { - "$ref": "#field_oscal-metadata_remarks" - }, - "originations": { - "type": "array", - "minItems": 1, - "items": { - "title": "Origin", - "description": "Identifies the source of the finding, such as a tool or person.", - "type": "object", - "properties": { - "actors": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#assembly_oscal-assessment-common_origin-actor" - } - } - }, - "required": [ - "actors" - ], - "additionalProperties": false - } - } - }, - "required": [ - "title", - "description" - ], - "additionalProperties": false - }, "oscal-poam-oscal-assessment-common:import-ssp": { "title": "Import System Security Plan", "description": "Used by the assessment plan and POA&M to import information about the system.", @@ -2612,13 +2456,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user" - ] + "$ref": "#/definitions/AssessmentSubjectValidValues" } ] }, @@ -2686,14 +2524,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user", - "resource" - ] + "$ref": "#/definitions/SelectSubjectByIdValidValues" } ] }, @@ -2740,14 +2571,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "component", - "inventory-item", - "location", - "party", - "user", - "resource" - ] + "$ref": "#/definitions/SubjectReferenceValidValues" } ] }, @@ -3163,13 +2987,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "ssp-statement-issue", - "control-objective", - "mitigation", - "finding", - "historic" - ] + "$ref": "#/definitions/ObservationTypeValidValues" } ] } @@ -3748,14 +3566,7 @@ "$ref": "#/definitions/TokenDatatype" }, { - "enum": [ - "open", - "investigating", - "remediating", - "deviation-requested", - "deviation-approved", - "closed" - ] + "$ref": "#/definitions/RiskStatusValidValues" } ] }, @@ -3803,16 +3614,7 @@ "$ref": "#/definitions/URIDatatype" }, { - "enum": [ - "http://fedramp.gov", - "http://fedramp.gov/ns/oscal", - "http://csrc.nist.gov/ns/oscal", - "http://csrc.nist.gov/ns/oscal/unknown", - "http://cve.mitre.org", - "http://www.first.org/cvss/v2.0", - "http://www.first.org/cvss/v3.0", - "http://www.first.org/cvss/v3.1" - ] + "$ref": "#/definitions/NamingSystemValidValues" } ] }, @@ -4060,6 +3862,162 @@ ], "additionalProperties": false }, + "oscal-poam-oscal-poam:local-definitions": { + "title": "Local Definitions", + "description": "Allows components, and inventory-items to be defined within the POA&M for circumstances where no OSCAL-based SSP exists, or is not delivered with the POA&M.", + "$id": "#assembly_oscal-poam_local-definitions", + "type": "object", + "properties": { + "components": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-implementation-common_system-component" + } + }, + "inventory-items": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-implementation-common_inventory-item" + } + }, + "assessment-assets": { + "$ref": "#assembly_oscal-assessment-common_assessment-assets" + }, + "remarks": { + "$ref": "#field_oscal-metadata_remarks" + } + }, + "additionalProperties": false + }, + "oscal-poam-oscal-poam:poam-item": { + "title": "POA&M Item", + "description": "Describes an individual POA&M item.", + "$id": "#assembly_oscal-poam_poam-item", + "type": "object", + "properties": { + "uuid": { + "title": "POA&M Item Universally Unique Identifier", + "description": "A machine-oriented, globally unique identifier with instance scope that can be used to reference this POA&M item entry in this OSCAL instance. This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.", + "$ref": "#/definitions/UUIDDatatype" + }, + "title": { + "title": "POA&M Item Title", + "description": "The title or name for this POA&M item .", + "type": "string" + }, + "description": { + "title": "POA&M Item Description", + "description": "A human-readable description of POA&M item.", + "type": "string" + }, + "props": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_property" + } + }, + "links": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-metadata_link" + } + }, + "related-findings": { + "type": "array", + "minItems": 1, + "items": { + "title": "Related Finding", + "description": "Relates the finding to referenced finding(s).", + "type": "object", + "properties": { + "finding-uuid": { + "title": "Finding Universally Unique Identifier Reference", + "description": "A machine-oriented identifier reference to a finding defined in the list of findings.", + "$ref": "#/definitions/UUIDDatatype" + } + }, + "required": [ + "finding-uuid" + ], + "additionalProperties": false + } + }, + "related-observations": { + "type": "array", + "minItems": 1, + "items": { + "title": "Related Observation", + "description": "Relates the finding to a set of referenced observations that were used to determine the finding.", + "type": "object", + "properties": { + "observation-uuid": { + "title": "Observation Universally Unique Identifier Reference", + "description": "A machine-oriented identifier reference to an observation defined in the list of observations.", + "$ref": "#/definitions/UUIDDatatype" + } + }, + "required": [ + "observation-uuid" + ], + "additionalProperties": false + } + }, + "related-risks": { + "type": "array", + "minItems": 1, + "items": { + "title": "Associated Risk", + "description": "Relates the finding to a set of referenced risks that were used to determine the finding.", + "type": "object", + "properties": { + "risk-uuid": { + "title": "Risk Universally Unique Identifier Reference", + "description": "A machine-oriented identifier reference to a risk defined in the list of risks.", + "$ref": "#/definitions/UUIDDatatype" + } + }, + "required": [ + "risk-uuid" + ], + "additionalProperties": false + } + }, + "remarks": { + "$ref": "#field_oscal-metadata_remarks" + }, + "originations": { + "type": "array", + "minItems": 1, + "items": { + "title": "Origin", + "description": "Identifies the source of the finding, such as a tool or person.", + "type": "object", + "properties": { + "actors": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#assembly_oscal-assessment-common_origin-actor" + } + } + }, + "required": [ + "actors" + ], + "additionalProperties": false + } + } + }, + "required": [ + "title", + "description" + ], + "additionalProperties": false + }, "Base64Datatype": { "description": "Binary data encoded using the Base 64 encoding algorithm as defined by RFC4648.", "type": "string", @@ -4150,6 +4108,66 @@ "http://fedramp.gov", "http://fedramp.gov/ns/oscal" ] + }, + "SelectSubjectByIdValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user", + "resource" + ] + }, + "AssessmentSubjectValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user" + ] + }, + "NamingSystemValidValues": { + "enum": [ + "http://fedramp.gov", + "http://fedramp.gov/ns/oscal", + "http://csrc.nist.gov/ns/oscal", + "http://csrc.nist.gov/ns/oscal/unknown", + "http://cve.mitre.org", + "http://www.first.org/cvss/v2.0", + "http://www.first.org/cvss/v3.0", + "http://www.first.org/cvss/v3.1" + ] + }, + "SubjectReferenceValidValues": { + "enum": [ + "component", + "inventory-item", + "location", + "party", + "user", + "resource" + ] + }, + "ObservationTypeValidValues": { + "enum": [ + "ssp-statement-issue", + "control-objective", + "mitigation", + "finding", + "historic" + ] + }, + "RiskStatusValidValues": { + "enum": [ + "open", + "investigating", + "remediating", + "deviation-requested", + "deviation-approved", + "closed" + ] } }, "properties": { diff --git a/release-1.1.2-schemas-fixup/oscal_profile_schema.json b/release-1.1.2-schemas-fixup/oscal_profile_schema.json index 9f6f2c191..40f6d198f 100644 --- a/release-1.1.2-schemas-fixup/oscal_profile_schema.json +++ b/release-1.1.2-schemas-fixup/oscal_profile_schema.json @@ -1260,14 +1260,14 @@ "type": "array", "minItems": 1, "items": { - "$ref": "#assembly_oscal-profile_select-control-by-id" + "$ref": "#assembly_oscal-profile_select-control" } }, "exclude-controls": { "type": "array", "minItems": 1, "items": { - "$ref": "#assembly_oscal-profile_select-control-by-id" + "$ref": "#assembly_oscal-profile_select-control" } } }, @@ -1665,23 +1665,23 @@ "type": "array", "minItems": 1, "items": { - "$ref": "#assembly_oscal-profile_select-control-by-id" + "$ref": "#assembly_oscal-profile_select-control" } }, "exclude-controls": { "type": "array", "minItems": 1, "items": { - "$ref": "#assembly_oscal-profile_select-control-by-id" + "$ref": "#assembly_oscal-profile_select-control" } } }, "additionalProperties": false }, - "oscal-profile-oscal-profile:select-control-by-id": { + "oscal-profile-oscal-profile:select-control": { "title": "Select Control", "description": "Select a control or controls from an imported control set.", - "$id": "#assembly_oscal-profile_select-control-by-id", + "$id": "#assembly_oscal-profile_select-control", "type": "object", "properties": { "with-child-controls": { diff --git a/scripts/oscal_normalize.py b/scripts/oscal_normalize.py index 61ec79a6e..1d0c681d5 100644 --- a/scripts/oscal_normalize.py +++ b/scripts/oscal_normalize.py @@ -737,7 +737,6 @@ def write_oscal(classes, forward_refs, fstem): additions = { 'assessment_plan': [ 'from trestle.oscal.common import RelatedObservation', - 'from trestle.oscal.common import RiskStatus1', 'from trestle.oscal.common import SystemComponent', 'from trestle.oscal.common import TaskValidValues', 'from trestle.oscal.common import TokenDatatype', @@ -746,7 +745,6 @@ def write_oscal(classes, forward_refs, fstem): 'from trestle.oscal.common import AssessmentAssets', 'from trestle.oscal.common import Observation', 'from trestle.oscal.common import RelatedObservation', - 'from trestle.oscal.common import RiskStatus1', 'from trestle.oscal.common import SystemComponent', 'from trestle.oscal.common import TaskValidValues', 'from trestle.oscal.common import TokenDatatype', @@ -756,7 +754,6 @@ def write_oscal(classes, forward_refs, fstem): ], 'poam': [ 'from trestle.oscal.common import RelatedObservation', - 'from trestle.oscal.common import RiskStatus1', 'from trestle.oscal.common import TaskValidValues', 'from trestle.oscal.common import TokenDatatype', 'from trestle.oscal.common import RelatedObservation as RelatedObservation1', @@ -986,7 +983,10 @@ def kill_roots(file_classes): line = c.lines[ii] for name, body in new_root_classes.items(): # handle special case - if any(token in line for token in ['id: TokenDatatype', 'value: StringDatatype']): + if any(token in line for token in ['id: TokenDatatype', + 'value: StringDatatype', + 'uuid: UUIDDatatype', + 'uuid: Optional[UUIDDatatype]']): line = line.replace(name, body, 1) continue if 'title=' in line and 'Value' in line: diff --git a/scripts/schema_preprocess.py b/scripts/schema_preprocess.py index 0b096e3ce..16a60558a 100644 --- a/scripts/schema_preprocess.py +++ b/scripts/schema_preprocess.py @@ -18,7 +18,7 @@ import logging import os from pathlib import Path -from typing import Any, Dict +from typing import Any, Dict, List logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -80,6 +80,7 @@ def patch_schemas(fixup_dir_path: Path, patch_file_path: Path) -> None: patch_poam_origins(model_name) patch_poam_item(model_name, 'related-findings') patch_poam_item(model_name, 'related-observations') + patch_profile(model_name) create_refs(model_name) @@ -182,6 +183,35 @@ def patch_poam_item(model_name: str, k3: str) -> None: json_data_put(model_name, data) +def patch_profile(model_name: str) -> None: + """Patch profile.""" + if not model_name.endswith('oscal_profile_schema.json'): + return + old_data = data_get(model_name) + new_data = [] + old_value = 'select-control-by-id' + new_value = 'select-control' + count = 0 + for line in old_data: + if old_value in line: + count += 1 + line = line.replace(old_value, new_value) + new_data.append(line) + logger.info(f'patch: {model_name} {old_value} -> {new_value}, count={count}') + data_put(model_name, new_data) + # format + data = json_data_get(model_name) + json_data_put(model_name, data) + + +def _find(needle: str, haystack: Dict) -> Any: + """Find needle in haystack.""" + for item in haystack: + if item == needle: + return haystack[item] + return None + + # Create refs for common elements def create_refs(model_name: str) -> None: """Create refs.""" @@ -201,134 +231,58 @@ def create_refs(model_name: str) -> None: ] for key in list_: create_ref_threat_id_valid_values(model_name, key) - - -# Create refs for common elements -def _create_refs_tbd(model_name: str) -> None: - """Create refs.""" - # Naming System Valid Values - list_ = [ - 'oscal-ap-oscal-assessment-common:characterization', - 'oscal-ar-oscal-assessment-common:characterization', - 'oscal-poam-oscal-assessment-common:characterization', - ] - for key in list_: - create_ref_naming_system_valid_values(model_name, key) - # Observation Valid Values - list_ = [ - 'oscal-ap-oscal-assessment-common:observation', - 'oscal-ar-oscal-assessment-common:observation', - 'oscal-poam-oscal-assessment-common:observation', - ] - for key in list_: - create_ref_observation_valid_values(model_name, key) - # System Component Valid Values - list_ = [ - 'oscal-ap-oscal-implementation-common:system-component', - 'oscal-ar-oscal-implementation-common:system-component', - 'oscal-poam-oscal-implementation-common:system-component', - 'oscal-ssp-oscal-implementation-common:system-component', - ] - for key in list_: - create_ref_system_component_valid_values(model_name, key) - # Defined Component Valid Values - list_ = [ - 'oscal-component-definition-oscal-component-definition:defined-component', - ] - for key in list_: - create_ref_defined_component_valid_values(model_name, key) - # Assessment Subject Valid Values + # Select Subject By Id Valid Values list_ = [ 'oscal-ap-oscal-assessment-common:select-subject-by-id', - 'oscal-ap-oscal-assessment-common:subject-reference', 'oscal-ar-oscal-assessment-common:select-subject-by-id', - 'oscal-ar-oscal-assessment-common:subject-reference', 'oscal-poam-oscal-assessment-common:select-subject-by-id', - 'oscal-poam-oscal-assessment-common:subject-reference', ] for key in list_: - create_ref_assessment_subject_valid_values(model_name, key) - # Subject Valid Values + create_ref_select_subject_by_id_valid_values(model_name, key) + # Assessment Subject Valid Values list_ = [ 'oscal-ap-oscal-assessment-common:assessment-subject', 'oscal-ar-oscal-assessment-common:assessment-subject', 'oscal-poam-oscal-assessment-common:assessment-subject', ] for key in list_: - create_ref_subject_valid_values(model_name, key) - # Address Valid Values + create_ref_assessment_subject_valid_values(model_name, key) + # Naming System Valid Values list_ = [ - 'oscal-ap-oscal-metadata:address', - 'oscal-ar-oscal-metadata:address', - 'oscal-catalog-oscal-metadata:address', - 'oscal-component-definition-oscal-metadata:address', - 'oscal-poam-oscal-metadata:address', - 'oscal-profile-oscal-metadata:address', - 'oscal-ssp-oscal-metadata:address', + 'oscal-ap-oscal-assessment-common:characterization', + 'oscal-ar-oscal-assessment-common:characterization', + 'oscal-poam-oscal-assessment-common:characterization', ] for key in list_: - create_ref_address_valid_values(model_name, key) - # Telephone Valid Values + create_ref_naming_system_valid_values(model_name, key) + # Subject Reference Valid Values list_ = [ - 'oscal-ap-oscal-metadata:telephone-number', - 'oscal-ar-oscal-metadata:telephone-number', - 'oscal-catalog-oscal-metadata:telephone-number', - 'oscal-component-definition-oscal-metadata:telephone-number', - 'oscal-poam-oscal-metadata:telephone-number', - 'oscal-profile-oscal-metadata:telephone-number', - 'oscal-ssp-oscal-metadata:telephone-number', + 'oscal-ap-oscal-assessment-common:subject-reference', + 'oscal-ar-oscal-assessment-common:subject-reference', + 'oscal-poam-oscal-assessment-common:subject-reference', + ] + for key in list_: + create_ref_subject_reference_valid_values(model_name, key) + # Subject Reference Valid Values + list_ = [ + 'oscal-ap-oscal-assessment-common:observation', + 'oscal-ar-oscal-assessment-common:observation', + 'oscal-poam-oscal-assessment-common:observation', ] for key in list_: - create_ref_telephone_valid_values(model_name, key) - # Associated Risk Status Valid Values + create_ref_observation_type_valid_values(model_name, key) + # Risk Status Valid Values list_ = [ 'oscal-ap-oscal-assessment-common:risk-status', 'oscal-ar-oscal-assessment-common:risk-status', 'oscal-poam-oscal-assessment-common:risk-status', ] for key in list_: - create_ref_associated_risk_status_valid_values(model_name, key) - - -def _find(needle: str, haystack: Dict) -> Any: - """Find needle in haystack.""" - for item in haystack: - if item == needle: - return haystack[item] - return None - - -def create_ref_naming_system_valid_values(model_name: str, k1: str) -> None: - """Create ref for Naming System Valid Values.""" - data = json_data_get(model_name) - tgt = data['definitions'] - tgt = tgt.get(k1) - if not tgt: - return - k2 = 'properties' - tgt = tgt.get(k2) - k3 = 'facets' - tgt = _find(k3, tgt) - k4 = 'items' - tgt = _find(k4, tgt) - k5 = 'properties' - tgt = _find(k5, tgt) - k6 = 'system' - tgt = _find(k6, tgt) - k7 = 'anyOf' - tgt = tgt.get(k7) - key = 'NamingSystemValidValues' - item = tgt[1] - replacement = {'$ref': f'#/definitions/{key}'} - tgt[1] = replacement - tgt = data['definitions'] - tgt[key] = item - logger.info(f'patch: {model_name} {replacement}') - json_data_put(model_name, data) + create_ref_risk_status_valid_values(model_name, key) -def create_ref_observation_valid_values(model_name: str, k1: str) -> None: - """Create ref for Observation Valid Values.""" +def create_ref_task_valid_values(model_name: str, k1: str) -> None: + """Create ref for Task Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) @@ -336,13 +290,11 @@ def create_ref_observation_valid_values(model_name: str, k1: str) -> None: return k2 = 'properties' tgt = tgt.get(k2) - k3 = 'types' + k3 = 'type' tgt = _find(k3, tgt) - k4 = 'items' - tgt = tgt = tgt.get(k4) - k5 = 'anyOf' - tgt = tgt.get(k5) - key = 'ObservationValidValues' + k4 = 'anyOf' + tgt = tgt.get(k4) + key = 'TaskValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -352,8 +304,8 @@ def create_ref_observation_valid_values(model_name: str, k1: str) -> None: json_data_put(model_name, data) -def create_ref_system_component_valid_values(model_name: str, k1: str) -> None: - """Create ref for System Component Valid Values.""" +def create_ref_threat_id_valid_values(model_name: str, k1: str) -> None: + """Create ref for Threat Id Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) @@ -361,11 +313,11 @@ def create_ref_system_component_valid_values(model_name: str, k1: str) -> None: return k2 = 'properties' tgt = tgt.get(k2) - k3 = 'type' + k3 = 'system' tgt = _find(k3, tgt) k4 = 'anyOf' tgt = tgt.get(k4) - key = 'SystemComponentValidValues' + key = 'ThreatIdValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -375,8 +327,8 @@ def create_ref_system_component_valid_values(model_name: str, k1: str) -> None: json_data_put(model_name, data) -def create_ref_defined_component_valid_values(model_name: str, k1: str) -> None: - """Create ref for Defined Component Valid Values.""" +def create_ref_select_subject_by_id_valid_values(model_name: str, k1: str) -> None: + """Create ref for Select Subject By Id Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) @@ -388,7 +340,7 @@ def create_ref_defined_component_valid_values(model_name: str, k1: str) -> None: tgt = _find(k3, tgt) k4 = 'anyOf' tgt = tgt.get(k4) - key = 'DefinedComponentValidValues' + key = 'SelectSubjectByIdValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -421,8 +373,8 @@ def create_ref_assessment_subject_valid_values(model_name: str, k1: str) -> None json_data_put(model_name, data) -def create_ref_subject_valid_values(model_name: str, k1: str) -> None: - """Create ref for Subject Valid Values.""" +def create_ref_naming_system_valid_values(model_name: str, k1: str) -> None: + """Create ref for Naming System Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) @@ -430,11 +382,17 @@ def create_ref_subject_valid_values(model_name: str, k1: str) -> None: return k2 = 'properties' tgt = tgt.get(k2) - k3 = 'type' + k3 = 'facets' tgt = _find(k3, tgt) - k4 = 'anyOf' - tgt = tgt.get(k4) - key = 'SubjectValidValues' + k4 = 'items' + tgt = _find(k4, tgt) + k5 = 'properties' + tgt = _find(k5, tgt) + k6 = 'system' + tgt = _find(k6, tgt) + k7 = 'anyOf' + tgt = tgt.get(k7) + key = 'NamingSystemValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -444,8 +402,8 @@ def create_ref_subject_valid_values(model_name: str, k1: str) -> None: json_data_put(model_name, data) -def create_ref_task_valid_values(model_name: str, k1: str) -> None: - """Create ref for Task Valid Values.""" +def create_ref_subject_reference_valid_values(model_name: str, k1: str) -> None: + """Create ref for Subject Reference Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) @@ -457,7 +415,7 @@ def create_ref_task_valid_values(model_name: str, k1: str) -> None: tgt = _find(k3, tgt) k4 = 'anyOf' tgt = tgt.get(k4) - key = 'TaskValidValues' + key = 'SubjectReferenceValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -467,8 +425,8 @@ def create_ref_task_valid_values(model_name: str, k1: str) -> None: json_data_put(model_name, data) -def create_ref_address_valid_values(model_name: str, k1: str) -> None: - """Create ref for Address Valid Values.""" +def create_ref_observation_type_valid_values(model_name: str, k1: str) -> None: + """Create ref for Observation Type Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) @@ -476,11 +434,13 @@ def create_ref_address_valid_values(model_name: str, k1: str) -> None: return k2 = 'properties' tgt = tgt.get(k2) - k3 = 'type' + k3 = 'types' tgt = _find(k3, tgt) - k4 = 'anyOf' + k4 = 'items' tgt = tgt.get(k4) - key = 'AddressValidValues' + k5 = 'anyOf' + tgt = tgt.get(k5) + key = 'ObservationTypeValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -490,20 +450,16 @@ def create_ref_address_valid_values(model_name: str, k1: str) -> None: json_data_put(model_name, data) -def create_ref_telephone_valid_values(model_name: str, k1: str) -> None: - """Create ref for Telephone Valid Values.""" +def create_ref_risk_status_valid_values(model_name: str, k1: str) -> None: + """Create ref for Risk Status Valid Values.""" data = json_data_get(model_name) tgt = data['definitions'] tgt = tgt.get(k1) if not tgt: return - k2 = 'properties' + k2 = 'anyOf' tgt = tgt.get(k2) - k3 = 'type' - tgt = _find(k3, tgt) - k4 = 'anyOf' - tgt = tgt.get(k4) - key = 'Telephone Valid Values' + key = 'RiskStatusValidValues' item = tgt[1] replacement = {'$ref': f'#/definitions/{key}'} tgt[1] = replacement @@ -513,46 +469,20 @@ def create_ref_telephone_valid_values(model_name: str, k1: str) -> None: json_data_put(model_name, data) -def create_ref_threat_id_valid_values(model_name: str, k1: str) -> None: - """Create ref for Threat Id Valid Values.""" - data = json_data_get(model_name) - tgt = data['definitions'] - tgt = tgt.get(k1) - if not tgt: - return - k2 = 'properties' - tgt = tgt.get(k2) - k3 = 'system' - tgt = _find(k3, tgt) - k4 = 'anyOf' - tgt = tgt.get(k4) - key = 'ThreatIdValidValues' - item = tgt[1] - replacement = {'$ref': f'#/definitions/{key}'} - tgt[1] = replacement - tgt = data['definitions'] - tgt[key] = item - logger.info(f'patch: {model_name} {replacement}') - json_data_put(model_name, data) +def data_get(model_name: str) -> List: + """Get data.""" + data = [] + with open(model_name, 'r') as f: + for line in f: + data.append(line.strip()) + return data -def create_ref_associated_risk_status_valid_values(model_name: str, k1: str) -> None: - """Create ref for Associated Risk Status Valid Values.""" - data = json_data_get(model_name) - tgt = data['definitions'] - tgt = tgt.get(k1) - if not tgt: - return - k2 = 'anyOf' - tgt = tgt.get(k2) - key = 'AssociatedRiskStatusValidValues' - item = tgt[1] - replacement = {'$ref': f'#/definitions/{key}'} - tgt[1] = replacement - tgt = data['definitions'] - tgt[key] = item - logger.info(f'patch: {model_name} {replacement}') - json_data_put(model_name, data) +def data_put(model_name: str, data: List) -> None: + """Put data.""" + with open(model_name, 'w') as f: + for line in data: + f.write(f'{line}\n') def json_data_get(model_name: str) -> Dict: @@ -580,35 +510,41 @@ def fixup_json(fixup_dir_path: Path) -> None: def get_order(key: str) -> int: """Get order.""" - if 'json-schema-directive' in key: - return 0 - if key.endswith('ap:assessment-plan'): - return 1 - if key.endswith('ar:assessment-results'): - return 1 - if key.endswith('catalog:catalog'): - return 1 - if key.endswith('component-definition:component-definition'): - return 1 - if key.endswith('poam:plan-of-action-and-milestones'): - return 1 - if key.endswith('profile:profile'): - return 1 - if key.endswith('ssp:system-security-plan'): - return 1 - if 'oscal-metadata:' in key: - return 2 - if 'oscal-control-common:' in key: - return 3 - if 'oscal-implementation-common:' in key: - return 4 - return 5 + if key != 'range': + if 'json-schema-directive' in key: + return 0 + if key.endswith('ap:assessment-plan'): + return 1 + if key.endswith('ar:assessment-results'): + return 1 + if key.endswith('catalog:catalog'): + return 1 + if key.endswith('component-definition:component-definition'): + return 1 + if key.endswith('poam:plan-of-action-and-milestones'): + return 1 + if key.endswith('profile:profile'): + return 1 + if key.endswith('ssp:system-security-plan'): + return 1 + if 'oscal-metadata:' in key: + return 2 + if 'oscal-control-common:' in key: + return 3 + if 'oscal-implementation-common:' in key: + return 4 + if 'oscal-assessment-common:' in key: + return 5 + return 6 + else: + # range = 1 + the highest number above + return 7 def names_reorder(data: Dict) -> None: """Reorder.""" reorder_defs = {} - for index in range(6): + for index in range(get_order('range')): for key in data['definitions'].keys(): order = get_order(key) if order == index: diff --git a/trestle/core/commands/author/profile.py b/trestle/core/commands/author/profile.py index c2469cfe6..5a7a54db2 100644 --- a/trestle/core/commands/author/profile.py +++ b/trestle/core/commands/author/profile.py @@ -638,8 +638,8 @@ def update_profile_import( include_with_ids: Set[str] = catalog_control_ids - exclude_with_ids - orig_prof_import.include_controls = [prof.SelectControlById(with_ids=sorted(include_with_ids))] - orig_prof_import.exclude_controls = [prof.SelectControlById(with_ids=sorted(exclude_with_ids))] + orig_prof_import.include_controls = [prof.SelectControl(with_ids=sorted(include_with_ids))] + orig_prof_import.exclude_controls = [prof.SelectControl(with_ids=sorted(exclude_with_ids))] def initialize_profile( self, diff --git a/trestle/core/generators.py b/trestle/core/generators.py index 662498f94..5fb535e59 100644 --- a/trestle/core/generators.py +++ b/trestle/core/generators.py @@ -32,7 +32,7 @@ from trestle.common.str_utils import AliasMode from trestle.core.base_model import OscalBaseModel from trestle.oscal import OSCAL_VERSION -from trestle.oscal.common import Base64, Base64Datatype, Methods, TaskValidValues +from trestle.oscal.common import Base64, Base64Datatype, Methods, ObservationTypeValidValues, TaskValidValues from trestle.oscal.ssp import DateDatatype logger = logging.getLogger(__name__) @@ -48,6 +48,8 @@ sample_task_valid_value = TaskValidValues.milestone sample_method = Methods.EXAMINE +sample_observation_type_valid_value = ObservationTypeValidValues.historic + def safe_is_sub(sub: Any, parent: Any) -> bool: """Is this a subclass of parent.""" @@ -79,6 +81,18 @@ def is_enum_task_valid_value(type_: type) -> bool: return rval +def is_enum_observation_type_valid_value(type_: type) -> bool: + """Test for observation type valid value.""" + rval = False + if utils.get_origin(type_) == Union: + args = typing.get_args(type_) + for arg in args: + if "" == f'{arg}': + rval = True + break + return rval + + def generate_sample_value_by_type( type_: type, field_name: str, @@ -92,6 +106,8 @@ def generate_sample_value_by_type( return sample_method if is_enum_task_valid_value(type_): return sample_task_valid_value + if is_enum_observation_type_valid_value(type_): + return sample_observation_type_valid_value if type_ is Base64: return sample_base64 if type_ is datetime: @@ -211,14 +227,22 @@ def generate_sample_model( outer_type, include_optional=include_optional, depth=depth - 1 ) else: + # Handle special cases (hacking) + if model_type in [Base64Datatype]: + model_dict[field] = sample_base64_value + elif model_type in [Base64]: + if field == 'filename': + model_dict[field] = sample_base64.filename + elif field == 'media_type': + model_dict[field] = sample_base64.media_type + elif field == 'value': + model_dict[field] = sample_base64.value + elif model_type in [DateDatatype]: + model_dict[field] = sample_date_value # Hacking here: # Root models should ideally not exist, however, sometimes we are stuck with them. # If that is the case we need sufficient information on the type in order to generate a model. # E.g. we need the type of the container. - if model_type in [Base64, Base64Datatype]: - model_dict[field] = sample_base64_value - elif model_type in [DateDatatype]: - model_dict[field] = sample_date_value elif field == '__root__' and hasattr(model, '__name__'): model_dict[field] = generate_sample_value_by_type( outer_type, str_utils.classname_to_alias(model.__name__, AliasMode.FIELD) diff --git a/trestle/core/resolver/prune.py b/trestle/core/resolver/prune.py index e00afe870..1c64e8b59 100644 --- a/trestle/core/resolver/prune.py +++ b/trestle/core/resolver/prune.py @@ -50,12 +50,12 @@ def _set_catalog(self, catalog: cat.Catalog) -> None: self._catalog_interface = CatalogInterface(catalog) self._catalog = catalog - def _controls_selected(self, select_list: Optional[List[prof.SelectControlById]]) -> List[str]: + def _controls_selected(self, select_list: Optional[List[prof.SelectControl]]) -> List[str]: control_ids: List[str] = [] if select_list is not None: for select_control in select_list: if select_control.matching is not None: - raise TrestleError('Profiles with SelectControlById based on matching are not supported.') + raise TrestleError('Profiles with SelectControl based on matching are not supported.') include_children = select_control.with_child_controls == 'yes' if select_control.with_ids: new_ids = select_control.with_ids diff --git a/trestle/oscal/assessment_plan.py b/trestle/oscal/assessment_plan.py index 39a215195..08bcc5802 100644 --- a/trestle/oscal/assessment_plan.py +++ b/trestle/oscal/assessment_plan.py @@ -35,24 +35,11 @@ from trestle.oscal import OSCAL_VERSION_REGEX, OSCAL_VERSION import trestle.oscal.common as common from trestle.oscal.common import RelatedObservation -from trestle.oscal.common import RiskStatus1 from trestle.oscal.common import SystemComponent from trestle.oscal.common import TaskValidValues from trestle.oscal.common import TokenDatatype -class Type3(Enum): - """ - Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement. - """ - - component = 'component' - inventory_item = 'inventory-item' - location = 'location' - party = 'party' - user = 'user' - - class TermsAndConditions(OscalBaseModel): """ Used to define various terms and conditions under which an assessment, described by the plan, can be performed. Each child part defines a different type of term or condition. @@ -64,47 +51,6 @@ class Config: parts: Optional[List[common.AssessmentPart]] = Field(None) -class System(Enum): - """ - Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash. - """ - - http___fedramp_gov = 'http://fedramp.gov' - http___fedramp_gov_ns_oscal = 'http://fedramp.gov/ns/oscal' - http___csrc_nist_gov_ns_oscal = 'http://csrc.nist.gov/ns/oscal' - http___csrc_nist_gov_ns_oscal_unknown = 'http://csrc.nist.gov/ns/oscal/unknown' - http___cve_mitre_org = 'http://cve.mitre.org' - http___www_first_org_cvss_v2_0 = 'http://www.first.org/cvss/v2.0' - http___www_first_org_cvss_v3_0 = 'http://www.first.org/cvss/v3.0' - http___www_first_org_cvss_v3_1 = 'http://www.first.org/cvss/v3.1' - - -class SelectControlById(OscalBaseModel): - """ - Used to select a control for inclusion/exclusion based on one or more control identifiers. A set of statement identifiers can be used to target the inclusion/exclusion to only specific control statements providing more granularity over the specific statements that are within the asessment scope. - """ - - class Config: - extra = Extra.forbid - - control_id: constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ) = Field( - ..., - alias='control-id', - description= - 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', - ) - statement_ids: Optional[List[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - )]] = Field( - None, alias='statement-ids' - ) - - class LocalDefinitions(OscalBaseModel): """ Used to define data objects that are used in the assessment plan, that do not appear in the referenced SSP. @@ -121,238 +67,6 @@ class Config: remarks: Optional[str] = None -class Facet(OscalBaseModel): - """ - An individual characteristic that is part of a larger set produced by the same actor. - """ - - class Config: - extra = Extra.forbid - - name: constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ) = Field(..., description='The name of the risk metric within the specified system.', title='Facet Name') - system: Union[AnyUrl, System] = Field( - ..., - description= - 'Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash.', - title='Naming System', - ) - value: constr(regex=r'^\S(.*\S)?$' - ) = Field(..., description='Indicates the value of the facet.', title='Facet Value') - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - remarks: Optional[str] = None - - -class Entry(OscalBaseModel): - """ - Identifies an individual risk response that occurred as part of managing an identified risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk log entry elsewhere in this or other OSCAL instances. The locally defined UUID of the risk log entry can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Risk Log Entry Universally Unique Identifier', - ) - title: Optional[str] = Field(None, description='The title for this risk log entry.', title='Title') - description: Optional[str] = Field( - None, - description='A human-readable description of what was done regarding the risk.', - title='Risk Task Description' - ) - start: datetime = Field(..., description='Identifies the start date and time of the event.', title='Start') - end: Optional[datetime] = Field( - None, - description= - 'Identifies the end date and time of the event. If the event is a point in time, the start and end will be the same date and time.', - title='End' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - logged_by: Optional[List[common.LoggedBy]] = Field(None, alias='logged-by') - status_change: Optional[Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - RiskStatus1]] = Field( - None, alias='status-change' - ) - related_responses: Optional[List[common.RelatedResponse]] = Field(None, alias='related-responses') - remarks: Optional[str] = None - - -class Characterization(OscalBaseModel): - """ - A collection of descriptive data about the containing object from a specific origin. - """ - - class Config: - extra = Extra.forbid - - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - origin: common.Origin - facets: List[Facet] = Field(...) - - -class AssessmentSubject(OscalBaseModel): - """ - Identifies system elements being assessed, such as components, inventory items, and locations. In the assessment plan, this identifies a planned assessment subject. In the assessment results this is an actual assessment subject, and reflects any changes from the plan. exactly what will be the focus of this assessment. Any subjects not identified in this way are out-of-scope. - """ - - class Config: - extra = Extra.forbid - - type: Union[ - constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - Type3 - ] = Field( - ..., - description= - 'Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement.', - title='Subject Type' - ) - description: Optional[str] = Field( - None, - description='A human-readable description of the collection of subjects being included in this assessment.', - title='Include Subjects Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - include_all: Optional[common.IncludeAll] = Field(None, alias='include-all') - include_subjects: Optional[List[common.SelectSubjectById]] = Field(None, alias='include-subjects') - exclude_subjects: Optional[List[common.SelectSubjectById]] = Field(None, alias='exclude-subjects') - remarks: Optional[str] = None - - -class RiskLog(OscalBaseModel): - """ - A log of all risk-related tasks taken. - """ - - class Config: - extra = Extra.forbid - - entries: List[Entry] = Field(...) - - -class IdentifiedSubject(OscalBaseModel): - """ - Used to detail assessment subjects that were identfied by this task. - """ - - class Config: - extra = Extra.forbid - - subject_placeholder_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='subject-placeholder-uuid', - description= - 'A machine-oriented identifier reference to a unique assessment subject placeholder defined by this task.', - title='Assessment Subject Placeholder Universally Unique Identifier Reference', - ) - subjects: List[AssessmentSubject] = Field(...) - - -class RelatedTask(OscalBaseModel): - """ - Identifies an individual task for which the containing object is a consequence of. - """ - - class Config: - extra = Extra.forbid - - task_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='task-uuid', - description='A machine-oriented identifier reference to a unique task.', - title='Task Universally Unique Identifier Reference' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - responsible_parties: Optional[List[common.ResponsibleParty]] = Field(None, alias='responsible-parties') - subjects: Optional[List[AssessmentSubject]] = Field(None) - identified_subject: Optional[IdentifiedSubject] = Field( - None, - alias='identified-subject', - description='Used to detail assessment subjects that were identfied by this task.', - title='Identified Subject' - ) - remarks: Optional[str] = None - - -class AssociatedActivity(OscalBaseModel): - """ - Identifies an individual activity to be performed as part of a task. - """ - - class Config: - extra = Extra.forbid - - activity_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='activity-uuid', - description='A machine-oriented identifier reference to an activity defined in the list of activities.', - title='Activity Universally Unique Identifier Reference' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - responsible_roles: Optional[List[common.ResponsibleRole]] = Field(None, alias='responsible-roles') - subjects: List[AssessmentSubject] = Field(...) - remarks: Optional[str] = None - - -class Task(OscalBaseModel): - """ - Represents a scheduled event or milestone, which may be associated with a series of assessment actions. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this task elsewhere in this or other OSCAL instances. The locally defined UUID of the task can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Task Universally Unique Identifier', - ) - type: Union[TokenDatatype, TaskValidValues] = Field(..., description='The type of task.', title='Task Type') - title: str = Field(..., description='The title for this task.', title='Task Title') - description: Optional[str] = Field( - None, description='A human-readable description of this task.', title='Task Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - timing: Optional[Timing] = Field( - None, description='The timing under which the task is intended to occur.', title='Event Timing' - ) - dependencies: Optional[List[common.Dependency]] = Field(None) - tasks: Optional[List[Task]] = None - associated_activities: Optional[List[AssociatedActivity]] = Field(None, alias='associated-activities') - subjects: Optional[List[AssessmentSubject]] = Field(None) - responsible_roles: Optional[List[common.ResponsibleRole]] = Field(None, alias='responsible-roles') - remarks: Optional[str] = None - - class AssessmentPlan(OscalBaseModel): """ An assessment plan, such as those provided by a FedRAMP assessor. @@ -383,101 +97,14 @@ class Config: alias='terms-and-conditions', description= 'Used to define various terms and conditions under which an assessment, described by the plan, can be performed. Each child part defines a different type of term or condition.', - title='Assessment Plan Terms and Conditions', + title='Assessment Plan Terms and Conditions' ) reviewed_controls: common.ReviewedControls = Field(..., alias='reviewed-controls') - assessment_subjects: Optional[List[AssessmentSubject]] = Field(None, alias='assessment-subjects') + assessment_subjects: Optional[List[common.AssessmentSubject]] = Field(None, alias='assessment-subjects') assessment_assets: Optional[common.AssessmentAssets] = Field(None, alias='assessment-assets') - tasks: Optional[List[Task]] = Field(None) + tasks: Optional[List[common.Task]] = Field(None) back_matter: Optional[common.BackMatter] = Field(None, alias='back-matter') -class Response(OscalBaseModel): - """ - Describes either recommended or an actual plan for addressing the risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this remediation elsewhere in this or other OSCAL instances. The locally defined UUID of the risk response can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Remediation Universally Unique Identifier', - ) - lifecycle: Union[ - constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - common.Lifecycle - ] = Field( - ..., - description= - 'Identifies whether this is a recommendation, such as from an assessor or tool, or an actual plan accepted by the system owner.', - title='Remediation Intent' - ) - title: str = Field(..., description='The title for this response activity.', title='Response Title') - description: str = Field( - ..., description='A human-readable description of this response plan.', title='Response Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - origins: Optional[List[common.Origin]] = Field(None) - required_assets: Optional[List[common.RequiredAsset]] = Field(None, alias='required-assets') - tasks: Optional[List[Task]] = Field(None) - remarks: Optional[str] = None - - -class Risk(OscalBaseModel): - """ - An identified risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk elsewhere in this or other OSCAL instances. The locally defined UUID of the risk can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Risk Universally Unique Identifier', - ) - title: str = Field(..., description='The title for this risk.', title='Risk Title') - description: str = Field( - ..., - description= - 'A human-readable summary of the identified risk, to include a statement of how the risk impacts the system.', - title='Risk Description' - ) - statement: str = Field( - ..., description='An summary of impact for how the risk affects the system.', title='Risk Statement' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - status: Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - RiskStatus1] - origins: Optional[List[common.Origin]] = Field(None) - threat_ids: Optional[List[common.ThreatId]] = Field(None, alias='threat-ids') - characterizations: Optional[List[Characterization]] = Field(None) - mitigating_factors: Optional[List[common.MitigatingFactor]] = Field(None, alias='mitigating-factors') - deadline: Optional[datetime] = Field( - None, description='The date/time by which the risk must be resolved.', title='Risk Resolution Deadline' - ) - remediations: Optional[List[Response]] = Field(None) - risk_log: Optional[RiskLog] = Field( - None, alias='risk-log', description='A log of all risk-related tasks taken.', title='Risk Log' - ) - related_observations: Optional[List[common.RelatedObservation]] = Field(None, alias='related-observations') - - class Model(OscalBaseModel): assessment_plan: AssessmentPlan = Field(..., alias='assessment-plan') diff --git a/trestle/oscal/assessment_results.py b/trestle/oscal/assessment_results.py index 6683c0321..7a60181d5 100644 --- a/trestle/oscal/assessment_results.py +++ b/trestle/oscal/assessment_results.py @@ -37,63 +37,24 @@ from trestle.oscal.common import AssessmentAssets from trestle.oscal.common import Observation from trestle.oscal.common import RelatedObservation -from trestle.oscal.common import RiskStatus1 from trestle.oscal.common import SystemComponent from trestle.oscal.common import TaskValidValues from trestle.oscal.common import TokenDatatype -class Type3(Enum): - """ - Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement. - """ - - component = 'component' - inventory_item = 'inventory-item' - location = 'location' - party = 'party' - user = 'user' - - -class System(Enum): - """ - Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash. - """ - - http___fedramp_gov = 'http://fedramp.gov' - http___fedramp_gov_ns_oscal = 'http://fedramp.gov/ns/oscal' - http___csrc_nist_gov_ns_oscal = 'http://csrc.nist.gov/ns/oscal' - http___csrc_nist_gov_ns_oscal_unknown = 'http://csrc.nist.gov/ns/oscal/unknown' - http___cve_mitre_org = 'http://cve.mitre.org' - http___www_first_org_cvss_v2_0 = 'http://www.first.org/cvss/v2.0' - http___www_first_org_cvss_v3_0 = 'http://www.first.org/cvss/v3.0' - http___www_first_org_cvss_v3_1 = 'http://www.first.org/cvss/v3.1' - - -class SelectControlById(OscalBaseModel): +class LocalDefinitions1(OscalBaseModel): """ - Used to select a control for inclusion/exclusion based on one or more control identifiers. A set of statement identifiers can be used to target the inclusion/exclusion to only specific control statements providing more granularity over the specific statements that are within the asessment scope. + Used to define data objects that are used in the assessment plan, that do not appear in the referenced SSP. """ class Config: extra = Extra.forbid - control_id: constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ) = Field( - ..., - alias='control-id', - description= - 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', - ) - statement_ids: Optional[List[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - )]] = Field( - None, alias='statement-ids' - ) + components: Optional[List[common.SystemComponent]] = Field(None) + inventory_items: Optional[List[common.InventoryItem]] = Field(None, alias='inventory-items') + users: Optional[List[common.SystemUser]] = Field(None) + assessment_assets: Optional[common.AssessmentAssets] = Field(None, alias='assessment-assets') + tasks: Optional[List[common.Task]] = Field(None) class LocalDefinitions(OscalBaseModel): @@ -125,188 +86,7 @@ class Config: remarks: Optional[str] = None -class Facet(OscalBaseModel): - """ - An individual characteristic that is part of a larger set produced by the same actor. - """ - - class Config: - extra = Extra.forbid - - name: constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ) = Field(..., description='The name of the risk metric within the specified system.', title='Facet Name') - system: Union[AnyUrl, System] = Field( - ..., - description= - 'Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash.', - title='Naming System', - ) - value: constr(regex=r'^\S(.*\S)?$' - ) = Field(..., description='Indicates the value of the facet.', title='Facet Value') - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - remarks: Optional[str] = None - - class Entry1(OscalBaseModel): - """ - Identifies an individual risk response that occurred as part of managing an identified risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk log entry elsewhere in this or other OSCAL instances. The locally defined UUID of the risk log entry can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Risk Log Entry Universally Unique Identifier', - ) - title: Optional[str] = Field(None, description='The title for this risk log entry.', title='Title') - description: Optional[str] = Field( - None, - description='A human-readable description of what was done regarding the risk.', - title='Risk Task Description' - ) - start: datetime = Field(..., description='Identifies the start date and time of the event.', title='Start') - end: Optional[datetime] = Field( - None, - description= - 'Identifies the end date and time of the event. If the event is a point in time, the start and end will be the same date and time.', - title='End' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - logged_by: Optional[List[common.LoggedBy]] = Field(None, alias='logged-by') - status_change: Optional[Union[TokenDatatype, RiskStatus1]] = Field(None, alias='status-change') - related_responses: Optional[List[common.RelatedResponse]] = Field(None, alias='related-responses') - remarks: Optional[str] = None - - -class Characterization(OscalBaseModel): - """ - A collection of descriptive data about the containing object from a specific origin. - """ - - class Config: - extra = Extra.forbid - - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - origin: common.Origin - facets: List[Facet] = Field(...) - - -class Attestation(OscalBaseModel): - """ - A set of textual statements, typically written by the assessor. - """ - - class Config: - extra = Extra.forbid - - responsible_parties: Optional[List[common.ResponsibleParty]] = Field(None, alias='responsible-parties') - parts: List[common.AssessmentPart] = Field(...) - - -class AssessmentSubject(OscalBaseModel): - """ - Identifies system elements being assessed, such as components, inventory items, and locations. In the assessment plan, this identifies a planned assessment subject. In the assessment results this is an actual assessment subject, and reflects any changes from the plan. exactly what will be the focus of this assessment. Any subjects not identified in this way are out-of-scope. - """ - - class Config: - extra = Extra.forbid - - type: Union[ - constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - Type3 - ] = Field( - ..., - description= - 'Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement.', - title='Subject Type' - ) - description: Optional[str] = Field( - None, - description='A human-readable description of the collection of subjects being included in this assessment.', - title='Include Subjects Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - include_all: Optional[common.IncludeAll] = Field(None, alias='include-all') - include_subjects: Optional[List[common.SelectSubjectById]] = Field(None, alias='include-subjects') - exclude_subjects: Optional[List[common.SelectSubjectById]] = Field(None, alias='exclude-subjects') - remarks: Optional[str] = None - - -class RiskLog(OscalBaseModel): - """ - A log of all risk-related tasks taken. - """ - - class Config: - extra = Extra.forbid - - entries: List[Entry1] = Field(...) - - -class IdentifiedSubject(OscalBaseModel): - """ - Used to detail assessment subjects that were identfied by this task. - """ - - class Config: - extra = Extra.forbid - - subject_placeholder_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='subject-placeholder-uuid', - description= - 'A machine-oriented identifier reference to a unique assessment subject placeholder defined by this task.', - title='Assessment Subject Placeholder Universally Unique Identifier Reference', - ) - subjects: List[AssessmentSubject] = Field(...) - - -class RelatedTask(OscalBaseModel): - """ - Identifies an individual task for which the containing object is a consequence of. - """ - - class Config: - extra = Extra.forbid - - task_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='task-uuid', - description='A machine-oriented identifier reference to a unique task.', - title='Task Universally Unique Identifier Reference' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - responsible_parties: Optional[List[common.ResponsibleParty]] = Field(None, alias='responsible-parties') - subjects: Optional[List[AssessmentSubject]] = Field(None) - identified_subject: Optional[IdentifiedSubject] = Field( - None, - alias='identified-subject', - description='Used to detail assessment subjects that were identfied by this task.', - title='Identified Subject' - ) - remarks: Optional[str] = None - - -class Entry(OscalBaseModel): """ Identifies the result of an action and/or task that occurred as part of executing an assessment plan or an assessment event that occurred in producing the assessment results. """ @@ -336,178 +116,31 @@ class Config: props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) logged_by: Optional[List[common.LoggedBy]] = Field(None, alias='logged-by') - related_tasks: Optional[List[RelatedTask]] = Field(None, alias='related-tasks') + related_tasks: Optional[List[common.RelatedTask]] = Field(None, alias='related-tasks') remarks: Optional[str] = None -class AssessmentLog(OscalBaseModel): - """ - A log of all assessment-related actions taken. - """ - - class Config: - extra = Extra.forbid - - entries: List[Entry] = Field(...) - - -class AssociatedActivity(OscalBaseModel): - """ - Identifies an individual activity to be performed as part of a task. - """ - - class Config: - extra = Extra.forbid - - activity_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='activity-uuid', - description='A machine-oriented identifier reference to an activity defined in the list of activities.', - title='Activity Universally Unique Identifier Reference' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - responsible_roles: Optional[List[common.ResponsibleRole]] = Field(None, alias='responsible-roles') - subjects: List[AssessmentSubject] = Field(...) - remarks: Optional[str] = None - - -class Task(OscalBaseModel): - """ - Represents a scheduled event or milestone, which may be associated with a series of assessment actions. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this task elsewhere in this or other OSCAL instances. The locally defined UUID of the task can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Task Universally Unique Identifier', - ) - type: Union[TokenDatatype, TaskValidValues] = Field(..., description='The type of task.', title='Task Type') - title: str = Field(..., description='The title for this task.', title='Task Title') - description: Optional[str] = Field( - None, description='A human-readable description of this task.', title='Task Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - timing: Optional[Timing] = Field( - None, description='The timing under which the task is intended to occur.', title='Event Timing' - ) - dependencies: Optional[List[common.Dependency]] = Field(None) - tasks: Optional[List[Task]] = None - associated_activities: Optional[List[AssociatedActivity]] = Field(None, alias='associated-activities') - subjects: Optional[List[AssessmentSubject]] = Field(None) - responsible_roles: Optional[List[common.ResponsibleRole]] = Field(None, alias='responsible-roles') - remarks: Optional[str] = None - - -class Response(OscalBaseModel): - """ - Describes either recommended or an actual plan for addressing the risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this remediation elsewhere in this or other OSCAL instances. The locally defined UUID of the risk response can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Remediation Universally Unique Identifier', - ) - lifecycle: Union[ - constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - common.Lifecycle - ] = Field( - ..., - description= - 'Identifies whether this is a recommendation, such as from an assessor or tool, or an actual plan accepted by the system owner.', - title='Remediation Intent' - ) - title: str = Field(..., description='The title for this response activity.', title='Response Title') - description: str = Field( - ..., description='A human-readable description of this response plan.', title='Response Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - origins: Optional[List[common.Origin]] = Field(None) - required_assets: Optional[List[common.RequiredAsset]] = Field(None, alias='required-assets') - tasks: Optional[List[Task]] = Field(None) - remarks: Optional[str] = None - - -class Risk(OscalBaseModel): +class Attestation(OscalBaseModel): """ - An identified risk. + A set of textual statements, typically written by the assessor. """ class Config: extra = Extra.forbid - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk elsewhere in this or other OSCAL instances. The locally defined UUID of the risk can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Risk Universally Unique Identifier', - ) - title: str = Field(..., description='The title for this risk.', title='Risk Title') - description: str = Field( - ..., - description= - 'A human-readable summary of the identified risk, to include a statement of how the risk impacts the system.', - title='Risk Description' - ) - statement: str = Field( - ..., description='An summary of impact for how the risk affects the system.', title='Risk Statement' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - status: Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - RiskStatus1] - origins: Optional[List[common.Origin]] = Field(None) - threat_ids: Optional[List[common.ThreatId]] = Field(None, alias='threat-ids') - characterizations: Optional[List[Characterization]] = Field(None) - mitigating_factors: Optional[List[common.MitigatingFactor]] = Field(None, alias='mitigating-factors') - deadline: Optional[datetime] = Field( - None, description='The date/time by which the risk must be resolved.', title='Risk Resolution Deadline' - ) - remediations: Optional[List[Response]] = Field(None) - risk_log: Optional[RiskLog] = Field( - None, alias='risk-log', description='A log of all risk-related tasks taken.', title='Risk Log' - ) - related_observations: Optional[List[common.RelatedObservation]] = Field(None, alias='related-observations') + responsible_parties: Optional[List[common.ResponsibleParty]] = Field(None, alias='responsible-parties') + parts: List[common.AssessmentPart] = Field(...) -class LocalDefinitions1(OscalBaseModel): +class AssessmentLog(OscalBaseModel): """ - Used to define data objects that are used in the assessment plan, that do not appear in the referenced SSP. + A log of all assessment-related actions taken. """ class Config: extra = Extra.forbid - components: Optional[List[common.SystemComponent]] = Field(None) - inventory_items: Optional[List[common.InventoryItem]] = Field(None, alias='inventory-items') - users: Optional[List[common.SystemUser]] = Field(None) - assessment_assets: Optional[common.AssessmentAssets] = Field(None, alias='assessment-assets') - tasks: Optional[List[Task]] = Field(None) + entries: List[Entry1] = Field(...) class Result(OscalBaseModel): @@ -539,7 +172,7 @@ class Config: None, description= 'Date/time stamp identifying the end of the evidence collection reflected in these results. In a continuous motoring scenario, this may contain the same value as start if appropriate.', - title='end field', + title='end field' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -559,7 +192,7 @@ class Config: title='Assessment Log' ) observations: Optional[List[common.Observation]] = Field(None) - risks: Optional[List[Risk]] = Field(None) + risks: Optional[List[common.Risk]] = Field(None) findings: Optional[List[common.Finding]] = Field(None) remarks: Optional[str] = None diff --git a/trestle/oscal/common.py b/trestle/oscal/common.py index d93f15617..dfe63626a 100644 --- a/trestle/oscal/common.py +++ b/trestle/oscal/common.py @@ -69,31 +69,6 @@ class URIDatatype(OscalBaseModel): __root__: AnyUrl = Field(..., description='A universal resource identifier (URI) formatted according to RFC3986.') -class Types(Enum): - """ - Identifies the nature of the observation. More than one may be used to further qualify and enable filtering. - """ - - ssp_statement_issue = 'ssp-statement-issue' - control_objective = 'control-objective' - mitigation = 'mitigation' - finding = 'finding' - historic = 'historic' - - -class Type4(Enum): - """ - Used to indicate the type of object pointed to by the uuid-ref within a subject. - """ - - component = 'component' - inventory_item = 'inventory-item' - location = 'location' - party = 'party' - user = 'user' - resource = 'resource' - - class Type2(Enum): """ A category describing the purpose of the component. @@ -202,6 +177,15 @@ class TaskValidValues(Enum): action = 'action' +class SubjectReferenceValidValues(Enum): + component = 'component' + inventory_item = 'inventory-item' + location = 'location' + party = 'party' + user = 'user' + resource = 'resource' + + class StringDatatype(OscalBaseModel): __root__: constr(regex=r'^\S(.*\S)?$') = Field( ..., @@ -256,6 +240,15 @@ class Config: ) +class SelectSubjectByIdValidValues(Enum): + component = 'component' + inventory_item = 'inventory-item' + location = 'location' + party = 'party' + user = 'user' + resource = 'resource' + + class SelectObjectiveById(OscalBaseModel): """ Used to select a control objective for inclusion/exclusion based on the control objective's identifier. @@ -270,6 +263,32 @@ class Config: ) = Field(..., alias='objective-id', description='Points to an assessment objective.', title='Objective ID') +class SelectControlById(OscalBaseModel): + """ + Used to select a control for inclusion/exclusion based on one or more control identifiers. A set of statement identifiers can be used to target the inclusion/exclusion to only specific control statements providing more granularity over the specific statements that are within the asessment scope. + """ + + class Config: + extra = Extra.forbid + + control_id: constr( + regex= + r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' + ) = Field( + ..., + alias='control-id', + description= + 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', + title='Control Identifier Reference' + ) + statement_ids: Optional[List[constr( + regex= + r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' + )]] = Field( + None, alias='statement-ids' + ) + + class Scheme1(Enum): """ Qualifies the kind of document identifier using a URI. If the scheme is not provided the value of the element will be interpreted as a string of characters. @@ -290,11 +309,7 @@ class RoleId(OscalBaseModel): __root__: TokenDatatype = Field(..., description='Reference to a role by UUID.', title='Role Identifier Reference') -class RiskStatus1(Enum): - """ - Describes the status of the associated risk. - """ - +class RiskStatusValidValues(Enum): open = 'open' investigating = 'investigating' remediating = 'remediating' @@ -304,7 +319,7 @@ class RiskStatus1(Enum): class RiskStatus(OscalBaseModel): - __root__: Union[TokenDatatype, RiskStatus1] = Field( + __root__: Union[TokenDatatype, RiskStatusValidValues] = Field( ..., description='Describes the status of the associated risk.', title='Risk Status' ) @@ -345,7 +360,7 @@ class Config: ..., alias='observation-uuid', description='A machine-oriented identifier reference to an observation defined in the list of observations.', - title='Observation Universally Unique Identifier Reference', + title='Observation Universally Unique Identifier Reference' ) @@ -487,6 +502,14 @@ class Config: date: datetime = Field(..., description='The task must occur on the specified date.', title='On Date Condition') +class ObservationTypeValidValues(Enum): + ssp_statement_issue = 'ssp-statement-issue' + control_objective = 'control-objective' + mitigation = 'mitigation' + finding = 'finding' + historic = 'historic' + + class ObjectiveStatus(OscalBaseModel): """ A determination of if the objective is satisfied or not within a given system. @@ -521,6 +544,17 @@ class NonNegativeIntegerDatatype(OscalBaseModel): """ +class NamingSystemValidValues(Enum): + http___fedramp_gov = 'http://fedramp.gov' + http___fedramp_gov_ns_oscal = 'http://fedramp.gov/ns/oscal' + http___csrc_nist_gov_ns_oscal = 'http://csrc.nist.gov/ns/oscal' + http___csrc_nist_gov_ns_oscal_unknown = 'http://csrc.nist.gov/ns/oscal/unknown' + http___cve_mitre_org = 'http://cve.mitre.org' + http___www_first_org_cvss_v2_0 = 'http://www.first.org/cvss/v2.0' + http___www_first_org_cvss_v3_0 = 'http://www.first.org/cvss/v3.0' + http___www_first_org_cvss_v3_1 = 'http://www.first.org/cvss/v3.1' + + class Name(Enum): """ A textual label that uniquely identifies the part's semantic type. @@ -607,7 +641,7 @@ class Config: alias='resource-fragment', description= 'In case where the href points to a back-matter/resource, this value will indicate the URI fragment to append to any rlink associated with the resource. This value MUST be URI encoded.', - title='Resource Fragment', + title='Resource Fragment' ) text: Optional[str] = Field( None, @@ -750,6 +784,31 @@ class Config: ) +class Facet(OscalBaseModel): + """ + An individual characteristic that is part of a larger set produced by the same actor. + """ + + class Config: + extra = Extra.forbid + + name: constr( + regex= + r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' + ) = Field(..., description='The name of the risk metric within the specified system.', title='Facet Name') + system: Union[URIDatatype, NamingSystemValidValues] = Field( + ..., + description= + 'Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash.', + title='Naming System' + ) + value: constr(regex=r'^\S(.*\S)?$' + ) = Field(..., description='Indicates the value of the facet.', title='Facet Value') + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + remarks: Optional[str] = None + + class ExternalId(OscalBaseModel): """ An identifier for a person or organization using a designated scheme. e.g. an Open Researcher and Contributor ID (ORCID). @@ -782,7 +841,7 @@ class Config: None, description= 'Qualifies the kind of document identifier using a URI. If the scheme is not provided the value of the element will be interpreted as a string of characters.', - title='Document Identification Scheme', + title='Document Identification Scheme' ) identifier: constr(regex=r'^\S(.*\S)?$') @@ -886,7 +945,7 @@ class Config: None, description= 'Name of the file before it was encoded as Base64 to be embedded in a resource. This is the name that will be assigned to the file when the file is decoded.', - title='File Name', + title='File Name' ) media_type: Optional[constr(regex=r'^\S(.*\S)?$')] = Field( None, @@ -926,6 +985,14 @@ class Config: unit: constr(regex=r'^\S(.*\S)?$') = Field(..., description='The unit of time for the period.', title='Time Unit') +class AssessmentSubjectValidValues(Enum): + component = 'component' + inventory_item = 'inventory-item' + location = 'location' + party = 'party' + user = 'user' + + class AssessmentSubjectPlaceholder(OscalBaseModel): """ Used when the assessment subjects will be determined as part of one or more other assessment activities. These assessment subjects will be recorded in the assessment results in the assessment log. @@ -967,7 +1034,7 @@ class Config: None, description= 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this part elsewhere in this or other OSCAL instances. The locally defined UUID of the part can be used to reference the data item locally or globally (e.g., in an ported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Part Identifier', + title='Part Identifier' ) name: Union[constr( regex= @@ -992,7 +1059,7 @@ class Config: alias='class', description= "A textual label that provides a sub-type or characterization of the part's name. This can be used to further distinguish or discriminate between the semantics of multiple parts of the same control with the same name and ns.", - title='Part Class', + title='Part Class' ) title: Optional[str] = Field( None, @@ -1165,17 +1232,13 @@ class Config: alias='subject-uuid', description= "A machine-oriented identifier reference to a component, inventory-item, location, party, user, or resource using it's UUID.", - title='Subject Universally Unique Identifier Reference', + title='Subject Universally Unique Identifier Reference' + ) + type: Union[TokenDatatype, SubjectReferenceValidValues] = Field( + ..., + description='Used to indicate the type of object pointed to by the uuid-ref within a subject.', + title='Subject Universally Unique Identifier Reference Type' ) - type: Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - Type4] = Field( - ..., - description='Used to indicate the type of object pointed to by the uuid-ref within a subject.', - title='Subject Universally Unique Identifier Reference Type' - ) title: Optional[str] = Field( None, description='The title or name for the referenced subject.', title='Subject Reference Title' ) @@ -1234,19 +1297,42 @@ class Config: alias='subject-uuid', description= "A machine-oriented identifier reference to a component, inventory-item, location, party, user, or resource using it's UUID.", - title='Subject Universally Unique Identifier Reference', + title='Subject Universally Unique Identifier Reference' + ) + type: Union[TokenDatatype, SelectSubjectByIdValidValues] = Field( + ..., + description='Used to indicate the type of object pointed to by the uuid-ref within a subject.', + title='Subject Universally Unique Identifier Reference Type' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + remarks: Optional[str] = None + + +class AssessmentSubject(OscalBaseModel): + """ + Identifies system elements being assessed, such as components, inventory items, and locations. In the assessment plan, this identifies a planned assessment subject. In the assessment results this is an actual assessment subject, and reflects any changes from the plan. exactly what will be the focus of this assessment. Any subjects not identified in this way are out-of-scope. + """ + + class Config: + extra = Extra.forbid + + type: Union[TokenDatatype, AssessmentSubjectValidValues] = Field( + ..., + description= + 'Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement.', + title='Subject Type' + ) + description: Optional[str] = Field( + None, + description='A human-readable description of the collection of subjects being included in this assessment.', + title='Include Subjects Description' ) - type: Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - Type4] = Field( - ..., - description='Used to indicate the type of object pointed to by the uuid-ref within a subject.', - title='Subject Universally Unique Identifier Reference Type' - ) props: Optional[List[Property]] = Field(None) links: Optional[List[Link]] = Field(None) + include_all: Optional[IncludeAll] = Field(None, alias='include-all') + include_subjects: Optional[List[SelectSubjectById]] = Field(None, alias='include-subjects') + exclude_subjects: Optional[List[SelectSubjectById]] = Field(None, alias='exclude-subjects') remarks: Optional[str] = None @@ -1419,28 +1505,6 @@ class Config: remarks: Optional[str] = None -class RelatedResponse(OscalBaseModel): - """ - Identifies an individual risk response that this log entry is for. - """ - - class Config: - extra = Extra.forbid - - response_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='response-uuid', - description='A machine-oriented identifier reference to a unique risk response.', - title='Response Universally Unique Identifier Reference' - ) - props: Optional[List[Property]] = Field(None) - links: Optional[List[Link]] = Field(None) - related_tasks: Optional[List[RelatedTask]] = Field(None, alias='related-tasks') - remarks: Optional[str] = None - - class Published(OscalBaseModel): __root__: DateTimeWithTimezoneDatatype = Field( ..., description='The date and time the document was last made available.', title='Publication Timestamp' @@ -1489,7 +1553,7 @@ class Config: ..., description= 'The common name of the protocol, which should be the appropriate "service name" from the IANA Service Name and Transport Protocol Port Number Registry.', - title='Protocol Name', + title='Protocol Name' ) title: Optional[str] = Field( None, @@ -1645,7 +1709,7 @@ class Config: alias='control-id', description= 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', + title='Control Identifier Reference' ) description: Optional[str] = Field( None, description='A human-readable description of this control objective.', title='Objective Description' @@ -1757,65 +1821,6 @@ class Config: links: Optional[List[Link]] = Field(None) -class Origin(OscalBaseModel): - """ - Identifies the source of the finding, such as a tool, interviewed person, or activity. - """ - - class Config: - extra = Extra.forbid - - actors: List[OriginActor] = Field(...) - related_tasks: Optional[List[RelatedTask]] = Field(None, alias='related-tasks') - - -class Observation(OscalBaseModel): - """ - Describes an individual observation. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this observation elsewhere in this or other OSCAL instances. The locally defined UUID of the observation can be used to reference the data item locally or globally (e.g., in an imorted OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Observation Universally Unique Identifier', - ) - title: Optional[str] = Field(None, description='The title for this observation.', title='Observation Title') - description: str = Field( - ..., - description='A human-readable description of this assessment observation.', - title='Observation Description' - ) - props: Optional[List[Property]] = Field(None) - links: Optional[List[Link]] = Field(None) - methods: List[Union[constr(regex=r'^\S(.*\S)?$'), Methods]] = Field(...) - types: Optional[List[Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - Types]]] = Field(None) - origins: Optional[List[Origin]] = Field(None) - subjects: Optional[List[SubjectReference]] = Field(None) - relevant_evidence: Optional[List[RelevantEvidence]] = Field(None, alias='relevant-evidence') - collected: datetime = Field( - ..., - description='Date/time stamp identifying when the finding information was collected.', - title='Collected Field' - ) - expires: Optional[datetime] = Field( - None, - description= - 'Date/time identifying when the finding information is out-of-date and no longer valid. Typically used with continuous assessment scenarios.', - title='Expires Field' - ) - remarks: Optional[str] = None - - class Location(OscalBaseModel): """ A physical point of presence, which may be associated with people, organizations, or other concepts within the current or linked OSCAL document. @@ -1867,7 +1872,7 @@ class Config: alias='component-uuid', description= 'A machine-oriented identifier reference to a component that is implemented as part of an inventory item.', - title='Component Universally Unique Identifier Reference', + title='Component Universally Unique Identifier Reference' ) props: Optional[List[Property]] = Field(None) links: Optional[List[Link]] = Field(None) @@ -1903,6 +1908,67 @@ class Config: remarks: Optional[str] = None +class IdentifiedSubject(OscalBaseModel): + """ + Used to detail assessment subjects that were identfied by this task. + """ + + class Config: + extra = Extra.forbid + + subject_placeholder_uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + alias='subject-placeholder-uuid', + description= + 'A machine-oriented identifier reference to a unique assessment subject placeholder defined by this task.', + title='Assessment Subject Placeholder Universally Unique Identifier Reference' + ) + subjects: List[AssessmentSubject] = Field(...) + + +class RelatedTask(OscalBaseModel): + """ + Identifies an individual task for which the containing object is a consequence of. + """ + + class Config: + extra = Extra.forbid + + task_uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + alias='task-uuid', + description='A machine-oriented identifier reference to a unique task.', + title='Task Universally Unique Identifier Reference' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + responsible_parties: Optional[List[ResponsibleParty]] = Field(None, alias='responsible-parties') + subjects: Optional[List[AssessmentSubject]] = Field(None) + identified_subject: Optional[IdentifiedSubject] = Field( + None, + alias='identified-subject', + description='Used to detail assessment subjects that were identfied by this task.', + title='Identified Subject' + ) + remarks: Optional[str] = None + + +class Origin(OscalBaseModel): + """ + Identifies the source of the finding, such as a tool, interviewed person, or activity. + """ + + class Config: + extra = Extra.forbid + + actors: List[OriginActor] = Field(...) + related_tasks: Optional[List[RelatedTask]] = Field(None, alias='related-tasks') + + class Hash(OscalBaseModel): """ A representation of a cryptographic digest generated over a resource using a specified hash algorithm. @@ -2012,13 +2078,124 @@ class Config: alias='implementation-statement-uuid', description= 'A machine-oriented identifier reference to the implementation statement in the SSP to which this finding is related.', - title='Implementation Statement UUID', + title='Implementation Statement UUID' ) related_observations: Optional[List[RelatedObservation]] = Field(None, alias='related-observations') related_risks: Optional[List[RelatedRisk]] = Field(None, alias='related-risks') remarks: Optional[str] = None +class Characterization(OscalBaseModel): + """ + A collection of descriptive data about the containing object from a specific origin. + """ + + class Config: + extra = Extra.forbid + + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + origin: Origin + facets: List[Facet] = Field(...) + + +class AssociatedActivity(OscalBaseModel): + """ + Identifies an individual activity to be performed as part of a task. + """ + + class Config: + extra = Extra.forbid + + activity_uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + alias='activity-uuid', + description='A machine-oriented identifier reference to an activity defined in the list of activities.', + title='Activity Universally Unique Identifier Reference' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + responsible_roles: Optional[List[ResponsibleRole]] = Field(None, alias='responsible-roles') + subjects: List[AssessmentSubject] = Field(...) + remarks: Optional[str] = None + + +class Task(OscalBaseModel): + """ + Represents a scheduled event or milestone, which may be associated with a series of assessment actions. + """ + + class Config: + extra = Extra.forbid + + uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + description= + 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this task elsewhere in this or other OSCAL instances. The locally defined UUID of the task can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', + title='Task Universally Unique Identifier', + ) + type: Union[TokenDatatype, TaskValidValues] = Field(..., description='The type of task.', title='Task Type') + title: str = Field(..., description='The title for this task.', title='Task Title') + description: Optional[str] = Field( + None, description='A human-readable description of this task.', title='Task Description' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + timing: Optional[Timing] = Field( + None, description='The timing under which the task is intended to occur.', title='Event Timing' + ) + dependencies: Optional[List[Dependency]] = Field(None) + tasks: Optional[List[Task]] = None + associated_activities: Optional[List[AssociatedActivity]] = Field(None, alias='associated-activities') + subjects: Optional[List[AssessmentSubject]] = Field(None) + responsible_roles: Optional[List[ResponsibleRole]] = Field(None, alias='responsible-roles') + remarks: Optional[str] = None + + +class Response(OscalBaseModel): + """ + Describes either recommended or an actual plan for addressing the risk. + """ + + class Config: + extra = Extra.forbid + + uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + description= + 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this remediation elsewhere in this or other OSCAL instances. The locally defined UUID of the risk response can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', + title='Remediation Universally Unique Identifier', + ) + lifecycle: Union[ + constr( + regex= + r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' + ), + Lifecycle + ] = Field( + ..., + description= + 'Identifies whether this is a recommendation, such as from an assessor or tool, or an actual plan accepted by the system owner.', + title='Remediation Intent' + ) + title: str = Field(..., description='The title for this response activity.', title='Response Title') + description: str = Field( + ..., description='A human-readable description of this response plan.', title='Response Description' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + origins: Optional[List[Origin]] = Field(None) + required_assets: Optional[List[RequiredAsset]] = Field(None, alias='required-assets') + tasks: Optional[List[Task]] = Field(None) + remarks: Optional[str] = None + + class Action(OscalBaseModel): """ An action applied by a role within a given party to the content. @@ -2033,7 +2210,7 @@ class Config: ..., description= 'A unique identifier that can be used to reference this defined action elsewhere in an OSCAL document. A UUID should be consistently used for a given location across revisions of the document.', - title='Action Universally Unique Identifier', + title='Action Universally Unique Identifier' ) date: Optional[datetime] = Field( None, description='The date and time when the action occurred.', title='Action Occurrence Date' @@ -2095,7 +2272,7 @@ class Config: alias='component-uuid', description= 'A machine-oriented identifier reference to a component that is implemented as part of an inventory item.', - title='Component Universally Unique Identifier Reference', + title='Component Universally Unique Identifier Reference' ) props: Optional[List[Property]] = Field(None) links: Optional[List[Link]] = Field(None) @@ -2195,3 +2372,163 @@ class Config: related_controls: Optional[ReviewedControls] = Field(None, alias='related-controls') responsible_roles: Optional[List[ResponsibleRole]] = Field(None, alias='responsible-roles') remarks: Optional[str] = None + + +class Observation(OscalBaseModel): + """ + Describes an individual observation. + """ + + class Config: + extra = Extra.forbid + + uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + description= + 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this observation elsewhere in this or other OSCAL instances. The locally defined UUID of the observation can be used to reference the data item locally or globally (e.g., in an imorted OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', + title='Observation Universally Unique Identifier', + ) + title: Optional[str] = Field(None, description='The title for this observation.', title='Observation Title') + description: str = Field( + ..., + description='A human-readable description of this assessment observation.', + title='Observation Description' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + methods: List[Union[constr(regex=r'^\S(.*\S)?$'), Methods]] = Field(...) + types: Optional[List[Union[constr( + regex= + r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' + ), + ObservationTypeValidValues]]] = Field(None) + origins: Optional[List[Origin]] = Field(None) + subjects: Optional[List[SubjectReference]] = Field(None) + relevant_evidence: Optional[List[RelevantEvidence]] = Field(None, alias='relevant-evidence') + collected: datetime = Field( + ..., + description='Date/time stamp identifying when the finding information was collected.', + title='Collected Field' + ) + expires: Optional[datetime] = Field( + None, + description= + 'Date/time identifying when the finding information is out-of-date and no longer valid. Typically used with continuous assessment scenarios.', + title='Expires Field' + ) + remarks: Optional[str] = None + + +class RelatedResponse(OscalBaseModel): + """ + Identifies an individual risk response that this log entry is for. + """ + + class Config: + extra = Extra.forbid + + response_uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + alias='response-uuid', + description='A machine-oriented identifier reference to a unique risk response.', + title='Response Universally Unique Identifier Reference' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + related_tasks: Optional[List[RelatedTask]] = Field(None, alias='related-tasks') + remarks: Optional[str] = None + + +class Entry(OscalBaseModel): + """ + Identifies an individual risk response that occurred as part of managing an identified risk. + """ + + class Config: + extra = Extra.forbid + + uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + description= + 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk log entry elsewhere in this or other OSCAL instances. The locally defined UUID of the risk log entry can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', + title='Risk Log Entry Universally Unique Identifier', + ) + title: Optional[str] = Field(None, description='The title for this risk log entry.', title='Title') + description: Optional[str] = Field( + None, + description='A human-readable description of what was done regarding the risk.', + title='Risk Task Description' + ) + start: datetime = Field(..., description='Identifies the start date and time of the event.', title='Start') + end: Optional[datetime] = Field( + None, + description= + 'Identifies the end date and time of the event. If the event is a point in time, the start and end will be the same date and time.', + title='End' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + logged_by: Optional[List[LoggedBy]] = Field(None, alias='logged-by') + status_change: Optional[RiskStatus] = Field(None, alias='status-change') + related_responses: Optional[List[RelatedResponse]] = Field(None, alias='related-responses') + remarks: Optional[str] = None + + +class RiskLog(OscalBaseModel): + """ + A log of all risk-related tasks taken. + """ + + class Config: + extra = Extra.forbid + + entries: List[Entry] = Field(...) + + +class Risk(OscalBaseModel): + """ + An identified risk. + """ + + class Config: + extra = Extra.forbid + + uuid: constr( + regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' + ) = Field( + ..., + description= + 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk elsewhere in this or other OSCAL instances. The locally defined UUID of the risk can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', + title='Risk Universally Unique Identifier', + ) + title: str = Field(..., description='The title for this risk.', title='Risk Title') + description: str = Field( + ..., + description= + 'A human-readable summary of the identified risk, to include a statement of how the risk impacts the system.', + title='Risk Description' + ) + statement: str = Field( + ..., description='An summary of impact for how the risk affects the system.', title='Risk Statement' + ) + props: Optional[List[Property]] = Field(None) + links: Optional[List[Link]] = Field(None) + status: RiskStatus + origins: Optional[List[Origin]] = Field(None) + threat_ids: Optional[List[ThreatId]] = Field(None, alias='threat-ids') + characterizations: Optional[List[Characterization]] = Field(None) + mitigating_factors: Optional[List[MitigatingFactor]] = Field(None, alias='mitigating-factors') + deadline: Optional[datetime] = Field( + None, description='The date/time by which the risk must be resolved.', title='Risk Resolution Deadline' + ) + remediations: Optional[List[Response]] = Field(None) + risk_log: Optional[RiskLog] = Field( + None, alias='risk-log', description='A log of all risk-related tasks taken.', title='Risk Log' + ) + related_observations: Optional[List[RelatedObservation]] = Field(None, alias='related-observations') diff --git a/trestle/oscal/component.py b/trestle/oscal/component.py index 01381994a..fa829bbf2 100644 --- a/trestle/oscal/component.py +++ b/trestle/oscal/component.py @@ -78,7 +78,7 @@ class Config: ..., description= 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this control statement elsewhere in this or other OSCAL instances. The UUID of the control statement in the source OSCAL instance is sufficient to reference the data item locally or globally (e.g., in an imported OSCAL instance).', - title='Control Statement Reference Universally Unique Identifier', + title='Control Statement Reference Universally Unique Identifier' ) description: str = Field( ..., @@ -175,13 +175,13 @@ class Config: alias='control-id', description= 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', + title='Control Identifier Reference' ) description: str = Field( ..., description= 'A suggestion from the supplier (e.g., component vendor or author) for how the specified control may be implemented if the containing component or capability is instantiated in a system security plan.', - title='Control Implementation Description', + title='Control Implementation Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) diff --git a/trestle/oscal/poam.py b/trestle/oscal/poam.py index 93bdff511..89f6ea189 100644 --- a/trestle/oscal/poam.py +++ b/trestle/oscal/poam.py @@ -35,94 +35,11 @@ from trestle.oscal import OSCAL_VERSION_REGEX, OSCAL_VERSION import trestle.oscal.common as common from trestle.oscal.common import RelatedObservation -from trestle.oscal.common import RiskStatus1 from trestle.oscal.common import TaskValidValues from trestle.oscal.common import TokenDatatype from trestle.oscal.common import RelatedObservation as RelatedObservation1 -class Type3(Enum): - """ - Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement. - """ - - component = 'component' - inventory_item = 'inventory-item' - location = 'location' - party = 'party' - user = 'user' - - -class System(Enum): - """ - Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash. - """ - - http___fedramp_gov = 'http://fedramp.gov' - http___fedramp_gov_ns_oscal = 'http://fedramp.gov/ns/oscal' - http___csrc_nist_gov_ns_oscal = 'http://csrc.nist.gov/ns/oscal' - http___csrc_nist_gov_ns_oscal_unknown = 'http://csrc.nist.gov/ns/oscal/unknown' - http___cve_mitre_org = 'http://cve.mitre.org' - http___www_first_org_cvss_v2_0 = 'http://www.first.org/cvss/v2.0' - http___www_first_org_cvss_v3_0 = 'http://www.first.org/cvss/v3.0' - http___www_first_org_cvss_v3_1 = 'http://www.first.org/cvss/v3.1' - - -class SelectControlById(OscalBaseModel): - """ - Used to select a control for inclusion/exclusion based on one or more control identifiers. A set of statement identifiers can be used to target the inclusion/exclusion to only specific control statements providing more granularity over the specific statements that are within the asessment scope. - """ - - class Config: - extra = Extra.forbid - - control_id: constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ) = Field( - ..., - alias='control-id', - description= - 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', - ) - statement_ids: Optional[List[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - )]] = Field( - None, alias='statement-ids' - ) - - -class RelatedFinding(OscalBaseModel): - """ - Relates the finding to referenced finding(s). - """ - - class Config: - extra = Extra.forbid - - finding_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='finding-uuid', - description='A machine-oriented identifier reference to a finding defined in the list of findings.', - title='Finding Universally Unique Identifier Reference' - ) - - -class Origination(OscalBaseModel): - """ - Identifies the source of the finding, such as a tool or person. - """ - - class Config: - extra = Extra.forbid - - actors: List[common.OriginActor] = Field(...) - - class LocalDefinitions(OscalBaseModel): """ Allows components, and inventory-items to be defined within the POA&M for circumstances where no OSCAL-based SSP exists, or is not delivered with the POA&M. @@ -137,274 +54,33 @@ class Config: remarks: Optional[str] = None -class Facet(OscalBaseModel): - """ - An individual characteristic that is part of a larger set produced by the same actor. - """ - - class Config: - extra = Extra.forbid - - name: constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ) = Field(..., description='The name of the risk metric within the specified system.', title='Facet Name') - system: Union[AnyUrl, System] = Field( - ..., - description= - 'Specifies the naming system under which this risk metric is organized, which allows for the same names to be used in different systems controlled by different parties. This avoids the potential of a name clash.', - title='Naming System', - ) - value: constr(regex=r'^\S(.*\S)?$' - ) = Field(..., description='Indicates the value of the facet.', title='Facet Value') - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - remarks: Optional[str] = None - - -class Entry(OscalBaseModel): - """ - Identifies an individual risk response that occurred as part of managing an identified risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk log entry elsewhere in this or other OSCAL instances. The locally defined UUID of the risk log entry can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Risk Log Entry Universally Unique Identifier', - ) - title: Optional[str] = Field(None, description='The title for this risk log entry.', title='Title') - description: Optional[str] = Field( - None, - description='A human-readable description of what was done regarding the risk.', - title='Risk Task Description' - ) - start: datetime = Field(..., description='Identifies the start date and time of the event.', title='Start') - end: Optional[datetime] = Field( - None, - description= - 'Identifies the end date and time of the event. If the event is a point in time, the start and end will be the same date and time.', - title='End' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - logged_by: Optional[List[common.LoggedBy]] = Field(None, alias='logged-by') - status_change: Optional[Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - RiskStatus1]] = Field( - None, alias='status-change' - ) - related_responses: Optional[List[common.RelatedResponse]] = Field(None, alias='related-responses') - remarks: Optional[str] = None - - -class Characterization(OscalBaseModel): - """ - A collection of descriptive data about the containing object from a specific origin. - """ - - class Config: - extra = Extra.forbid - - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - origin: common.Origin - facets: List[Facet] = Field(...) - - -class AssessmentSubject(OscalBaseModel): - """ - Identifies system elements being assessed, such as components, inventory items, and locations. In the assessment plan, this identifies a planned assessment subject. In the assessment results this is an actual assessment subject, and reflects any changes from the plan. exactly what will be the focus of this assessment. Any subjects not identified in this way are out-of-scope. - """ - - class Config: - extra = Extra.forbid - - type: Union[ - constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - Type3 - ] = Field( - ..., - description= - 'Indicates the type of assessment subject, such as a component, inventory, item, location, or party represented by this selection statement.', - title='Subject Type' - ) - description: Optional[str] = Field( - None, - description='A human-readable description of the collection of subjects being included in this assessment.', - title='Include Subjects Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - include_all: Optional[common.IncludeAll] = Field(None, alias='include-all') - include_subjects: Optional[List[common.SelectSubjectById]] = Field(None, alias='include-subjects') - exclude_subjects: Optional[List[common.SelectSubjectById]] = Field(None, alias='exclude-subjects') - remarks: Optional[str] = None - - -class AssociatedActivity(OscalBaseModel): - """ - Identifies an individual activity to be performed as part of a task. - """ - - class Config: - extra = Extra.forbid - - activity_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='activity-uuid', - description='A machine-oriented identifier reference to an activity defined in the list of activities.', - title='Activity Universally Unique Identifier Reference' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - responsible_roles: Optional[List[common.ResponsibleRole]] = Field(None, alias='responsible-roles') - subjects: List[AssessmentSubject] = Field(...) - remarks: Optional[str] = None - - -class Task(OscalBaseModel): - """ - Represents a scheduled event or milestone, which may be associated with a series of assessment actions. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this task elsewhere in this or other OSCAL instances. The locally defined UUID of the task can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Task Universally Unique Identifier', - ) - type: Union[TokenDatatype, TaskValidValues] = Field(..., description='The type of task.', title='Task Type') - title: str = Field(..., description='The title for this task.', title='Task Title') - description: Optional[str] = Field( - None, description='A human-readable description of this task.', title='Task Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - timing: Optional[Timing] = Field( - None, description='The timing under which the task is intended to occur.', title='Event Timing' - ) - dependencies: Optional[List[common.Dependency]] = Field(None) - tasks: Optional[List[Task]] = None - associated_activities: Optional[List[AssociatedActivity]] = Field(None, alias='associated-activities') - subjects: Optional[List[AssessmentSubject]] = Field(None) - responsible_roles: Optional[List[common.ResponsibleRole]] = Field(None, alias='responsible-roles') - remarks: Optional[str] = None - - -class Response(OscalBaseModel): - """ - Describes either recommended or an actual plan for addressing the risk. - """ - - class Config: - extra = Extra.forbid - - uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this remediation elsewhere in this or other OSCAL instances. The locally defined UUID of the risk response can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Remediation Universally Unique Identifier', - ) - lifecycle: Union[ - constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - common.Lifecycle - ] = Field( - ..., - description= - 'Identifies whether this is a recommendation, such as from an assessor or tool, or an actual plan accepted by the system owner.', - title='Remediation Intent' - ) - title: str = Field(..., description='The title for this response activity.', title='Response Title') - description: str = Field( - ..., description='A human-readable description of this response plan.', title='Response Description' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - origins: Optional[List[common.Origin]] = Field(None) - required_assets: Optional[List[common.RequiredAsset]] = Field(None, alias='required-assets') - tasks: Optional[List[Task]] = Field(None) - remarks: Optional[str] = None - - -class RiskLog(OscalBaseModel): +class Origination(OscalBaseModel): """ - A log of all risk-related tasks taken. + Identifies the source of the finding, such as a tool or person. """ class Config: extra = Extra.forbid - entries: List[Entry] = Field(...) + actors: List[common.OriginActor] = Field(...) -class Risk(OscalBaseModel): +class RelatedFinding(OscalBaseModel): """ - An identified risk. + Relates the finding to referenced finding(s). """ class Config: extra = Extra.forbid - uuid: constr( + finding_uuid: constr( regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' ) = Field( ..., - description= - 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this risk elsewhere in this or other OSCAL instances. The locally defined UUID of the risk can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Risk Universally Unique Identifier', - ) - title: str = Field(..., description='The title for this risk.', title='Risk Title') - description: str = Field( - ..., - description= - 'A human-readable summary of the identified risk, to include a statement of how the risk impacts the system.', - title='Risk Description' - ) - statement: str = Field( - ..., description='An summary of impact for how the risk affects the system.', title='Risk Statement' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - status: Union[constr( - regex= - r'^[_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-\.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$' - ), - RiskStatus1] - origins: Optional[List[common.Origin]] = Field(None) - threat_ids: Optional[List[common.ThreatId]] = Field(None, alias='threat-ids') - characterizations: Optional[List[Characterization]] = Field(None) - mitigating_factors: Optional[List[common.MitigatingFactor]] = Field(None, alias='mitigating-factors') - deadline: Optional[datetime] = Field( - None, description='The date/time by which the risk must be resolved.', title='Risk Resolution Deadline' - ) - remediations: Optional[List[Response]] = Field(None) - risk_log: Optional[RiskLog] = Field( - None, alias='risk-log', description='A log of all risk-related tasks taken.', title='Risk Log' + alias='finding-uuid', + description='A machine-oriented identifier reference to a finding defined in the list of findings.', + title='Finding Universally Unique Identifier Reference' ) - related_observations: Optional[List[common.RelatedObservation]] = Field(None, alias='related-observations') class PoamItem(OscalBaseModel): @@ -421,7 +97,7 @@ class Config: None, description= 'A machine-oriented, globally unique identifier with instance scope that can be used to reference this POA&M item entry in this OSCAL instance. This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='POA&M Item Universally Unique Identifier', + title='POA&M Item Universally Unique Identifier' ) title: str = Field(..., description='The title or name for this POA&M item .', title='POA&M Item Title') description: str = Field( @@ -450,67 +126,18 @@ class Config: ..., description= 'A machine-oriented, globally unique identifier with instancescope that can be used to reference this POA&M instance in this OSCAL instance. This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='POA&M Universally Unique Identifier', + title='POA&M Universally Unique Identifier' ) metadata: common.Metadata import_ssp: Optional[common.ImportSsp] = Field(None, alias='import-ssp') system_id: Optional[common.SystemId] = Field(None, alias='system-id') local_definitions: Optional[LocalDefinitions] = Field(None, alias='local-definitions') observations: Optional[List[common.Observation]] = Field(None) - risks: Optional[List[Risk]] = Field(None) + risks: Optional[List[common.Risk]] = Field(None) findings: Optional[List[common.Finding]] = Field(None) poam_items: List[PoamItem] = Field(..., alias='poam-items') back_matter: Optional[common.BackMatter] = Field(None, alias='back-matter') -class IdentifiedSubject(OscalBaseModel): - """ - Used to detail assessment subjects that were identfied by this task. - """ - - class Config: - extra = Extra.forbid - - subject_placeholder_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='subject-placeholder-uuid', - description= - 'A machine-oriented identifier reference to a unique assessment subject placeholder defined by this task.', - title='Assessment Subject Placeholder Universally Unique Identifier Reference', - ) - subjects: List[AssessmentSubject] = Field(...) - - -class RelatedTask(OscalBaseModel): - """ - Identifies an individual task for which the containing object is a consequence of. - """ - - class Config: - extra = Extra.forbid - - task_uuid: constr( - regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' - ) = Field( - ..., - alias='task-uuid', - description='A machine-oriented identifier reference to a unique task.', - title='Task Universally Unique Identifier Reference' - ) - props: Optional[List[common.Property]] = Field(None) - links: Optional[List[common.Link]] = Field(None) - responsible_parties: Optional[List[common.ResponsibleParty]] = Field(None, alias='responsible-parties') - subjects: Optional[List[AssessmentSubject]] = Field(None) - identified_subject: Optional[IdentifiedSubject] = Field( - None, - alias='identified-subject', - description='Used to detail assessment subjects that were identfied by this task.', - title='Identified Subject' - ) - remarks: Optional[str] = None - - class Model(OscalBaseModel): plan_of_action_and_milestones: PlanOfActionAndMilestones = Field(..., alias='plan-of-action-and-milestones') diff --git a/trestle/oscal/profile.py b/trestle/oscal/profile.py index f36126eb7..2f9fa67da 100644 --- a/trestle/oscal/profile.py +++ b/trestle/oscal/profile.py @@ -224,7 +224,7 @@ class Config: alias='control-id', description= 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', + title='Control Identifier Reference' ) removes: Optional[List[Remove]] = Field(None) adds: Optional[List[Add]] = Field(None) @@ -242,7 +242,7 @@ class Config: alters: Optional[List[Alter]] = Field(None) -class SelectControlById(OscalBaseModel): +class SelectControl(OscalBaseModel): """ Select a control or controls from an imported control set. """ @@ -277,8 +277,8 @@ class Config: title='Catalog or Profile Reference' ) include_all: Optional[common.IncludeAll] = Field(None, alias='include-all') - include_controls: Optional[List[SelectControlById]] = Field(None, alias='include-controls') - exclude_controls: Optional[List[SelectControlById]] = Field(None, alias='exclude-controls') + include_controls: Optional[List[SelectControl]] = Field(None, alias='include-controls') + exclude_controls: Optional[List[SelectControl]] = Field(None, alias='exclude-controls') class InsertControls(OscalBaseModel): @@ -296,8 +296,8 @@ class Config: None, description='A designation of how a selection of controls in a profile is to be ordered.', title='Order' ) include_all: Optional[common.IncludeAll] = Field(None, alias='include-all') - include_controls: Optional[List[SelectControlById]] = Field(None, alias='include-controls') - exclude_controls: Optional[List[SelectControlById]] = Field(None, alias='exclude-controls') + include_controls: Optional[List[SelectControl]] = Field(None, alias='include-controls') + exclude_controls: Optional[List[SelectControl]] = Field(None, alias='exclude-controls') class Group(OscalBaseModel): diff --git a/trestle/oscal/ssp.py b/trestle/oscal/ssp.py index 4a99d6077..26253e0ce 100644 --- a/trestle/oscal/ssp.py +++ b/trestle/oscal/ssp.py @@ -109,21 +109,21 @@ class Config: alias='security-objective-confidentiality', description= 'A target-level of confidentiality for the system, based on the sensitivity of information within the system.', - title='Security Objective: Confidentiality', + title='Security Objective: Confidentiality' ) security_objective_integrity: constr(regex=r'^\S(.*\S)?$') = Field( ..., alias='security-objective-integrity', description= 'A target-level of integrity for the system, based on the sensitivity of information within the system.', - title='Security Objective: Integrity', + title='Security Objective: Integrity' ) security_objective_availability: constr(regex=r'^\S(.*\S)?$') = Field( ..., alias='security-objective-availability', description= 'A target-level of availability for the system, based on the sensitivity of information within the system.', - title='Security Objective: Availability', + title='Security Objective: Availability' ) @@ -150,13 +150,13 @@ class Config: alias='responsibility-uuid', description= 'A machine-oriented identifier reference to a control implementation that satisfies a responsibility imposed by a leveraged system.', - title='Responsibility UUID', + title='Responsibility UUID' ) description: str = Field( ..., description= 'An implementation statement that describes the aspects of a control or control statement implementation that a leveraging system is implementing based on a requirement from a leveraged system.', - title='Satisfied Control Implementation Responsibility Description', + title='Satisfied Control Implementation Responsibility Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -187,13 +187,13 @@ class Config: alias='provided-uuid', description= 'A machine-oriented identifier reference to an inherited control implementation that a leveraging system is inheriting from a leveraged system.', - title='Provided UUID', + title='Provided UUID' ) description: str = Field( ..., description= 'An implementation statement that describes the aspects of the control or control statement implementation that a leveraging system must implement to satisfy the control provided by a leveraged system.', - title='Control Implementation Responsibility Description', + title='Control Implementation Responsibility Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -221,7 +221,7 @@ class Config: ..., description= 'An implementation statement that describes the aspects of the control or control statement implementation that can be provided to another system leveraging this system.', - title='Provided Control Implementation Description', + title='Provided Control Implementation Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -252,13 +252,13 @@ class Config: alias='provided-uuid', description= 'A machine-oriented identifier reference to an inherited control implementation that a leveraging system is inheriting from a leveraged system.', - title='Provided UUID', + title='Provided UUID' ) description: str = Field( ..., description= 'An implementation statement that describes the aspects of a control or control statement implementation that a leveraging system is inheriting from a leveraged system.', - title='Inherited Control Implementation Description', + title='Inherited Control Implementation Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -293,7 +293,7 @@ class Config: None, description= 'An implementation statement that describes the aspects of the control or control statement implementation that can be available to another system leveraging this system.', - title='Control Implementation Export Description', + title='Control Implementation Export Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -316,7 +316,7 @@ class Config: ..., description= 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this diagram elsewhere in this or other OSCAL instances. The locally defined UUID of the diagram can be used to reference the data item locally or globally (e.g., in an imported OSCAL instance). This UUID should be assigned per-subject, which means it should be consistently used to identify the same subject across revisions of the document.', - title='Diagram ID', + title='Diagram ID' ) description: Optional[str] = Field(None, description='A summary of the diagram.', title='Diagram Description') props: Optional[List[common.Property]] = Field(None) @@ -383,7 +383,7 @@ class Config: ..., alias='component-uuid', description='A machine-oriented identifier reference to the component that is implemeting a given control.', - title='Component Universally Unique Identifier Reference', + title='Component Universally Unique Identifier Reference' ) uuid: constr( regex=r'^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$' @@ -397,7 +397,7 @@ class Config: ..., description= 'An implementation statement that describes how a control or a control statement is implemented within the referenced system component.', - title='Control Implementation Description', + title='Control Implementation Description' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -464,7 +464,7 @@ class Config: ..., description= 'A machine-oriented, globally unique identifier with cross-instance scope that can be used to reference this control statement elsewhere in this or other OSCAL instances. The UUID of the control statement in the source OSCAL instance is sufficient to reference the data item locally or globally (e.g., in an imported OSCAL instance).', - title='Control Statement Reference Universally Unique Identifier', + title='Control Statement Reference Universally Unique Identifier' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) @@ -497,7 +497,7 @@ class Config: alias='control-id', description= 'A reference to a control with a corresponding id value. When referencing an externally defined control, the Control Identifier Reference must be used in the context of the external / imported OSCAL instance (e.g., uri-reference).', - title='Control Identifier Reference', + title='Control Identifier Reference' ) props: Optional[List[common.Property]] = Field(None) links: Optional[List[common.Link]] = Field(None) diff --git a/trestle/tasks/xlsx_to_oscal_profile.py b/trestle/tasks/xlsx_to_oscal_profile.py index 188b0016d..faaa2ce74 100644 --- a/trestle/tasks/xlsx_to_oscal_profile.py +++ b/trestle/tasks/xlsx_to_oscal_profile.py @@ -28,7 +28,7 @@ from trestle.oscal.profile import Import from trestle.oscal.profile import Modify from trestle.oscal.profile import Profile -from trestle.oscal.profile import SelectControlById +from trestle.oscal.profile import SelectControl as SelectControlById from trestle.oscal.profile import SetParameter from trestle.tasks.base_task import TaskBase from trestle.tasks.base_task import TaskOutcome