-
Notifications
You must be signed in to change notification settings - Fork 41
Add socket manifest <lang> including scala as first lang
#311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
923645e
Add `socket sbom` command and `socket sbom scala`
pvdz 5f2fcfa
lint fix/prettier
pvdz 3356fbe
sbom -> manifest
pvdz 6a7a6c1
lint:fix
pvdz 1b1b4e8
Use common readFile/spawn deps
pvdz e89a921
lint
pvdz cabccdf
Merge branch 'main' into add-sbom
pvdz 875eb61
Add a `manifest auto` command which tries to zero config generate a m…
pvdz 3cd83e9
Back out change that landed in main already
pvdz 3a79c58
Merge branch 'main' into add-sbom
pvdz 59f5e43
Pass on flag options to meow proper, fixing boolean flags
pvdz 82ea91b
npm run check:lint -- --fix
pvdz 71a86f4
Merge branch 'main' into add-sbom
jdalton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import meow from 'meow' | ||
|
|
||
| import { scala } from './scala' | ||
| import { meowWithSubcommands } from '../../utils/meow-with-subcommands' | ||
|
|
||
| import type { CliSubcommand } from '../../utils/meow-with-subcommands' | ||
|
|
||
| const description = | ||
| 'Generate a "Software Bill of Materials" for given file or dir' | ||
| const help = (name: string) => ` | ||
| Usage | ||
|
|
||
| $ ${name} <language> <target> | ||
|
|
||
| Generates a declarative dependency manifest (like a package.json for Node.JS | ||
| or requirements.txt for PyPi), but for certain supported ecosystems | ||
| where it's common to use a dynamic manifest, like Scala's sbt. | ||
|
|
||
| Only certain languages are supported and there may be language specific | ||
| configurations available. See \`manifest <language> --help\` for usage details | ||
| per language. | ||
|
|
||
| Currently supported language: scala | ||
|
|
||
| Examples | ||
|
|
||
| $ ${name} scala . | ||
| ` | ||
|
|
||
| export const manifest: CliSubcommand = { | ||
| description, | ||
| async run(argv, importMeta, { parentName }) { | ||
| const name = `${parentName} manifest` | ||
|
|
||
| // Note: this won't catch `socket manifest -xyz --help` sort of cases which | ||
| // would fallback to the default meow help behavior. That's fine. | ||
| if (argv.length === 0 || argv[0] === '--help') { | ||
| meow(help(name), { | ||
| argv: ['--help'] as const, // meow will exit() when --help is passed | ||
| description, | ||
| importMeta | ||
| }) | ||
| } | ||
|
|
||
| await meowWithSubcommands( | ||
| { | ||
| scala | ||
| }, | ||
| { | ||
| argv, | ||
| description, | ||
| importMeta, | ||
| name | ||
| } | ||
| ) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,231 @@ | ||
| import fs from 'node:fs' | ||
| import path from 'node:path' | ||
| import util from 'node:util' | ||
|
|
||
| import spawn from '@npmcli/promise-spawn' | ||
| import meow from 'meow' | ||
|
|
||
| import { Spinner } from '@socketsecurity/registry/lib/spinner' | ||
|
|
||
| import { safeReadFile } from '../../utils/fs' | ||
| import { getFlagListOutput } from '../../utils/output-formatting.ts' | ||
|
|
||
| import type { CliSubcommand } from '../../utils/meow-with-subcommands' | ||
|
|
||
| type ListDescription = | ||
| | string | ||
| | { description: string; type?: string; default?: string } | ||
|
|
||
| const renamep = util.promisify(fs.rename) | ||
|
|
||
| const description = | ||
| 'Generate a "Software Bill of Materials" (`pom.xml`) from Scala\'s `build.sbt` file' | ||
|
|
||
| const scalaCmdFlags: Record<string, ListDescription> = { | ||
| bin: { | ||
| type: 'string', | ||
| default: 'sbt', | ||
| description: 'Location of sbt binary to use' | ||
| }, | ||
| out: { | ||
| type: 'string', | ||
| default: './socket.pom.xml', | ||
| description: | ||
| 'Path of output file; where to store the resulting manifest, see also --stdout' | ||
| }, | ||
| stdout: { | ||
| type: 'boolean', | ||
| description: 'Print resulting pom.xml to stdout (supersedes --out)' | ||
| }, | ||
| sbtOpts: { | ||
| type: 'string', | ||
| default: '', | ||
| description: 'Additional options to pass on to sbt, as per `sbt --help`' | ||
| }, | ||
| verbose: { | ||
| type: 'boolean', | ||
| description: 'Print debug messages' | ||
| } | ||
| } | ||
|
|
||
| const help = (name: string, flags: Record<string, ListDescription>) => ` | ||
| Usage | ||
| $ ${name} [--sbt=path/to/sbt/binary] [--out=path/to/result] FILE|DIR | ||
|
|
||
| Options | ||
| ${getFlagListOutput(flags, 6)} | ||
|
|
||
| Uses \`sbt makePom\` to generate a \`pom.xml\` from your \`build.sbt\` file. | ||
| This xml file is the dependency manifest (like a package.json | ||
| for Node.js or requirements.txt for PyPi), but specifically for Scala. | ||
|
|
||
| There are some caveats with \`build.sbt\` to \`pom.xml\` conversion: | ||
|
|
||
| - the xml is exported as socket.pom.xml as to not confuse existing build tools | ||
| but it will first hit your /target/sbt<version> folder (as a different name) | ||
|
|
||
| - the pom.xml format (standard by Scala) does not support certain sbt features | ||
| - \`excludeAll()\`, \`dependencyOverrides\`, \`force()\`, \`relativePath\` | ||
| - For details: https://www.scala-sbt.org/1.x/docs/Library-Management.html | ||
|
|
||
| - it uses your sbt settings and local configuration verbatim | ||
|
|
||
| - it can only export one target per run, so if you have multiple targets like | ||
| development and production, you must run them separately. | ||
|
|
||
| You can optionally configure the path to the \`sbt\` bin to invoke. | ||
|
|
||
| Examples | ||
|
|
||
| $ ${name} ./build.sbt | ||
| $ ${name} --bin=/usr/bin/sbt ./build.sbt | ||
| ` | ||
|
|
||
| export const scala: CliSubcommand = { | ||
| description, | ||
| async run(argv, importMeta, { parentName }) { | ||
| const name = `${parentName} scala` | ||
| // note: meow will exit if it prints the --help screen | ||
| const cli = meow(help(name, scalaCmdFlags), { | ||
| argv: argv.length === 0 ? ['--help'] : argv, | ||
| description, | ||
| importMeta | ||
| }) | ||
|
|
||
| const target = cli.input[0] | ||
|
|
||
| if (!target) { | ||
| // will exit. | ||
| new Spinner() | ||
| .start('Parsing...') | ||
| .error( | ||
| `Failure: Missing FILE|DIR argument. See \`${name} --help\` for details.` | ||
| ) | ||
| process.exit(1) | ||
| } | ||
|
|
||
| if (cli.input.length > 1) { | ||
| // will exit. | ||
| new Spinner() | ||
| .start('Parsing...') | ||
| .error( | ||
| `Failure: Can only accept one FILE or DIR, received ${cli.input.length} (make sure to escape spaces!). See \`${name} --help\` for details.` | ||
| ) | ||
| process.exit(1) | ||
| } | ||
|
|
||
| let bin: string = 'sbt' | ||
| if (cli.flags['bin']) { | ||
| bin = cli.flags['bin'] as string | ||
| } | ||
|
|
||
| let out: string = './socket.pom.xml' | ||
| if (cli.flags['out']) { | ||
| out = cli.flags['out'] as string | ||
| } | ||
| if (cli.flags['stdout']) { | ||
| out = '-' | ||
| } | ||
|
|
||
| // TODO: we can make `-` (accept from stdin) work by storing it into /tmp | ||
| if (target === '-') { | ||
| new Spinner() | ||
| .start('Parsing...') | ||
| .error( | ||
| `Failure: Currently source code from stdin is not supported. See \`${name} --help\` for details.` | ||
| ) | ||
| process.exit(1) | ||
| } | ||
|
|
||
| const verbose = (cli.flags['verbose'] as boolean) ?? false | ||
|
|
||
| let sbtOpts: Array<string> = [] | ||
| if (cli.flags['sbtOpts']) { | ||
| sbtOpts = (cli.flags['sbtOpts'] as string) | ||
| .split(' ') | ||
| .map(s => s.trim()) | ||
| .filter(Boolean) | ||
| } | ||
|
|
||
| await startConversion(target, bin, out, verbose, sbtOpts) | ||
| } | ||
| } | ||
|
|
||
| async function startConversion( | ||
| target: string, | ||
| bin: string, | ||
| out: string, | ||
| verbose: boolean, | ||
| sbtOpts: Array<string> | ||
| ) { | ||
| const spinner = new Spinner() | ||
|
|
||
| const rbin = path.resolve(bin) | ||
| const rtarget = path.resolve(target) | ||
| const rout = out === '-' ? '-' : path.resolve(out) | ||
|
|
||
| if (verbose) { | ||
| spinner.clear() | ||
| console.log(`- Absolute bin path: \`${rbin}\``) | ||
| console.log(`- Absolute target path: \`${rtarget}\``) | ||
| console.log(`- Absolute out path: \`${rout}\``) | ||
| } | ||
|
|
||
| spinner.start(`Running sbt from \`${bin}\` on \`${target}\`...`) | ||
|
|
||
| try { | ||
| // We must now run sbt, pick the generated xml from the /target folder (the stdout should tell you the location upon success) and store it somewhere else. | ||
| // TODO: Not sure what this somewhere else might be tbh. | ||
|
|
||
| const output = await spawn(bin, ['makePom'].concat(sbtOpts), { | ||
| cwd: target || '.' | ||
| }) | ||
| spinner.success() | ||
| if (verbose) { | ||
| console.group('sbt stdout:') | ||
| console.log(output) | ||
| console.groupEnd() | ||
| } | ||
|
|
||
| if (output.stderr) { | ||
| spinner.error('There were errors while running sbt') | ||
| // (In verbose mode, stderr was printed above, no need to repeat it) | ||
| if (!verbose) console.error(output.stderr) | ||
| process.exit(1) | ||
| } | ||
|
|
||
| const loc = output.stdout?.match(/Wrote (.*?.pom)\n/)?.[1]?.trim() | ||
| if (!loc) { | ||
| spinner.error( | ||
| 'There were no errors from sbt but could not find the location of resulting .pom file either' | ||
| ) | ||
| process.exit(1) | ||
| } | ||
|
|
||
| // Move the pom file to ...? initial cwd? loc will be an absolute path, or dump to stdout | ||
| if (out === '-') { | ||
| spinner.start('Result:\n```').success() | ||
| console.log(await safeReadFile(loc, 'utf8')) | ||
| console.log('```') | ||
| spinner.start().success(`OK`) | ||
| } else { | ||
| if (verbose) { | ||
| spinner.start( | ||
| `Moving manifest file from \`${loc.replace(/^\/home\/[^/]*?\//, '~/')}\` to \`${out}\`` | ||
| ) | ||
| } else { | ||
| spinner.start('Moving output pom file') | ||
| } | ||
| // TODO: do we prefer fs-extra? renaming can be gnarly on windows and fs-extra's version is better | ||
| await renamep(loc, out) | ||
| spinner.success() | ||
| spinner.start().success(`OK. File should be available in \`${out}\``) | ||
| } | ||
| } catch (e) { | ||
| spinner.error('There was an unexpected error while running this') | ||
| if (verbose) { | ||
| console.log(e) | ||
| } | ||
| process.exit(1) | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.