Skip to content
Merged
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: 10 additions & 0 deletions .config/rollup.dist.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ async function copySocketFactsInitGradle() {
await fs.copyFile(filepath, destPath)
}

async function copySocketFactsSbtPlugin() {
const filepath = path.join(
constants.srcPath,
'commands/manifest/socket-facts.plugin.scala',
)
const destPath = path.join(constants.distPath, 'socket-facts.plugin.scala')
await fs.copyFile(filepath, destPath)
}

async function copyBashCompletion() {
const filepath = path.join(
constants.srcPath,
Expand Down Expand Up @@ -468,6 +477,7 @@ export default async () => {
await Promise.all([
copyInitGradle(),
copySocketFactsInitGradle(),
copySocketFactsSbtPlugin(),
copyBashCompletion(),
updatePackageJson(),
// Remove dist/vendor.js.map file.
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Changed
- **Bazel diagnostics** — `socket manifest bazel --verbose` now emits bounded subprocess traces with argv, cwd, duration, exit status, output sizes, and failure stderr tails to make customer log-only triage safer and faster.

## [1.1.106](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.106) - 2026-05-27

### Added
- **`socket manifest scala --facts [beta]`** — Emit a `.socket.facts.json` dependency graph from an sbt build for `socket scan create` to consume as a pregenerated SBOM. Toggle also exposed via the `socket manifest setup` wizard for use with `--auto-manifest`.

## [1.1.105](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.105) - 2026-05-27

### Changed
Expand All @@ -30,7 +35,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [1.1.98](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.98) - 2026-05-22

### Added
- **`socket manifest gradle --facts [beta]`** (and its `socket manifest kotlin --facts` alias) — Emit a `.socket.facts.json` dependency graph from a Gradle build, consumable by `socket scan create --reach` as pregenerated SBOM input for Tier 1 reachability. Toggle also exposed via the `socket manifest setup` wizard for use with `--auto-manifest`.
- **`socket manifest gradle --facts [beta]`** (and its `socket manifest kotlin --facts` alias) — Emit a `.socket.facts.json` dependency graph from a Gradle build for `socket scan create` to consume as a pregenerated SBOM. Toggle also exposed via the `socket manifest setup` wizard for use with `--auto-manifest`.

### Changed
- Updated the Coana CLI to v `15.3.8`.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "socket",
"version": "1.1.105",
"version": "1.1.106",
"description": "CLI for Socket.dev",
"homepage": "https://github.com/SocketDev/socket-cli",
"license": "MIT AND OFL-1.1",
Expand Down
106 changes: 100 additions & 6 deletions src/commands/manifest/cmd-manifest-scala.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'node:path'
import { debugFn } from '@socketsecurity/registry/lib/debug'
import { logger } from '@socketsecurity/registry/lib/logger'

import { convertSbtToFacts } from './convert-sbt-to-facts.mts'
import { convertSbtToMaven } from './convert_sbt_to_maven.mts'
import constants, { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
import { commonFlags } from '../../flags.mts'
Expand All @@ -28,6 +29,21 @@ const config: CliCommandConfig = {
type: 'string',
description: 'Location of sbt binary to use',
},
facts: {
type: 'boolean',
description:
'Emit a Socket facts JSON file (`.socket.facts.json`) describing the resolved dependency graph instead of generating `pom.xml` files',
},
configs: {
type: 'string',
description:
'With --facts: comma-separated sbt configurations to resolve (default: compile,optional,provided,runtime,test)',
},
ignoreUnresolved: {
type: 'boolean',
description:
'With --facts: skip dependencies that fail to resolve instead of failing the run',
},
out: {
type: 'string',
description:
Expand Down Expand Up @@ -75,6 +91,13 @@ const config: CliCommandConfig = {

You can specify --bin to override the path to the \`sbt\` binary to invoke.

Pass --facts to instead emit a single \`.socket.facts.json\` describing the
resolved dependency graph of the whole build (no \`pom.xml\` files). It reads
dependency metadata only and never downloads artifacts; an unresolved
dependency is a fatal error. With --facts you can pass
--configs=compile,test to choose which sbt configurations to resolve, and
--ignore-unresolved to skip dependencies that fail to resolve.

Support is beta. Please report issues or give us feedback on what's missing.

This is only for SBT. If your Scala setup uses gradle, please see the help
Expand All @@ -83,6 +106,7 @@ const config: CliCommandConfig = {
Examples

$ ${command}
$ ${command} --facts .
$ ${command} ./proj --bin=/usr/bin/sbt --file=boot.sbt
`,
}
Expand Down Expand Up @@ -125,7 +149,8 @@ async function run(
sockJson?.defaults?.manifest?.sbt,
)

let { bin, out, sbtOpts, stdout, verbose } = cli.flags
let { bin, configs, facts, ignoreUnresolved, out, sbtOpts, stdout, verbose } =
cli.flags

// Set defaults for any flag/arg that is not given. Check socket.json first.
if (!bin) {
Expand All @@ -136,6 +161,33 @@ async function run(
bin = 'sbt'
}
}
if (facts === undefined) {
if (sockJson.defaults?.manifest?.sbt?.facts !== undefined) {
facts = sockJson.defaults?.manifest?.sbt?.facts
logger.info(`Using default --facts from ${SOCKET_JSON}:`, facts)
} else {
facts = false
}
}
if (configs === undefined) {
if (sockJson.defaults?.manifest?.sbt?.configs !== undefined) {
configs = sockJson.defaults?.manifest?.sbt?.configs
logger.info(`Using default --configs from ${SOCKET_JSON}:`, configs)
} else {
configs = ''
}
}
if (ignoreUnresolved === undefined) {
if (sockJson.defaults?.manifest?.sbt?.ignoreUnresolved !== undefined) {
ignoreUnresolved = sockJson.defaults?.manifest?.sbt?.ignoreUnresolved
logger.info(
`Using default --ignore-unresolved from ${SOCKET_JSON}:`,
ignoreUnresolved,
)
} else {
ignoreUnresolved = false
}
}
if (
stdout === undefined &&
sockJson.defaults?.manifest?.sbt?.stdout !== undefined
Expand Down Expand Up @@ -171,6 +223,34 @@ async function run(
verbose = false
}

// `--configs` and `--ignore-unresolved` only affect --facts; the pom path
// (`sbt makePom`) has no equivalent knobs. Warn rather than silently ignore
// an explicitly-passed flag. (socket.json defaults don't trip this — only a
// flag actually present on the command line does.)
if (
!facts &&
(cli.flags['configs'] !== undefined ||
cli.flags['ignoreUnresolved'] !== undefined)
) {
logger.warn(
'The `--configs` and `--ignore-unresolved` options only apply with `--facts`; ignoring them.',
)
Comment thread
jfblaa marked this conversation as resolved.
}

// Conversely, --out / --stdout only affect the pom path; with --facts the
// plugin always writes `.socket.facts.json` to the build root (its
// socket.outputDirectory/outputFile JVM props aren't exposed by the CLI), so
// warn rather than let `--facts --out custom.json` silently write nothing
// there.
if (
facts &&
(cli.flags['out'] !== undefined || cli.flags['stdout'] !== undefined)
) {
logger.warn(
'The `--out` and `--stdout` options do not apply with `--facts`; the facts file is always written to the build root.',
)
}

if (verbose) {
logger.group('- ', parentName, config.commandName, ':')
logger.group('- flags:', cli.flags)
Expand Down Expand Up @@ -206,14 +286,28 @@ async function run(
return
}

const parsedSbtOpts = String(sbtOpts || '')
.split(' ')
.map(s => s.trim())
.filter(Boolean)

if (facts) {
await convertSbtToFacts({
bin: String(bin),
configs: String(configs || ''),
cwd,
ignoreUnresolved: Boolean(ignoreUnresolved),
sbtOpts: parsedSbtOpts,
verbose: Boolean(verbose),
})
return
}

await convertSbtToMaven({
bin: String(bin),
cwd: cwd,
cwd,
out: String(out),
sbtOpts: String(sbtOpts)
.split(' ')
.map(s => s.trim())
.filter(Boolean),
sbtOpts: parsedSbtOpts,
verbose: Boolean(verbose),
})
}
29 changes: 29 additions & 0 deletions src/commands/manifest/cmd-manifest-scala.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ describe('socket manifest scala', async () => {

Options
--bin Location of sbt binary to use
--configs With --facts: comma-separated sbt configurations to resolve (default: compile,optional,provided,runtime,test)
--facts Emit a Socket facts JSON file (\`.socket.facts.json\`) describing the resolved dependency graph instead of generating \`pom.xml\` files
--ignore-unresolved With --facts: skip dependencies that fail to resolve instead of failing the run
--out Path of output file; where to store the resulting manifest, see also --stdout
--sbt-opts Additional options to pass on to sbt, as per \`sbt --help\`
--stdout Print resulting pom.xml to stdout (supersedes --out)
Expand Down Expand Up @@ -51,6 +54,13 @@ describe('socket manifest scala', async () => {

You can specify --bin to override the path to the \`sbt\` binary to invoke.

Pass --facts to instead emit a single \`.socket.facts.json\` describing the
resolved dependency graph of the whole build (no \`pom.xml\` files). It reads
dependency metadata only and never downloads artifacts; an unresolved
dependency is a fatal error. With --facts you can pass
--configs=compile,test to choose which sbt configurations to resolve, and
--ignore-unresolved to skip dependencies that fail to resolve.

Support is beta. Please report issues or give us feedback on what's missing.

This is only for SBT. If your Scala setup uses gradle, please see the help
Expand All @@ -59,6 +69,7 @@ describe('socket manifest scala', async () => {
Examples

$ socket manifest scala
$ socket manifest scala --facts .
$ socket manifest scala ./proj --bin=/usr/bin/sbt --file=boot.sbt"
`,
)
Expand Down Expand Up @@ -94,4 +105,22 @@ describe('socket manifest scala', async () => {
expect(code, 'dry-run should exit with code 0 if input ok').toBe(0)
},
)

cmdit(
['manifest', 'scala', '--facts', FLAG_DRY_RUN, FLAG_CONFIG, '{}'],
'should accept --facts with dry-run',
async cmd => {
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd)
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | CLI: <redacted>
|__ | * | _| '_| -_| _| | token: <redacted>, org: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket manifest scala\`, cwd: <redacted>"
`)

expect(code, '--facts --dry-run should exit with code 0').toBe(0)
},
)
})
Loading
Loading