Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0355520
work in progress
georgedias Mar 1, 2024
ee70c3e
Completed filtered html report
georgedias Mar 1, 2024
11933bf
SonarCloud fix
georgedias Mar 1, 2024
15fcf8c
Merge branch 'master' into htmlFilteredReports
georgedias Mar 1, 2024
1716018
Removed copy package file
georgedias Mar 1, 2024
4f3d77f
Merge branch 'htmlFilteredReports' of github.com:mitre/heimdall2 into…
georgedias Mar 1, 2024
ebb6630
remove ssl certs from pr
em-c-rod Mar 4, 2024
ee2d83c
Revert "remove ssl certs from pr"
em-c-rod Mar 4, 2024
fb5cae2
try removing the certs again because the test may have errored for a …
em-c-rod Mar 4, 2024
ad7e902
reset yarn.lock to what master has and set the package.json setting b…
em-c-rod Mar 4, 2024
6fcd9f7
Merge branch 'master' into htmlFilteredReports
aaronlippold Mar 10, 2024
6d0d602
Added capability to filter reports on status and severity
georgedias Mar 14, 2024
c9da6b9
Sonar cloud fixes
georgedias Mar 14, 2024
16debd8
Update apps/frontend/src/components/global/ExportHTMLModal.vue
em-c-rod Mar 14, 2024
c685143
Update apps/frontend/src/components/global/ExportHTMLModal.vue
em-c-rod Mar 14, 2024
2eb1c5f
Update apps/frontend/src/components/global/ExportHTMLModal.vue
em-c-rod Mar 14, 2024
27d54f7
linting
em-c-rod Mar 14, 2024
ef73c42
Only display files that have selected controls
georgedias Mar 15, 2024
942b798
Merge branch 'htmlFilteredReports' of github.com:mitre/heimdall2 into…
georgedias Mar 15, 2024
9876542
Only display files that have selected controls
georgedias Mar 15, 2024
22455aa
Merge branch 'master' into htmlFilteredReports
georgedias Mar 15, 2024
a490685
Added wait cursor while loading files and generating HTML report
georgedias Mar 16, 2024
bccfbbc
Merge branch 'master' into htmlFilteredReports
em-c-rod Mar 21, 2024
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
100 changes: 98 additions & 2 deletions apps/frontend/src/components/global/ExportHTMLModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
<pre class="pt-5" v-text="description" />
</v-col>
</v-row>
<v-row>
<v-col cols="1">
<v-icon color="primary">mdi-information-variant-circle</v-icon>
</v-col>
<v-col>
Both Manager and Administrator Reports can be data intensive,
does consuming computer memory resources, which can take longer for
the browser to render the page.
</v-col>
</v-row>
</v-card-text>
<v-divider />
<v-card-actions>
Expand All @@ -57,6 +67,7 @@ import {Filter} from '../../store/data_filters';
import {InspecDataModule} from '../../store/data_store';
import {SnackbarModule} from '../../store/snackbar';
import {FromHDFToHTMLMapper} from '@mitre/hdf-converters';
import {SourcedContextualizedEvaluation} from '../../store/report_intake';

// All selectable export types for an HTML export
enum FileExportTypes {
Expand Down Expand Up @@ -119,22 +130,32 @@ export default class ExportHTMLModal extends Vue {
}

const files = [];
const filteredStatus = this.filter.status!.toString();
const filteredSeverity = this.filter.severity!.toString();

for (const fileId of this.filter.fromFile) {
const file = InspecDataModule.allEvaluationFiles.find(
(f) => f.uniqueId === fileId
);

if (file) {
const data = file.evaluation;

const filteredControls = this.getFilterControlIds(
data,
filteredStatus,
filteredSeverity
);
const fileName = file.filename;
const fileID = file.uniqueId;
files.push({data, fileName, fileID});
files.push({data, fileName, fileID, filteredControls});
}
}

// Generate and export HTML file
const body = await new FromHDFToHTMLMapper(files, this.exportType).toHTML(
'/static/export/'
);

saveAs(
new Blob([s2ab(body)], {type: 'application/octet-stream'}),
`${this.exportType}_Report_${new Date().toString()}.html`.replace(
Expand All @@ -145,5 +166,80 @@ export default class ExportHTMLModal extends Vue {

this.closeModal();
}

/**
* Generate an array containing the control identification numbers
* (profiles.controls) selected. The Id is extracted for the
* profiles.controls.id, it can be CIS, STIG (V or SV), CWEID, WASCID,
* or any other control Id.
*
* Possible selection permutations are:
* - Status (pass, failed, etc)
* - Severity ( low, medium, etc)
* - Combination of Status and Severity
*/
getFilterControlIds(
data: SourcedContextualizedEvaluation,
status: string,
severity: string
): string[] {
/**
* NOTE: The filterControls array is used to specify what controls
* are selected based on Status and Severity selection.
* If we use the approach of filtering the content from the data object
* (e.g.
* data.data.profiles[0].controls =
* data.data.profiles[0].controls.filter((control) => {
* if (filteredControls.includes(control.id)) {
* return filteredControls.includes(control.id);
* }
* });
* )
* the contextualize object does not get updated and the results
* in data_store get out of sync, there is, when utilizing the
* ".contains" it returns the results object (child of the controls object)
* where the file.evaluations returns the filtered controls.
*/
let filteredControls: string[] = [];
// Both Status and Severity selection
if (status.length > 0 && severity.length > 0) {
data.contains.map((profile) => {
profile.contains.map((result) => {
if (
status?.includes(result.root.hdf.status) &&
severity?.includes(result.root.hdf.severity)
) {
filteredControls.push(result.data.id);
}
});
});
// Status selection
} else if (status.length > 0) {
data.contains.map((profile) => {
profile.contains.map((result) => {
if (status?.includes(result.root.hdf.status)) {
filteredControls.push(result.data.id);
}
});
});
// Severity selection
} else if (severity.length > 0) {
data.contains.map((profile) => {
profile.contains.map((result) => {
if (severity?.includes(result.root.hdf.severity)) {
filteredControls.push(result.data.id);
}
});
});
// No selection
} else {
data.contains.map((profile) => {
profile.contains.map((result) => {
filteredControls.push(result.data.id);
});
});
}
return filteredControls;
}
}
</script>
19 changes: 14 additions & 5 deletions apps/frontend/src/components/global/upload_tabs/FileReader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,13 @@
<v-progress-circular
indeterminate
color="#ff5600"
:size="80"
:width="20"
/>
:size="120"
:width="15"
>
<template #default>
<b>{{ percent }}% loaded</b>
</template>
</v-progress-circular>
</div>
</div>
</v-col>
Expand Down Expand Up @@ -140,7 +144,7 @@ interface VueFileAgentRecord {
export default class FileReader extends mixins(ServerMixin) {
fileRecords: Array<VueFileAgentRecord> = [];
loading = false;

percent = 0;
isActiveDialog = false;

filesSelected() {
Expand All @@ -151,10 +155,14 @@ export default class FileReader extends mixins(ServerMixin) {

/** Callback for our file reader */
commit_files(files: File[]) {
const totalFiles = files.length;
let index = 1;
Promise.all(
files.map(async (file) => {
try {
return await InspecIntakeModule.loadFile({file});
const fileId = await InspecIntakeModule.loadFile({file});
this.percent = Math.floor((index++ / totalFiles) * 100);
return fileId;
} catch (err) {
SnackbarModule.failure(String(err));
}
Expand All @@ -174,6 +182,7 @@ export default class FileReader extends mixins(ServerMixin) {
})
.finally(() => {
this.loading = false;
this.percent = 0;
});
}

Expand Down
3 changes: 3 additions & 0 deletions apps/frontend/src/views/Results.vue
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ export default class Results extends mixins(RouteMixin, ServerMixin) {
treeFilters: TreeMapState = [];
controlSelection: string | null = null;

gotStatus: boolean = false;
gotSeverity: boolean = false;

/** Model for if all-filtered snackbar should be showing */
filterSnackbar = false;

Expand Down
2 changes: 1 addition & 1 deletion libs/hdf-converters/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@
"^.+\\.ts$": "ts-jest"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ type InputData = {
data: ContextualizedEvaluation | string;
fileName: string;
fileID: string;
filteredControls?: string[];
};

type ProcessedData = {
data: ContextualizedEvaluation;
fileName: string;
fileID: string;
filteredControls?: string[];
};

// All selectable export types for an HTML export
Expand Down Expand Up @@ -174,7 +176,12 @@ export class FromHDFToHTMLMapper {
}

this.addFiledata(
{data: file.data, fileName: file.fileName, fileID: file.fileID},
{
data: file.data,
fileName: file.fileName,
fileID: file.fileID,
filteredControls: file.filteredControls
},
exportType
);
}
Expand All @@ -199,11 +206,24 @@ export class FromHDFToHTMLMapper {

// Pull out results from file
const allResultLevels: ContextualizedControl[] = [];
file.data.contains.map((profile) => {
profile.contains.map((result) => {
allResultLevels.push(result);
if (file.filteredControls === undefined) {
file.data.contains.map((profile) => {
profile.contains.map((result) => {
allResultLevels.push(result);
});
});
});
} else {
file.data.contains.flatMap((profile) => {
profile.contains.flatMap((result) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
for (const element of file.filteredControls!) {
if (element === result.data.id) {
allResultLevels.push(result);
}
}
});
});
}

// Begin filling out outpuData object to pass into HTML template
// Set high level generalized profile details
Expand Down Expand Up @@ -310,7 +330,7 @@ export class FromHDFToHTMLMapper {
};

// Calculate & set compliance level and color from result statuses
// Set default complaince level and color
// Set default compliance level and color
this.outputData.compliance.level = '0.00%';
this.outputData.compliance.color = 'low';

Expand All @@ -324,7 +344,9 @@ export class FromHDFToHTMLMapper {
100
);
// Set compliance level
this.outputData.compliance.level = complianceLevel;
this.outputData.compliance.level = complianceLevel.includes('NaN')
? '0.00%'
: complianceLevel;
// Determine color of compliance level
// High compliance is green, medium is yellow, low is red
this.outputData.compliance.color = translateCompliance(complianceLevel);
Expand Down Expand Up @@ -495,7 +517,7 @@ export class FromHDFToHTMLMapper {
return text;
}

// Prompt HTML generation from data pulled from file during constructor intialization
// Prompt HTML generation from data pulled from file during constructor initialization
// Requires path to prompt location of needed files relative to function call location
async toHTML(path: string): Promise<string> {
// Pull export template + styles and create outputData object containing data to fill template with
Expand All @@ -517,7 +539,6 @@ export class FromHDFToHTMLMapper {
'//# sourceMappingURL=tw-elements.umd.min.js.map',
''
);

// Render template and return generated HTML file
return Mustache.render(template, this.outputData);
}
Expand Down
6 changes: 4 additions & 2 deletions libs/inspecjs/src/compat_wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,14 @@ export interface HDFControl {
*/
parsedNistRevision: NistRevision | null;

/** Get the start time of this control's run, as determiend by the time of the first test.
/**
* Get the start time of this control's run, as determined by the time of the first test.
* If no tests were run, (it is a profile-json or has no tests) returns undefined
*/
start_time?: string;

/** Get the results of this control's control segments as a list.
/**
* Get the results of this control's control segments as a list.
* If no tests were run, (this is a profile-json) returns undefined.
* Can be empty in the rare case that no control segments exist/were run.
*/
Expand Down
4 changes: 2 additions & 2 deletions libs/inspecjs/src/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Provides general utilities for articulating associations beteen evaluations, profiles, and controls.
* Provides general utilities for articulating associations between evaluations, profiles, and controls.
* Especially useful for handling overlay/wrapper profiles.
*/

Expand Down Expand Up @@ -206,7 +206,7 @@ export function contextualizeEvaluation(

// Link each contextualized control
for (const cc of allControls) {
// Behaviour changes based on if we have well-formed or malformed profile dependency
// Behavior changes based on if we have well-formed or malformed profile dependency
if (cc.sourcedFrom.extendsFrom.length || cc.sourcedFrom.extendedBy.length) {
// Our profile is a baseline! No need to continue - children will make connections for us
// If we aren't extended from something we just drop. Our children will make connections for us
Expand Down