Skip to content
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
10 changes: 5 additions & 5 deletions components/sctm/SecurityAssessment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
</span>
</ListboxButton>

<transition
<Transition
leave-active-class="transition ease-in duration-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
Expand Down Expand Up @@ -93,7 +93,7 @@
</li>
</ListboxOption>
</ListboxOptions>
</transition>
</Transition>
</div>
</Listbox>
</div>
Expand Down Expand Up @@ -180,7 +180,7 @@
</span>
</ListboxButton>

<transition
<Transition
leave-active-class="transition ease-in duration-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
Expand Down Expand Up @@ -219,7 +219,7 @@
</li>
</ListboxOption>
</ListboxOptions>
</transition>
</Transition>
</div>
</Listbox>
</div>
Expand Down Expand Up @@ -255,7 +255,7 @@

<script setup lang="ts">
import { CheckIcon, ChevronDownIcon } from "@heroicons/vue/20/solid";
import { Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions, Transition } from "@headlessui/vue";
import { Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions } from "@headlessui/vue";

interface DropdownItem {
id: number;
Expand Down
58 changes: 58 additions & 0 deletions server/utils/cciMapping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { CciItem, CciReference } from "~/db/models";

export function normalizeCciControlIndex(index: string): string | null {
const controlMatch = index
.trim()
.toUpperCase()
.match(/^([A-Z]{2}-\s*\d+(?:\s*\(\d+\))?)/);

Check warning on line 7 in server/utils/cciMapping.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=mitre_tir&issues=AZ_XneULF7nRZoMTCFNh&open=AZ_XneULF7nRZoMTCFNh&pullRequest=230

return controlMatch
? controlMatch[1].replace(/\s+/g, "")
: null;
}

export async function getCciMappingData(
policyDocumentId: number | undefined,
) {
const cciItems = await CciItem.findAll({
attributes: ["cciId", "definition"],
include: [
{
model: CciReference,
attributes: ["index"],
through: { attributes: [] },
where: {
PolicyDocumentId: policyDocumentId,
},
},
],
});

const cciMap = new Map<string, string[]>();

for (const cciItem of cciItems) {
const refs = cciItem.CciReferences ?? [];

for (const ref of refs) {
if (!ref.index) continue;

const normalizedIndex =
normalizeCciControlIndex(ref.index);

if (!normalizedIndex) continue;

const cciIds = cciMap.get(normalizedIndex) ?? [];

if (!cciIds.includes(cciItem.cciId)) {
cciIds.push(cciItem.cciId);
}

cciMap.set(normalizedIndex, cciIds);
}
}

return {
cciItems,
cciMap,
};
}
69 changes: 29 additions & 40 deletions server/utils/excelExport/scaExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import {
FrequencyType,
ImplementationStatus,
TestMethod,
CciItem,
CciReference,
ComplianceStatus,
} from "~/db/models";
import {
getCciMappingData,
normalizeCciControlIndex,
} from "~/server/utils/cciMapping";

export async function generateSecurityControlAssessment(
boundaryId: number,
Expand Down Expand Up @@ -374,33 +376,13 @@ export async function generateSecurityControlAssessment(
],
});

const cciItems = await CciItem.findAll({
attributes: ["cciId", "definition"],
include: [
{
model: CciReference,
attributes: ["index"],
through: { attributes: [] },
where: {
PolicyDocumentId: boundary?.PolicyDocumentId,
},
},
],
});
const cciItemMap = new Map(cciItems.map((item) => [item.cciId, item]));
const cciMap = new Map<string, string[]>();

for (const cciItem of cciItems) {
const refs = cciItem.CciReferences ?? [];
for (const ref of refs) {
if (!ref.index) continue;
const normalizedIndex = ref.index.replace(/\s+/g, "");
if (!cciMap.has(normalizedIndex)) {
cciMap.set(normalizedIndex, []);
}
cciMap.get(normalizedIndex)!.push(cciItem.cciId);
}
}
const { cciItems, cciMap } = await getCciMappingData(
boundary?.PolicyDocumentId,
);

const cciItemMap = new Map(
cciItems.map((item) => [item.cciId, item]),
);

const stigResults = await getEvaluationSummary(boundaryId, undefined, false);

Expand All @@ -418,19 +400,26 @@ export async function generateSecurityControlAssessment(

for (const cciId of cciIds) {
const cciItem = cciItemMap.get(cciId);
const cciRef = cciItem?.CciReferences?.[0]?.index ?? "";
const normalizedControl = cciRef.replace(/\s+/g, "");
if (!normalizedControl) continue;
const refs = cciItem?.CciReferences ?? [];

if (!controlToStatusMap.has(normalizedControl)) {
controlToStatusMap.set(normalizedControl, new Map());
}
for (const ref of refs) {
if (!ref.index) continue;

const normalizedControl = normalizeCciControlIndex(ref.index);
if (!normalizedControl) continue;

if (!controlToStatusMap.has(normalizedControl)) {
controlToStatusMap.set(normalizedControl, new Map());
}

const statusMap = controlToStatusMap.get(normalizedControl)!;

if (!statusMap.has(status)) {
statusMap.set(status, new Set());
}

const statusMap = controlToStatusMap.get(normalizedControl)!;
if (!statusMap.has(status)) {
statusMap.set(status, new Set());
statusMap.get(status)!.add(displayValue);
}
statusMap.get(status)!.add(displayValue);
}
}
}
Expand Down Expand Up @@ -564,7 +553,7 @@ export async function generateSecurityControlAssessment(
}

newRow[Columns.controlNumber] = controlNumber;
const normalizedControlNumber = controlNumber.replace(/\s+/g, "");
const normalizedControlNumber = normalizeCciControlIndex(controlNumber) ?? "";
const statusMap = controlToStatusMap.get(normalizedControlNumber);
const cciIds = cciMap.get(normalizedControlNumber) || [];
newRow[Columns.cci] = cciIds.length ? cciIds.join("\n") + "\n" : "";
Expand Down
41 changes: 8 additions & 33 deletions server/utils/excelExport/sctmExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import {
FrequencyType,
ImplementationStatus,
TestMethod,
CciItem,
CciReference
} from "~/db/models";
import {
getCciMappingData,
normalizeCciControlIndex,
} from "~/server/utils/cciMapping";

export async function generateSctm(
boundaryId: number,
Expand Down Expand Up @@ -376,36 +378,9 @@ export async function generateSctm(
],
}))

const cciItems = await CciItem.findAll({
attributes: ["cciId", "definition"],
include: [
{
model: CciReference,
attributes: ["index"],
through: { attributes: [] },
where: {
PolicyDocumentId: boundary?.PolicyDocumentId,
},
},
],
});

const cciMap = new Map<string, string[]>();


for (const cciItem of cciItems) {
const refs = cciItem.CciReferences ?? []; // safe fallback
for (const ref of refs) {
if (!ref.index) continue;

// Normalize by removing spaces for universal matching
const normalizedIndex = ref.index.replace(/\s+/g, "");
if (!cciMap.has(normalizedIndex)) {
cciMap.set(normalizedIndex, []);
}
cciMap.get(normalizedIndex)!.push(cciItem.cciId);
}
}
const { cciMap } = await getCciMappingData(
boundary?.PolicyDocumentId,
);

const revName = `rev${boundary?.PolicyDocument?.version}`;
const revision = await ControlRevision.findOne({ where: { name: revName } });
Expand Down Expand Up @@ -521,7 +496,7 @@ export async function generateSctm(
control.ControlStatements?.map((s: any) => s.description).join("\n") || "";
}
newRow[Columns.controlNumber] = controlNumber;
const normalizedControlNumber = controlNumber.replace(/\s+/g, "");
const normalizedControlNumber = normalizeCciControlIndex(controlNumber) ?? "";
const cciIds = cciMap.get(normalizedControlNumber) || [];
newRow[Columns.cci] = cciIds.length ? cciIds.join("\n") + "\n" : "";
// Map all other fields from ControlRecordItem
Expand Down