Skip to content

Subgroups subcontrols #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions research/OSCAL/Catalog/SP800-218/nestTest.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
]
}
1 change: 1 addition & 0 deletions web_app/sdlc-checklist/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export class AppComponent {
}

finishSave() {
(document.getElementById('incomplete-comment-dialog') as HTMLDialogElement)?.close();
this.assessmentPlanService.generateAssessmentPlan();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
[examples]="control.examples"
[references]="control.references"
[props]="control.props"
[subControls]="control.controls"
></app-rollable>
</div>

<dialog class="pane popup" [id]="'comment-popup-' + control.uid" (mousedown)="clicked($event)">
<br>
<label for="comment" class="explanation-label">Brief Explanation: </label><br><br>
<label [for]="'comment-' + control.uid" class="explanation-label">Brief Explanation: </label><br><br>
<textarea [id]="'comment-' + control.uid" placeholder="Explanation" rows="4"></textarea>
<div class="bottom-buttons">
<div (click)="done()" (keydown.enter)="done()" tabindex=0>
Expand Down
15 changes: 15 additions & 0 deletions web_app/sdlc-checklist/src/app/group/group.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
9 changes: 5 additions & 4 deletions web_app/sdlc-checklist/src/app/group/group.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ <h2 (click)="group.toggleExpansion()" [className]="group.expanded ? 'prependDown
</div>
</div>
<div class="group-rollable-content" [hidden]="!group.expanded">
<div id="checkbox-container" class="checkbox-container">
<app-control *ngFor="let item of group.controls"
[control]="item"
></app-control>
<div class="checkbox-container">
<app-control *ngFor="let item of group.controls" [control]="item"></app-control>
</div>
<div [class]="((nestLevel % 2 === 0) ? 'even ' : 'odd ') + 'group-container'">
<app-group *ngFor="let subgroup of group.groups" [group]="subgroup" [nestLevel]="nestLevel + 1"></app-group>
</div>
</div>
</section>
7 changes: 4 additions & 3 deletions web_app/sdlc-checklist/src/app/group/group.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 })
}

/**
Expand All @@ -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});
}
}
46 changes: 33 additions & 13 deletions web_app/sdlc-checklist/src/app/models/attestationModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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};
}
Expand All @@ -171,6 +169,8 @@ export class Catalog {
}
})
}

get controls(): Control[] {return Array.from(this.controlMap.values());}
}

export class Group {
Expand All @@ -179,6 +179,7 @@ export class Group {
title: string;
expanded: boolean = true;
catalogUUID: string;
groups: Group[] = []

/**
* Creates a new group from a blank catalog
Expand All @@ -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))});
}

/**
Expand All @@ -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 {
Expand All @@ -211,6 +222,7 @@ export class Control {
examples: string[] = [];
props: Prop[] = [];
expanded: boolean = false;
controls: Control[] = [];

/**
* Creates a control from a blank catalog file
Expand All @@ -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))});
}

/**
Expand Down Expand Up @@ -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
*/
Expand Down
4 changes: 3 additions & 1 deletion web_app/sdlc-checklist/src/app/models/catalogModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ export interface MetadataShell {
export interface GroupShell {
title: string;
id: string;
controls: ControlShell[];
controls: ControlShell[] | undefined;
groups: GroupShell[] | undefined;
}

export interface ControlShell {
id: string;
title: string;
props: PropShell[];
parts: PartShell[];
controls: ControlShell[] | undefined;
}

export interface PropShell {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
.rollable-content {
margin-left: 20px;
margin-top: 5px;
border-left: 1px solid black;
}
.example, .reference {
margin: .1em 3em .3 3em;
Expand All @@ -47,4 +48,8 @@ ul {
.reference {
margin-left: 30px;
margin-right: 30px;
}

.subcontrols-unordered-list {
list-style-type: none;
}
Loading