diff --git a/README.md b/README.md index 678581bf..5c3fc49f 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ USAGE FLAGS -c, --csv Output in CSV format -m, --months= [default: 12] The number of months of git history to review - -s, --save Save the committers report as eol.committers. + -s, --save Save the committers report as herodevs.committers. GLOBAL FLAGS --json Format output as json. @@ -117,7 +117,7 @@ FLAGS -c, --csv Save output in CSV format (only applies when using --save) -d, --dir= The directory to scan in order to create a cyclonedx sbom -f, --file= The file path of an existing cyclonedx sbom to scan for EOL - -s, --save Save the list of purls as eol.purls. + -s, --save Save the list of purls as herodevs.purls. GLOBAL FLAGS --json Format output as json. @@ -152,7 +152,7 @@ FLAGS -d, --dir= The directory to scan in order to create a cyclonedx sbom -f, --file= The file path of an existing cyclonedx sbom to scan for EOL -p, --purls= The file path of a list of purls to scan for EOL - -s, --save Save the generated report as eol.report.json in the scanned directory + -s, --save Save the generated report as herodevs.report.json in the scanned directory GLOBAL FLAGS --json Format output as json. @@ -184,7 +184,7 @@ FLAGS -b, --background Run the scan in the background -d, --dir= The directory to scan in order to create a cyclonedx sbom -f, --file= The file path of an existing cyclonedx sbom to scan for EOL - -s, --save Save the generated SBOM as eol.sbom.json in the scanned directory + -s, --save Save the generated SBOM as herodevs.sbom.json in the scanned directory GLOBAL FLAGS --json Format output as json. diff --git a/e2e/fixtures/npm/eol.sbom.json b/e2e/fixtures/npm/herodevs.sbom.json similarity index 100% rename from e2e/fixtures/npm/eol.sbom.json rename to e2e/fixtures/npm/herodevs.sbom.json diff --git a/e2e/scan/eol.test.ts b/e2e/scan/eol.test.ts index 8fc9f3c1..642ba2e4 100644 --- a/e2e/scan/eol.test.ts +++ b/e2e/scan/eol.test.ts @@ -8,7 +8,7 @@ import { describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; import { runCommand } from '@oclif/test'; -import { config } from '../../src/config/constants'; +import { config, filenamePrefix } from '../../src/config/constants'; const execAsync = promisify(exec); @@ -62,8 +62,8 @@ describe('scan:eol e2e', () => { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const fixturesDir = path.resolve(__dirname, '../fixtures'); const simplePurls = path.resolve(__dirname, '../fixtures/npm/simple.purls.json'); - const simpleSbom = path.join(fixturesDir, 'npm/eol.sbom.json'); - const reportPath = path.resolve(fixturesDir, 'eol.report.json'); + const simpleSbom = path.join(fixturesDir, `npm/${filenamePrefix}.sbom.json`); + const reportPath = path.resolve(fixturesDir, `${filenamePrefix}.report.json`); const upToDatePurls = path.resolve(__dirname, '../fixtures/npm/up-to-date.purls.json'); const emptyPurlsPath = path.resolve(__dirname, '../fixtures/npm/empty.purls.json'); @@ -213,7 +213,7 @@ describe('with directory flag', () => { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const simpleDir = path.resolve(__dirname, '../fixtures/npm/simple'); const upToDateDir = path.resolve(__dirname, '../fixtures/npm/up-to-date'); - const reportPath = path.join(simpleDir, 'eol.report.json'); + const reportPath = path.join(simpleDir, `${filenamePrefix}.report.json`); async function run(cmd: string) { // Ensure test directory exists and is clean diff --git a/package.json b/package.json index 7b7f5719..452823dc 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "ci": "biome ci", "ci:fix": "biome check --write", "clean": "shx rm -rf dist && npm run clean:files && shx rm -rf node_modules", - "clean:files": "shx rm -f eol.**.csv eol.**.json eol.**.text", + "clean:files": "shx rm -f herodevs.**.csv herodevs.**.json herodevs.**.txt", "dev": "npm run build && ./bin/dev.js", "dev:debug": "npm run build && DEBUG=oclif:* ./bin/dev.js", "format": "biome format --write", diff --git a/src/commands/report/committers.ts b/src/commands/report/committers.ts index 616c5688..b442ea68 100644 --- a/src/commands/report/committers.ts +++ b/src/commands/report/committers.ts @@ -3,6 +3,7 @@ import { Command, Flags } from '@oclif/core'; import fs from 'node:fs'; import path from 'node:path'; +import { filenamePrefix } from '../../config/constants.ts'; import { type CommitEntry, type ReportData, @@ -37,7 +38,7 @@ export default class Committers extends Command { }), save: Flags.boolean({ char: 's', - description: 'Save the committers report as eol.committers.', + description: `Save the committers report as ${filenamePrefix}.committers.`, default: false, }), }; @@ -61,7 +62,7 @@ export default class Committers extends Command { // JSON mode if (save) { try { - fs.writeFileSync(path.resolve('eol.committers.json'), JSON.stringify(reportData, null, 2)); + fs.writeFileSync(path.resolve(`${filenamePrefix}.committers.json`), JSON.stringify(reportData, null, 2)); this.log('Report written to json'); } catch (error) { this.error(`Failed to save JSON report: ${getErrorMessage(error)}`); @@ -77,7 +78,7 @@ export default class Committers extends Command { const csvOutput = formatAsCsv(reportData); if (save) { try { - fs.writeFileSync(path.resolve('eol.committers.csv'), csvOutput); + fs.writeFileSync(path.resolve(`${filenamePrefix}.committers.csv`), csvOutput); this.log('Report written to csv'); } catch (error) { this.error(`Failed to save CSV report: ${getErrorMessage(error)}`); @@ -90,7 +91,7 @@ export default class Committers extends Command { if (save) { try { - fs.writeFileSync(path.resolve('eol.committers.txt'), textOutput); + fs.writeFileSync(path.resolve(`${filenamePrefix}.committers.txt`), textOutput); this.log('Report written to txt'); } catch (error) { this.error(`Failed to save txt report: ${getErrorMessage(error)}`); diff --git a/src/commands/report/purls.ts b/src/commands/report/purls.ts index 591dfcda..cebe7e99 100644 --- a/src/commands/report/purls.ts +++ b/src/commands/report/purls.ts @@ -2,6 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { Command, Flags, ux } from '@oclif/core'; +import { filenamePrefix } from '../../config/constants.ts'; import { getErrorMessage, isErrnoException } from '../../service/error.svc.ts'; import { extractPurls, getPurlOutput } from '../../service/purls.svc.ts'; import ScanSbom from '../scan/sbom.ts'; @@ -28,7 +29,7 @@ export default class ReportPurls extends Command { save: Flags.boolean({ char: 's', default: false, - description: 'Save the list of purls as eol.purls.', + description: `Save the list of purls as ${filenamePrefix}.purls.`, }), csv: Flags.boolean({ char: 'c', @@ -57,7 +58,7 @@ export default class ReportPurls extends Command { if (save) { try { const outputFile = csv && !this.jsonEnabled() ? 'csv' : 'json'; - const outputPath = path.join(_dirFlag || process.cwd(), `eol.purls.${outputFile}`); + const outputPath = path.join(_dirFlag || process.cwd(), `${filenamePrefix}.purls.${outputFile}`); const purlOutput = getPurlOutput(purls, outputFile); fs.writeFileSync(outputPath, purlOutput); diff --git a/src/commands/scan/eol.ts b/src/commands/scan/eol.ts index 84627d82..6b548b6a 100644 --- a/src/commands/scan/eol.ts +++ b/src/commands/scan/eol.ts @@ -5,7 +5,7 @@ import terminalLink from 'terminal-link'; import { batchSubmitPurls } from '../../api/nes/nes.client.ts'; import type { ScanResult } from '../../api/types/hd-cli.types.js'; import type { ComponentStatus, InsightsEolScanComponent } from '../../api/types/nes.types.ts'; -import { config } from '../../config/constants.ts'; +import { config, filenamePrefix } from '../../config/constants.ts'; import type { Sbom } from '../../service/eol/cdx.svc.ts'; import { getErrorMessage, isErrnoException } from '../../service/error.svc.ts'; import { extractPurls, parsePurlsFile } from '../../service/purls.svc.ts'; @@ -37,7 +37,7 @@ export default class ScanEol extends Command { save: Flags.boolean({ char: 's', default: false, - description: 'Save the generated report as eol.report.json in the scanned directory', + description: `Save the generated report as ${filenamePrefix}.report.json in the scanned directory`, }), }; @@ -61,7 +61,7 @@ export default class ScanEol extends Command { } this.log('* Use --json to output the report payload'); - this.log('* Use --save to save the report to eol.report.json'); + this.log(`* Use --save to save the report to ${filenamePrefix}.report.json`); this.log('* Use --help for more commands or options'); } @@ -116,19 +116,19 @@ export default class ScanEol extends Command { private async saveReport(components: InsightsEolScanComponent[], createdOn?: string): Promise { const { flags } = await this.parse(ScanEol); - const reportPath = path.join(flags.dir || process.cwd(), 'eol.report.json'); + const reportPath = path.join(flags.dir || process.cwd(), `${filenamePrefix}.report.json`); try { fs.writeFileSync(reportPath, JSON.stringify({ components, createdOn }, null, 2)); - this.log('Report saved to eol.report.json'); + this.log(`Report saved to ${filenamePrefix}.report.json`); } catch (error) { if (!isErrnoException(error)) { this.error(`Failed to save report: ${getErrorMessage(error)}`); } if (error.code === 'EACCES') { - this.error('Permission denied. Unable to save report to eol.report.json'); + this.error(`Permission denied. Unable to save report to ${filenamePrefix}.report.json`); } else if (error.code === 'ENOSPC') { - this.error('No space left on device. Unable to save report to eol.report.json'); + this.error(`No space left on device. Unable to save report to ${filenamePrefix}.report.json`); } else { this.error(`Failed to save report: ${getErrorMessage(error)}`); } diff --git a/src/commands/scan/sbom.ts b/src/commands/scan/sbom.ts index c6a45d69..b11d4a9e 100644 --- a/src/commands/scan/sbom.ts +++ b/src/commands/scan/sbom.ts @@ -2,6 +2,7 @@ import { spawn } from 'node:child_process'; import fs from 'node:fs'; import { join, resolve } from 'node:path'; import { Command, Flags, ux } from '@oclif/core'; +import { filenamePrefix } from '../../config/constants.ts'; import type { Sbom } from '../../service/eol/cdx.svc.ts'; import { createSbom, validateIsCycloneDxSbom } from '../../service/eol/eol.svc.ts'; import { getErrorMessage } from '../../service/error.svc.ts'; @@ -25,7 +26,7 @@ export default class ScanSbom extends Command { save: Flags.boolean({ char: 's', default: false, - description: 'Save the generated SBOM as eol.sbom.json in the scanned directory', + description: `Save the generated SBOM as ${filenamePrefix}.sbom.json in the scanned directory`, }), background: Flags.boolean({ char: 'b', @@ -45,14 +46,13 @@ export default class ScanSbom extends Command { } static getSbomArgs(flags: Record): string[] { - const { dir, file, save, json, background } = flags ?? {}; + const { dir, file, background } = flags ?? {}; - const sbomArgs = []; + const sbomArgs = ['--json']; if (file) sbomArgs.push('--file', file); if (dir) sbomArgs.push('--dir', dir); // if (save) sbomArgs.push('--save'); // only save if sbom command is used directly with -s flag - if (json) sbomArgs.push('--json'); if (background) sbomArgs.push('--background'); return sbomArgs; @@ -75,17 +75,24 @@ export default class ScanSbom extends Command { const path = dir || process.cwd(); if (file) { sbom = this._getSbomFromFile(file); + ux.action.stop(); } else if (background) { this._getSbomInBackground(path); - this.log(`The scan is running in the background. The file will be saved at ${path}/eol.sbom.json`); + this.log(`The scan is running in the background. The file will be saved at ${path}/${filenamePrefix}.sbom.json`); + ux.action.stop(); return; } else { sbom = await this._getSbomFromScan(path); + ux.action.stop(); if (save) { this._saveSbom(path, sbom); } } + if (!save) { + this.log(JSON.stringify(sbom, null, 2)); + } + return sbom; } @@ -158,7 +165,7 @@ export default class ScanSbom extends Command { private _saveSbom(dir: string, sbom: Sbom) { try { - const outputPath = join(dir, 'eol.sbom.json'); + const outputPath = join(dir, `${filenamePrefix}.sbom.json`); fs.writeFileSync(outputPath, JSON.stringify(sbom, null, 2)); if (!this.jsonEnabled()) { this.log(`SBOM saved to ${outputPath}`); diff --git a/src/config/constants.ts b/src/config/constants.ts index 879b87c2..39afac77 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -8,3 +8,5 @@ export const config = { graphqlPath: process.env.GRAPHQL_PATH || GRAPHQL_PATH, showVulnCount: true, }; + +export const filenamePrefix = 'herodevs'; diff --git a/src/service/eol/sbom.worker.ts b/src/service/eol/sbom.worker.ts index f7a3f915..358d8473 100644 --- a/src/service/eol/sbom.worker.ts +++ b/src/service/eol/sbom.worker.ts @@ -1,6 +1,7 @@ import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { createBom } from '@cyclonedx/cdxgen'; +import { filenamePrefix } from '../../config/constants.ts'; import { SBOM_DEFAULT__OPTIONS } from './cdx.svc.ts'; process.on('uncaughtException', (err) => { @@ -18,7 +19,7 @@ try { const options = JSON.parse(process.argv[2]); const { path, opts } = options; const { bomJson } = await createBom(path, { ...SBOM_DEFAULT__OPTIONS, ...opts }); - const outputPath = join(path, 'eol.sbom.json'); + const outputPath = join(path, `${filenamePrefix}.sbom.json`); writeFileSync(outputPath, JSON.stringify(bomJson, null, 2)); process.exit(0); } catch (error: unknown) { diff --git a/src/service/purls.svc.ts b/src/service/purls.svc.ts index 3b1fc41a..644437df 100644 --- a/src/service/purls.svc.ts +++ b/src/service/purls.svc.ts @@ -73,7 +73,7 @@ export function extractPurls(sbom: Sbom): string[] { /** * Parse a purls file in either JSON or text format, including the format of - * eol.purls.json - { purls: [ 'pkg:npm/express@4.18.2', 'pkg:npm/react@18.3.1' ] } + * herodevs.purls.json - { purls: [ 'pkg:npm/express@4.18.2', 'pkg:npm/react@18.3.1' ] } * or a text file with one purl per line. */ export function parsePurlsFile(purlsFileString: string): string[] { diff --git a/test/service/purls.svc.test.ts b/test/service/purls.svc.test.ts index 8826f0c8..35accce6 100644 --- a/test/service/purls.svc.test.ts +++ b/test/service/purls.svc.test.ts @@ -53,7 +53,7 @@ describe('formatCsvValue', () => { describe('parsePurlsFile', () => { describe('JSON format', () => { - it('should parse eol.purls.json format', () => { + it('should parse herodevs.purls.json format', () => { const input = JSON.stringify({ purls: ['pkg:npm/@apollo/client@3.13.5', 'pkg:npm/react@18.2.0'], }); diff --git a/test/service/sbom.background.test.ts b/test/service/sbom.background.test.ts index bc8302d5..52403713 100644 --- a/test/service/sbom.background.test.ts +++ b/test/service/sbom.background.test.ts @@ -25,5 +25,7 @@ test('ScanSbom - Run scan in the background', async () => { ok(parseStub.calledOnce); - ok(logSpy.calledWith('The scan is running in the background. The file will be saved at ./some-dir/eol.sbom.json')); + ok( + logSpy.calledWith('The scan is running in the background. The file will be saved at ./some-dir/herodevs.sbom.json'), + ); });