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
8 changes: 6 additions & 2 deletions app/src/electron/request-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const fs = require('fs');
const parser = require('../../../lib/src/api/xml-json/parser');
const alterISRA = require('../../../lib/src/api/xml-json/alter-isra/alter-isra');
const validateJsonSchema = require('../../../lib/src/api/xml-json/validate-json-schema');
const cleanupVulnerabilitySupportingAssets = require('../../../lib/src/api/xml-json/alter-isra/cleanup-vulnerability-refs');

const errorMessages = require('./validation')

Expand Down Expand Up @@ -740,9 +741,12 @@ function getJSON(filePath){
}
}
}
const vulnerabilitySupportingAssetCleanup = cleanupVulnerabilitySupportingAssets(jsonData);

const importedISRA = validateJsonSchema(jsonData);
return importedISRA
importedISRA.vulnerabilitySupportingAssetCleanup = vulnerabilitySupportingAssetCleanup;

return importedISRA;
} catch (error) {
console.log(error);
const errorMessage = getError(error)
Expand Down Expand Up @@ -1355,4 +1359,4 @@ ipcMain.on('israreport:saveGraph', (event,graph) => {

// ipcMain.handle('dark-mode:system', () => {
// nativeTheme.themeSource = 'system';
// });
// });
5 changes: 4 additions & 1 deletion lib/src/api/data-load/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const ISRAProject = require('../../model/classes/ISRAProject/isra-project');
const validateJSONschema = require('../xml-json/validate-json-schema');
const populateClass = require('../xml-json/populate-class');
const { sanitizeSupportingAssetRefs, sanitizeTrackingURI } = require('../xml-json/alter-isra/sanitizers');
const cleanupVulnerabilitySupportingAssets = require('../xml-json/alter-isra/cleanup-vulnerability-refs');

/**
* Load existing json file if any
Expand Down Expand Up @@ -113,10 +114,12 @@ const DataLoad = (filePath) => {
}
}

const vulnerabilitySupportingAssetCleanup = cleanupVulnerabilitySupportingAssets(jsonData);
const validJSONData = validateJSONschema(jsonData);

const israProject = new ISRAProject();
populateClass(validJSONData, israProject);
israProject.vulnerabilitySupportingAssetCleanup = vulnerabilitySupportingAssetCleanup;
return israProject;
} catch (error) {
console.log(error.message);
Expand All @@ -131,4 +134,4 @@ const DataLoad = (filePath) => {
}
};

module.exports = DataLoad;
module.exports = DataLoad;
42 changes: 42 additions & 0 deletions lib/src/api/xml-json/alter-isra/cleanup-vulnerability-refs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*----------------------------------------------------------------------------
*
* Copyright © 2025 THALES. All Rights Reserved.
*
* -----------------------------------------------------------------------------
*/

const cleanupVulnerabilitySupportingAssets = (israData) => {
const validSupportingAssetIds = new Set(
(israData.SupportingAsset || [])
.map((asset) => Number(asset && asset.supportingAssetId))
.filter((id) => Number.isInteger(id))
);

const cleanup = [];

(israData.Vulnerability || []).forEach((vulnerability) => {
if (!vulnerability || !Array.isArray(vulnerability.supportingAssetRef)) return;

const before = vulnerability.supportingAssetRef.length;

vulnerability.supportingAssetRef = vulnerability.supportingAssetRef
.map((ref) => Number(ref))
.filter((ref) => (
Number.isInteger(ref) &&
validSupportingAssetIds.has(ref)
));

const removed = before - vulnerability.supportingAssetRef.length;

if (removed > 0) {
cleanup.push({
vulnerabilityId: vulnerability.vulnerabilityId,
removed,
});
}
});

return cleanup;
};

module.exports = cleanupVulnerabilitySupportingAssets;
57 changes: 46 additions & 11 deletions lib/src/api/xml-json/alter-isra/sanitizers.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,62 @@ const {

const sanitizeTrackingURI = (uri) => {
if (typeof uri !== "string") return "";

const trimmed = uri.trim();

if (trimmed === "") return "";

return URLpattern.test(trimmed) ? trimmed : "";
};

const isIntegerString = (value) => /^-?\d+$/.test(value);

const pushIntegerRef = (acc, value) => {
if (value === null || value === undefined || value === "") return;

if (typeof value === "number") {
if (Number.isInteger(value)) acc.push(value);
return;
}

if (typeof value === "string") {
value.split(",").forEach((part) => {
const trimmed = part.trim();

if (trimmed === "" || !isIntegerString(trimmed)) return;

const parsed = Number.parseInt(trimmed, 10);

if (Number.isInteger(parsed)) acc.push(parsed);
});
}
};

const sanitizeSupportingAssetRefs = (refs) => {
if (!Array.isArray(refs)) return [];
if (refs === null || refs === undefined || refs === "") return [];

const refArray = Array.isArray(refs) ? refs : [refs];

return refs.reduce((acc, ref) => {
if (ref === null || ref === undefined) return acc;
return refArray.reduce((acc, ref) => {
if (ref === null || ref === undefined || ref === "") return acc;

if (typeof ref === "number" && Number.isInteger(ref)) {
acc.push(ref);
if (typeof ref === "number" || typeof ref === "string") {
pushIntegerRef(acc, ref);
return acc;
}

if (typeof ref === "string") {
const trimmed = ref.trim();
if (trimmed === "" || !/^-?\d+$/.test(trimmed)) return acc;
const parsed = Number.parseInt(trimmed, 10);
if (Number.isInteger(parsed)) acc.push(parsed);
if (typeof ref === "object") {
const candidate =
ref.supportingAssetId ??
ref.supportingAssetRef ??
ref.id ??
ref.value;

if (candidate !== undefined) {
sanitizeSupportingAssetRefs(candidate).forEach((parsedRef) => {
acc.push(parsedRef);
});
}
}

return acc;
Expand All @@ -58,4 +93,4 @@ const sanitizeSupportingAssetRefs = (refs) => {
module.exports = {
sanitizeTrackingURI,
sanitizeSupportingAssetRefs,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,17 @@ describe('DataLoad silently repairs illegal supportingAssetRef', () => {
if (tmpDir) fs.rmSync(tmpDir, { recursive: true, force: true });
});

test('loads without schema error and normalizes refs to integers', () => {
test('loads without schema error and removes invalid supporting asset refs', () => {
const loadedProject = DataLoad(sraPath);
const loadedJson = JSON.parse(loadedProject.toJSON());

expect(Array.isArray(loadedJson.Vulnerability)).toBe(true);
expect(Array.isArray(loadedJson.Vulnerability[0].supportingAssetRef)).toBe(
true
);
expect(loadedJson.Vulnerability[0].supportingAssetRef).toEqual([1, 2]);

// test-7.xml only contains SupportingAsset ID 1.
// ID 2 should be removed by cleanup.
expect(loadedJson.Vulnerability[0].supportingAssetRef).toEqual([1]);
});
});
});
Loading