Skip to content

Commit

Permalink
Add: Added a dedicated view for compliance audit reports (#3952)
Browse files Browse the repository at this point in the history
* Compliance reports are now listed under Resilience tab and do not appear anymore under Scans tab. A dedicated view for a compliance report shows compliance of results.
* This feature is currently behind a feature toggle: COMPLIANCE_REPORTS
  • Loading branch information
a-h-abdelsalam authored Aug 23, 2024
1 parent 600951b commit 52940b5
Show file tree
Hide file tree
Showing 88 changed files with 8,335 additions and 409 deletions.
3 changes: 3 additions & 0 deletions allowedSnakeCase.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ module.exports = [
'_asset_id',
'asset_id',
'assigned_to',
'audit_report',
'audit_reports',
'auth_algorithm',
'auth_conf_setting',
'auth_method',
Expand Down Expand Up @@ -248,6 +250,7 @@ module.exports = [
'highest_severity',
'high_per_host',
'host_allow',
'host_compliance',
'host_cves',
'hostnames_by_ip',
'hosts_allow',
Expand Down
9 changes: 9 additions & 0 deletions public/locales/gsa-de.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@
"Audit made visible for:\n{{user}}\n{{role}}\n{{group}}": "Audit sichtbar gemacht für:\n{{user}}\n{{role}}\n{{group}}",
"Audit: {{name}}": "Audit: {{name}}",
"Audits": "Audits",
"Audit Reports by Compliance (Total: {{count}})": "Audit-Berichte nach Compliance (Gesamt: {{count}})",
"Audit Reports": "Audit-Berichte",
"Audit Report": "Audit-Bericht",
"Audits using this Policy": "Audits, die diese Richtlinie verwenden",
"Auth": "Auth.",
"Auth Algorithm": "Auth-Algorithmus",
Expand Down Expand Up @@ -243,6 +246,7 @@
"Certificate in use will expire at {{date}}": "Aktuelles Zertifikat wird am {{date}} ablaufen",
"Change Password": "Passwort ändern",
"Changed": "Verändert",
"Chart: Audit Reports by Compliance": "Diagramm: Audit-Berichte nach Compliance",
"Chart: CERT-Bund Advisories by CVSS": "Diagramm: CERT-Bund-Advisories nach CVSS",
"Chart: CERT-Bund Advisories by Creation Time": "Diagramm: CERT-Bund-Advisories nach Erstellungszeit",
"Chart: CERT-Bund Advisories by Severity Class": "Diagramm: CERT-Bund-Advisories nach Schweregradklasse",
Expand Down Expand Up @@ -323,6 +327,8 @@
"Complete": "Vollständig",
"Complexity": "Komplexität",
"Compliance Audits": "Compliance Audits",
"Compliance Audit Reports": "Compliance-Audit-Berichte",
"Compliance Percent": "Compliance-Prozent",
"Compliance Policies": "Compliance Richtlinien",
"Compliance Status": "Compliance Status",
"Compose": "Zusammenstellen",
Expand Down Expand Up @@ -841,6 +847,7 @@
"Include log messages in your filter settings.": "Log-Nachrichten in die Filtereinstellungen einbeziehen.",
"Include report": "Bericht einfügen",
"Included": "Beinhaltet",
"Incomplete": "Unvollständig",
"Info": "Info",
"Information": "Informationen",
"Inheriting user": "Erbender Benutzer",
Expand Down Expand Up @@ -1543,6 +1550,7 @@
"TLS Certificates by Modification Time (Total: {{count}})": "TLS-Zertifikate nach Änderungszeit (Gesamt: {{count}})",
"TLS Certificates by Status (Total: {{count}})": "TLS-Zertifikate nach Status (Gesamt: {{count}})",
"TLS Certificates for this Host": "TLS-Zertifikate für diesen Host",
"Table: Audit Reports by Compliance": "Tabelle: Audit-Berichte nach Compliance",
"Table: CERT-Bund Advisories by CVSS": "Tabelle: CERT-Bund-Advisories nach CVSS",
"Table: CERT-Bund Advisories by Creation Time": "Tabelle: CERT-Bund-Advisories nach Erstellungszeit",
"Table: CERT-Bund Advisories by Severity Class": "Tabelle: CERT-Bund-Advisories nach Schweregradklasse",
Expand Down Expand Up @@ -1908,6 +1916,7 @@
"task": "Aufgabe",
"to": "für",
"undefined": "undefiniert",
"Undefined": "Undefiniert",
"until {{- enddate}}": "bis {{- enddate}}",
"verinice Connector": "verinice-Konnektor",
"verinice.PRO Connector": "verinice.PRO-Konnektor",
Expand Down
15 changes: 11 additions & 4 deletions src/gmp/capabilities/capabilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {pluralizeType} from 'gmp/utils/entitytype';
import {parseBoolean} from 'gmp/parser';

const types = {
audit: 'task',
audits: 'task',
auditreport: 'audit_report',
auditreports: 'audit_reports',
host: 'asset',
hosts: 'asset',
os: 'asset',
Expand Down Expand Up @@ -42,12 +42,19 @@ const types = {
tlscertificates: 'tls_certificate',
};

const subtypes = {
audit: 'task',
audits: 'task',
audit_report: 'report',
audit_reports: 'reports',
};

const convertType = type => {
const ctype = types[type];
if (isDefined(ctype)) {
return ctype;
type = ctype;
}
return type;
return subtypes[type] || type;
};

class Capabilities {
Expand Down
33 changes: 33 additions & 0 deletions src/gmp/commands/__tests__/auditreport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* SPDX-FileCopyrightText: 2024 Greenbone AG
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import {describe, test, expect} from '@gsa/testing';
import {createHttp, createEntityResponse} from 'gmp/commands/testing';
import {AuditReportCommand} from 'gmp/commands/auditreports';

describe('AuditReportCommand tests', () => {
test('should request single audit report', () => {
const response = createEntityResponse('report', {_id: 'foo'});
const fakeHttp = createHttp(response);

expect.hasAssertions();

const cmd = new AuditReportCommand(fakeHttp);
return cmd.get({id: 'foo'}).then(resp => {
expect(fakeHttp.request).toHaveBeenCalledWith('get', {
args: {
cmd: 'get_report',
report_id: 'foo',
ignore_pagination: 1,
details: 1,
lean: 1,
},
});

const {data} = resp;
expect(data.id).toEqual('foo');
});
});
});
92 changes: 92 additions & 0 deletions src/gmp/commands/__tests__/auditreports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* SPDX-FileCopyrightText: 2024 Greenbone AG
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import {describe, test, expect} from '@gsa/testing';
import {ALL_FILTER} from 'gmp/models/filter';

import {
createHttp,
createEntitiesResponse,
createAggregatesResponse,
} from '../testing';
import {AuditReportsCommand} from 'gmp/commands/auditreports';

describe('AuditReportsCommand tests', () => {
test('should return all audit reports', () => {
const response = createEntitiesResponse('report', [
{
_id: '1',
},
{
_id: '2',
},
]);

const fakeHttp = createHttp(response);

expect.hasAssertions();

const cmd = new AuditReportsCommand(fakeHttp);
return cmd.getAll().then(resp => {
expect(fakeHttp.request).toHaveBeenCalledWith('get', {
args: {
cmd: 'get_reports',
details: 0,
filter: ALL_FILTER.toFilterString(),
usage_type: 'audit',
},
});
const {data} = resp;
expect(data.length).toEqual(2);
});
});

test('should return results', () => {
const response = createEntitiesResponse('report', [
{
_id: '1',
},
{
_id: '2',
},
]);

const fakeHttp = createHttp(response);

expect.hasAssertions();

const cmd = new AuditReportsCommand(fakeHttp);
return cmd.get().then(resp => {
expect(fakeHttp.request).toHaveBeenCalledWith('get', {
args: {
cmd: 'get_reports',
details: 0,
usage_type: 'audit',
},
});
const {data} = resp;
expect(data.length).toEqual(2);
});
});

test('should aggregate compliance counts', () => {
const response = createAggregatesResponse();
const fakeHttp = createHttp(response);

expect.hasAssertions();

const cmd = new AuditReportsCommand(fakeHttp);
return cmd.getComplianceAggregates().then(resp => {
expect(fakeHttp.request).toHaveBeenCalledWith('get', {
args: {
cmd: 'get_aggregate',
aggregate_type: 'report',
group_column: 'compliant',
usage_type: 'audit',
},
});
});
});
});
2 changes: 2 additions & 0 deletions src/gmp/commands/__tests__/reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('ReportsCommand tests', () => {
cmd: 'get_reports',
details: 0,
filter: ALL_FILTER.toFilterString(),
usage_type: 'scan',
},
});
const {data} = resp;
Expand Down Expand Up @@ -59,6 +60,7 @@ describe('ReportsCommand tests', () => {
args: {
cmd: 'get_reports',
details: 0,
usage_type: 'scan',
},
});
const {data} = resp;
Expand Down
139 changes: 139 additions & 0 deletions src/gmp/commands/auditreports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* SPDX-FileCopyrightText: 2024 Greenbone AG
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import {isDefined} from 'gmp/utils/identity';

import registerCommand from 'gmp/command';

import AuditReport from 'gmp/models/auditreport';

import {ALL_FILTER} from 'gmp/models/filter';

import DefaultTransform from 'gmp/http/transform/default';

import {convertBoolean} from './convert';
import EntitiesCommand from './entities';
import EntityCommand from './entity';

export class AuditReportsCommand extends EntitiesCommand {
constructor(http) {
super(http, 'report', AuditReport);
}

getEntitiesResponse(root) {
return root.get_reports.get_reports_response;
}

getComplianceAggregates({filter} = {}) {
return this.getAggregates({
aggregate_type: 'report',
group_column: 'compliant',
usage_type: 'audit',
filter,
});
}

get(params, options) {
return super.get(
{
details: 0,
...params,
usage_type: 'audit',
},
options,
);
}
}

export class AuditReportCommand extends EntityCommand {
constructor(http) {
super(http, 'report', AuditReport);
}

download({id}, {reportFormatId, deltaReportId, filter}) {
return this.httpGet(
{
cmd: 'get_report',
delta_report_id: deltaReportId,
details: 1,
report_id: id,
report_format_id: reportFormatId,
filter: isDefined(filter) ? filter.all() : ALL_FILTER,
},
{transform: DefaultTransform, responseType: 'arraybuffer'},
);
}

addAssets({id}, {filter = ''}) {
return this.httpPost({
cmd: 'create_asset',
report_id: id,
filter,
});
}

removeAssets({id}, {filter = ''}) {
return this.httpPost({
cmd: 'delete_asset',
report_id: id,
filter,
});
}

alert({alert_id, report_id, filter}) {
return this.httpPost({
cmd: 'report_alert',
alert_id,
report_id,
filter,
});
}

getDelta(
{id},
{id: delta_report_id},
{filter, details = true, ...options} = {},
) {
return this.httpGet(
{
id,
delta_report_id,
filter,
ignore_pagination: 1,
details: convertBoolean(details),
},
options,
).then(this.transformResponse);
}

get(
{id},
{
filter,
details = true,
ignorePagination = true,
lean = true,
...options
} = {},
) {
return this.httpGet(
{
id,
filter,
lean: convertBoolean(lean),
ignore_pagination: convertBoolean(ignorePagination),
details: convertBoolean(details),
},
options,
).then(this.transformResponse);
}

getElementFromRoot(root) {
return root.get_report.get_reports_response.report;
}
}

registerCommand('auditreport', AuditReportCommand);
registerCommand('auditreports', AuditReportsCommand);
1 change: 1 addition & 0 deletions src/gmp/commands/reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class ReportsCommand extends EntitiesCommand {
{
details: 0, // ensure to request no details by default
...params,
usage_type: 'scan',
},
options,
);
Expand Down
Loading

0 comments on commit 52940b5

Please sign in to comment.