diff --git a/research/OSCAL/Catalog/SP800-218/nestTest.json b/research/OSCAL/Catalog/SP800-218/nestTest.json new file mode 100644 index 0000000..410c57d --- /dev/null +++ b/research/OSCAL/Catalog/SP800-218/nestTest.json @@ -0,0 +1,157 @@ +{ + "uuid": "c152b49c-39b4-4765-a961-75051dcf2293", + "metadata": { + "title": "Nested Group and Control Test", + "last-modified": "2023-06-26T02:54:38Z", + "version": "1.0.0", + "oscal-version": "1.0.4", + "published": "2023-06-26T02:54:38Z" + }, + "groups": [ + { + "id": "4e(i)", + "title": "The software was developed and built in secure environments", + "groups": [ + { + "id": "4e(iv)", + "title": "The software producer employed automated tools or comparable processes that check for security vulnerabilities", + "groups": [ + { + "id": "deep", + "title": "Third-level group", + "controls": [ + { + "id": "4e(iv)(b)", + "title": "The software producer has a policy or process to address discovered security vulnerabilities prior to product release", + "controls": [ + { + "id": "4e(iv)(a)", + "title": "The software producer ensured these processes operate on an ongoing basis and, at a minimum, prior to product, version, or update releases" + } + ] + }, + { + "id": "4e(iv)(c)", + "title": "The software producer operates a vulnerability disclosure program and accepts, reviews, and addresses disclosed software vulnerabilities in a timely fashion" + } + ] + } + ], + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.4.1, PO.4.2, PS.1.1, PW.2.1, PW.4.4, PW.5.1, PW.6.1, PW.6.2, PW.7.1, PW.7.2, PW.8.2, PW.9.1, PW.9.2,RV.1.1, RV.1.2, RV.1.3, RV.2.1, RV.2.2, RV.3.3", + "class": "References" + } + ] + }, + { + "id": "4e(vi)", + "title": "Provenance data maintenance", + "controls": [ + { + "id": "4e(vi)", + "title": "The software producer maintains provenance data for internal and third-party code incorporated into the software" + } + ], + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.1.3, PO.3.2, PO.5.1, PO.5.2, PS.3.1, PS.3.2, PW.4.1, PW.4.4, RV.1.1, RV.1.2", + "class": "References" + } + ] + } + ], + "controls": [ + { + "id": "4e(i)(A)", + "title": "Separate and protect each environment involved in developing and building software", + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.5.1", + "class": "References" + } + ] + }, + { + "id": "4e(i)(B)", + "title": "Regularly logging, monitoring, and auditing trust relationships used for authorization and access to any software development and build environments, andamong components within each environment", + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.5.1", + "class": "References" + } + ] + }, + { + "id": "4e(i)(C)", + "title": "Enforcing multi-factor authentication and conditional access across the environments relevant to developing and building software in a manner that minimizes security risk", + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.5.1, PO.5.2", + "class": "References" + } + ] + }, + { + "id": "4e(i)(D)", + "title": "Taking consistent and reasonable steps to document, as well as minimize use or inclusion of software products that create undue risk, within the environments used to develop and build software", + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.5.1", + "class": "References" + } + ] + }, + { + "id": "4e(i)(E)", + "title": "Encrypting sensitive data, such as credentials, to the extent practicable and based on risk", + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.5.2", + "class": "References" + } + ] + }, + { + "id": "4e(i)(F)", + "title": "Implementing defensive cyber security practices, including continuous monitoring of operations and alerts and, as necessary, responding to suspected and confirmed cyber incidents", + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO.3.2, PO.3.3, PO.5.1, PO.5.2", + "class": "References" + } + ] + } + ] + }, + { + "id": "4e(iii)", + "title": "The software producer has made a good-faith effort to maintain trusted source code supply chains by:", + "controls": [ + { + "id": "4e(iii)(a)", + "title": "Employing automated tools or comparable processes" + }, + { + "id": "4e(iii)(b)", + "title": "Establishing a process that includes reasonable steps to address the security of third-party components and manage related vulnerabilities" + } + ], + "props": [ + { + "name": "NIST SSDF Reference", + "value": "PO 1.1, PO.3.1, PO.3.2, PO.5.1, PO.5.2, PS.1.1, PS.2.1, PS.3.1, PW.4.1, PW.4.4, PW 7.1, PW 8.1, RV 1.1", + "class": "References" + } + ] + } + ] +} \ No newline at end of file diff --git a/web_app/sdlc-checklist/src/app/app.component.ts b/web_app/sdlc-checklist/src/app/app.component.ts index c014fe4..d83fd1f 100644 --- a/web_app/sdlc-checklist/src/app/app.component.ts +++ b/web_app/sdlc-checklist/src/app/app.component.ts @@ -181,6 +181,7 @@ export class AppComponent { } finishSave() { + (document.getElementById('incomplete-comment-dialog') as HTMLDialogElement)?.close(); this.assessmentPlanService.generateAssessmentPlan(); } diff --git a/web_app/sdlc-checklist/src/app/control/control.component.html b/web_app/sdlc-checklist/src/app/control/control.component.html index ea968b1..ae876d9 100644 --- a/web_app/sdlc-checklist/src/app/control/control.component.html +++ b/web_app/sdlc-checklist/src/app/control/control.component.html @@ -19,12 +19,13 @@ [examples]="control.examples" [references]="control.references" [props]="control.props" + [subControls]="control.controls" >
-

+

diff --git a/web_app/sdlc-checklist/src/app/group/group.component.css b/web_app/sdlc-checklist/src/app/group/group.component.css index 6714679..b4c99c9 100644 --- a/web_app/sdlc-checklist/src/app/group/group.component.css +++ b/web_app/sdlc-checklist/src/app/group/group.component.css @@ -78,3 +78,18 @@ img:hover { .na { border-radius: 0 4px 4px 0; } + +.group-container { + margin-left: 30px; + margin-right: 30px; + padding-left: 10px; + border-left: 1px solid black; +} + +.even { + background-color: rgb(236, 236, 236); +} + +.odd { + background-color: white; +} \ No newline at end of file diff --git a/web_app/sdlc-checklist/src/app/group/group.component.html b/web_app/sdlc-checklist/src/app/group/group.component.html index 73a41f1..b251827 100644 --- a/web_app/sdlc-checklist/src/app/group/group.component.html +++ b/web_app/sdlc-checklist/src/app/group/group.component.html @@ -12,10 +12,11 @@

-
- +
+ +
+
+
\ No newline at end of file diff --git a/web_app/sdlc-checklist/src/app/group/group.component.ts b/web_app/sdlc-checklist/src/app/group/group.component.ts index b01af1f..c845728 100644 --- a/web_app/sdlc-checklist/src/app/group/group.component.ts +++ b/web_app/sdlc-checklist/src/app/group/group.component.ts @@ -31,6 +31,7 @@ import { Control, Result } from '../models/attestationModel'; }) export class GroupComponent { @Input() group: any; + @Input() nestLevel: number = 0; /** * Hides the rollable components of all child controls @@ -44,7 +45,7 @@ export class GroupComponent { * @returns Whether all children are checked */ areAllChildrenChecked(): boolean { - return this.group.controls.reduce((truth: boolean, control: Control): boolean => { return truth && control.result !== Result.blank}, true) + return !this.group.getAllControls().some((control: Control) => { return control.result === Result.blank }) } /** @@ -58,7 +59,7 @@ export class GroupComponent { case "x": case "no": result = Result.no; break; case "na": case "n/a": result = Result.na; break; } - if (result !== Result.blank && this.group.controls.findIndex((control: Control) => {return control.result !== result}) === -1) result = Result.blank; - this.group.controls.forEach((control: Control) => {control.result = result}); + if (result !== Result.blank && !this.group.getAllControls().some((control: Control) => {return control.result !== result})) result = Result.blank; + this.group.getAllControls().forEach((control: Control) => {control.result = result}); } } diff --git a/web_app/sdlc-checklist/src/app/models/attestationModel.ts b/web_app/sdlc-checklist/src/app/models/attestationModel.ts index 34ba151..5a6b54b 100644 --- a/web_app/sdlc-checklist/src/app/models/attestationModel.ts +++ b/web_app/sdlc-checklist/src/app/models/attestationModel.ts @@ -121,7 +121,7 @@ export class Catalog { jsonData.groups.forEach((group) => { let newGroup = new Group(group, this.uuid); this.groups.push(newGroup); - newGroup.controls.forEach((control) => this.controlMap.set(control.id, control)); + newGroup.getAllControls().forEach((control) => this.controlMap.set(control.id, control)); }) this.metadata = new CatalogMetadata(jsonData.metadata); } @@ -142,16 +142,14 @@ export class Catalog { new Prop({name: "Catalog Name", value : this.metadata.title, class:"catalog"} as PropShell)] let include: {"control-id": string}[] = []; let exclude: {"control-id": string}[] = []; - this.groups.forEach((group) => { - group.controls.forEach((control) => { - if (control.result !== Result.blank) { - props.push(new Prop({name: control.id, value: control.stringResult, class: "Compliance Claim"} as PropShell)); - include.push({"control-id": control.id}); - } else { - exclude.push({"control-id": control.id}); - } - if (control.commentFinalized) props.push(new Prop({name: control.id, value: control.comment , class: "Attestation Claim"} as PropShell)); - }) + this.controls.forEach((control) => { + if (control.result !== Result.blank) { + props.push(new Prop({name: control.id, value: control.stringResult, class: "Compliance Claim"} as PropShell)); + include.push({"control-id": control.id}); + } else { + exclude.push({"control-id": control.id}); + } + if (control.commentFinalized) props.push(new Prop({name: control.id, value: control.comment , class: "Attestation Claim"} as PropShell)); }) return {props: props, "include-controls": include, "exclude-controls": exclude}; } @@ -171,6 +169,8 @@ export class Catalog { } }) } + + get controls(): Control[] {return Array.from(this.controlMap.values());} } export class Group { @@ -179,6 +179,7 @@ export class Group { title: string; expanded: boolean = true; catalogUUID: string; + groups: Group[] = [] /** * Creates a new group from a blank catalog @@ -188,8 +189,11 @@ export class Group { constructor (jsonData: GroupShell, catalogID: string) { this.id = jsonData.id; this.title = jsonData.title; - this.catalogUUID = catalogID - jsonData.controls.forEach((control) => {this.controls.push(new Control(control, catalogID))}) + this.catalogUUID = catalogID; + if (jsonData.controls !== undefined) + jsonData.controls.forEach((control) => {this.controls.push(new Control(control, catalogID))}); + if (jsonData.groups !== undefined) + jsonData.groups.forEach((group) => {this.groups.push(new Group(group, catalogID))}); } /** @@ -198,6 +202,13 @@ export class Group { toggleExpansion() { this.expanded = !this.expanded; } + + getAllControls(): Control[] { + let controls: Control[] = []; + this.controls.forEach((control) => {controls = controls.concat(control.getAllControls())}) + this.groups.forEach((group) => {controls = controls.concat(group.getAllControls())}) + return controls; + } } export class Control { @@ -211,6 +222,7 @@ export class Control { examples: string[] = []; props: Prop[] = []; expanded: boolean = false; + controls: Control[] = []; /** * Creates a control from a blank catalog file @@ -230,6 +242,8 @@ export class Control { this.props.push(new Prop(prop)); } }) + if (jsonData.controls !== undefined) + jsonData.controls.forEach((control) => {this.controls.push(new Control(control, catalogID))}); } /** @@ -265,6 +279,12 @@ export class Control { return this.result !== Result.blank; } + getAllControls(): Control[] { + let controls: Control[] = [this]; + this.controls.forEach((control: Control) => {controls = controls.concat(control.getAllControls())}); + return controls; + } + /** * Gets the result as a string */ diff --git a/web_app/sdlc-checklist/src/app/models/catalogModel.ts b/web_app/sdlc-checklist/src/app/models/catalogModel.ts index 0078e31..76cc4c0 100644 --- a/web_app/sdlc-checklist/src/app/models/catalogModel.ts +++ b/web_app/sdlc-checklist/src/app/models/catalogModel.ts @@ -40,7 +40,8 @@ export interface MetadataShell { export interface GroupShell { title: string; id: string; - controls: ControlShell[]; + controls: ControlShell[] | undefined; + groups: GroupShell[] | undefined; } export interface ControlShell { @@ -48,6 +49,7 @@ export interface ControlShell { title: string; props: PropShell[]; parts: PartShell[]; + controls: ControlShell[] | undefined; } export interface PropShell { diff --git a/web_app/sdlc-checklist/src/app/rollable/rollable.component.css b/web_app/sdlc-checklist/src/app/rollable/rollable.component.css index 1f23b6a..54cf3c5 100644 --- a/web_app/sdlc-checklist/src/app/rollable/rollable.component.css +++ b/web_app/sdlc-checklist/src/app/rollable/rollable.component.css @@ -25,6 +25,7 @@ .rollable-content { margin-left: 20px; margin-top: 5px; + border-left: 1px solid black; } .example, .reference { margin: .1em 3em .3 3em; @@ -47,4 +48,8 @@ ul { .reference { margin-left: 30px; margin-right: 30px; +} + +.subcontrols-unordered-list { + list-style-type: none; } \ No newline at end of file diff --git a/web_app/sdlc-checklist/src/app/rollable/rollable.component.html b/web_app/sdlc-checklist/src/app/rollable/rollable.component.html index da73fd9..ee1d127 100644 --- a/web_app/sdlc-checklist/src/app/rollable/rollable.component.html +++ b/web_app/sdlc-checklist/src/app/rollable/rollable.component.html @@ -25,4 +25,12 @@

Properties

+
+

Sub-Controls

+
    +
  • + +
  • +
+
\ No newline at end of file diff --git a/web_app/sdlc-checklist/src/app/rollable/rollable.component.ts b/web_app/sdlc-checklist/src/app/rollable/rollable.component.ts index 3a57a9a..3045222 100644 --- a/web_app/sdlc-checklist/src/app/rollable/rollable.component.ts +++ b/web_app/sdlc-checklist/src/app/rollable/rollable.component.ts @@ -33,6 +33,7 @@ export class RollableComponent { @Input() examples: any; @Input() references: any; @Input() props: any; + @Input() subControls: any; /** * @@ -65,4 +66,8 @@ export class RollableComponent { hasProperties(): boolean { return this.props !== undefined && this.props.length > 0; } + + hasSubControls(): boolean { + return this.subControls !== undefined && this.subControls.length > 0; + } } \ No newline at end of file