Skip to content
Open
Changes from 1 commit
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
109 changes: 89 additions & 20 deletions scripts/snyk-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,67 @@ const { glob } = require('glob');
const { promisify } = require('util');
const execFile = promisify(childProcess.execFile);

const PACKAGE_LOCK_PATH = path.join(__dirname, '..', 'package-lock.json');

/**
* "node_modules/@vscode/vsce-sign" package which is a dev dependency used for
* publishing extension declares platform specific optionalDependencies, namely
* the following:
* - "@vscode/vsce-sign-alpine-arm64"
* - "@vscode/vsce-sign-alpine-x64"
* - "@vscode/vsce-sign-darwin-arm64"
* - "@vscode/vsce-sign-darwin-x64"
* - "@vscode/vsce-sign-linux-arm"
* - "@vscode/vsce-sign-linux-arm64"
* - "@vscode/vsce-sign-linux-x64"
* - "@vscode/vsce-sign-win32-arm64"
* - "@vscode/vsce-sign-win32-x64"
*
* Snyk requires what is declared in package-lock.json to be also present in
* installed node_modules but this will never happen because for any platform,
* other platform specific deps will always be missing which means Snyk will
* always fail in this case.
*
* Because we always install with `npm ci --omit=optional`, with this method we
* try to remove these identified problematic optionalDependencies before
* running the Snyk tests and once the tests are finished, we restore the
* original state back.
*/
async function removeProblematicOptionalDepsFromPackageLock() {
const TEMP_PACKAGE_LOCK_PATH = path.join(
__dirname,
'..',
'original-package-lock.json',
);

const packageLockContent = JSON.parse(
await fs.readFile(PACKAGE_LOCK_PATH, 'utf-8'),
);

if (
!packageLockContent.packages?.['node_modules/@vscode/vsce-sign']?.[
'optionalDependencies'
]
) {
console.info('No problematic optional dependencies to fix');
return;
}

packageLockContent.packages['node_modules/@vscode/vsce-sign'][
'optionalDependencies'
] = {};

await fs.rename(PACKAGE_LOCK_PATH, TEMP_PACKAGE_LOCK_PATH);
await fs.writeFile(
PACKAGE_LOCK_PATH,
JSON.stringify(packageLockContent, null, 2),
);

return async function restoreOriginalPackageLock() {
return await fs.rename(TEMP_PACKAGE_LOCK_PATH, PACKAGE_LOCK_PATH);
};
}

async function snykTest(cwd) {
const tmpPath = path.join(os.tmpdir(), 'tempfile-' + Date.now());

Expand All @@ -17,9 +78,8 @@ async function snykTest(cwd) {
await execFile(
'npx',
[
'snyk',
'snyk@latest',
'test',
'--all-projects',
'--severity-threshold=low',
'--dev',
`--json-file-output=${tmpPath}`,
Expand All @@ -45,26 +105,35 @@ async function snykTest(cwd) {
}

async function main() {
const rootPath = path.resolve(__dirname, '..');
await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true });
const results = await snykTest(rootPath);
let revertPackageLockChanges;
try {
const rootPath = path.resolve(__dirname, '..');
await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true });
revertPackageLockChanges =
await removeProblematicOptionalDepsFromPackageLock();
const results = await snykTest(rootPath);

await fs.writeFile(
path.join(rootPath, `.sbom/snyk-test-result.json`),
JSON.stringify(results, null, 2),
);
await fs.writeFile(
path.join(rootPath, `.sbom/snyk-test-result.json`),
JSON.stringify(results, null, 2),
);

await execFile(
'npx',
[
'snyk-to-html',
'-i',
path.join(rootPath, '.sbom/snyk-test-result.json'),
'-o',
path.join(rootPath, `.sbom/snyk-test-result.html`),
],
{ cwd: rootPath },
);
await execFile(
'npx',
[
'snyk-to-html',
'-i',
path.join(rootPath, '.sbom/snyk-test-result.json'),
'-o',
path.join(rootPath, `.sbom/snyk-test-result.html`),
],
{ cwd: rootPath },
);
} finally {
if (revertPackageLockChanges) {
await revertPackageLockChanges();
}
}
}

main();
Loading