From cc04f94f0973a61ac9e23f49ad389f6c9372a6b7 Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 9 Nov 2026 11:17:53 -0500 Subject: [PATCH] feat: build Socket 2.1 prerelease as Node 27 SEA --- .config/rollup.base.config.mjs | 27 +- .config/rollup.cdxgen-sea.config.mjs | 530 +++ .config/rollup.dist.config.mjs | 119 +- .config/rollup.sea.config.mjs | 31 +- .config/rollup.synp-sea.config.mjs | 222 ++ .github/workflows/bazel-windows.yml | 10 +- .gitignore | 1387 +++++++- .npmrc | 2 + README.md | 1 + bin/cli.js | 4 +- docs/plans/node27-sea-vfs-socket-package.md | 534 ++++ eslint.config.js | 10 +- package.json | 26 +- .../@socketsecurity__registry@1.1.17.patch | 12 - patches/tiny-updater@3.5.3.patch | 8 +- pnpm-lock.yaml | 754 +++-- scripts/build-package-matrix.mts | 401 +++ scripts/ci/check-actions.mts | 13 + scripts/ci/setup-node.mjs | 1 - scripts/constants.js | 215 +- scripts/sea/release/apple/capture.mts | 153 + scripts/test/integration.mts | 158 + scripts/test/native.mts | 275 ++ scripts/utils/packages.js | 6 +- scripts/utils/registry-helpers.js | 261 ++ src/cli.mts | 4 +- src/commands/analytics/cmd-analytics.mts | 2 +- src/commands/analytics/output-analytics.mts | 2 +- src/commands/audit-log/cmd-audit-log.mts | 2 +- src/commands/audit-log/output-audit-log.mts | 5 +- src/commands/ci/cmd-ci.mts | 2 +- src/commands/ci/fetch-default-org-slug.mts | 2 +- src/commands/ci/handle-ci.mts | 6 +- ...{cli.test.mts => cli.integration.test.mts} | 0 src/commands/config/cmd-config-auto.mts | 2 +- src/commands/config/cmd-config-get.mts | 2 +- src/commands/config/cmd-config-list.mts | 2 +- src/commands/config/cmd-config-set.mts | 2 +- src/commands/config/cmd-config-unset.mts | 2 +- src/commands/config/handle-config-set.mts | 2 +- src/commands/config/output-config-auto.mts | 5 +- src/commands/config/output-config-get.mts | 2 +- src/commands/config/output-config-list.mts | 3 +- src/commands/config/output-config-set.mts | 3 +- src/commands/config/output-config-unset.mts | 3 +- .../fix/branch-cleanup.integration.test.mts | 2 +- src/commands/fix/branch-cleanup.mts | 6 +- src/commands/fix/branch-cleanup.test.mts | 4 +- src/commands/fix/cmd-fix.e2e.test.mts | 2 +- src/commands/fix/cmd-fix.mts | 9 +- .../coana-fix-dynamic-sbom-inference.test.mts | 4 +- src/commands/fix/coana-fix.mts | 13 +- src/commands/fix/env-helpers.mts | 8 +- src/commands/fix/git.mts | 4 +- src/commands/fix/handle-fix-id.test.mts | 2 +- src/commands/fix/handle-fix-limit.test.mts | 4 +- src/commands/fix/handle-fix.mts | 6 +- src/commands/fix/output-fix-result.mts | 3 +- src/commands/fix/pull-request.mts | 6 +- src/commands/fix/types.mts | 2 +- .../install/cmd-install-completion.mts | 2 +- .../install/output-install-completion.mts | 4 +- src/commands/install/setup-tab-completion.mts | 2 +- ...test.mts => cmd-json.integration.test.mts} | 0 src/commands/json/output-cmd-json.mts | 8 +- src/commands/login/attempt-login.mts | 8 +- src/commands/login/cmd-login.mts | 3 +- src/commands/logout/attempt-logout.mts | 2 +- src/commands/logout/cmd-logout.mts | 2 +- .../manifest/bazel/bazel-bin-detect.mts | 42 +- src/commands/manifest/bazel/bazel-cleanup.mts | 2 +- .../manifest/bazel/bazel-cquery.test.mts | 6 +- .../manifest/bazel/bazel-native.e2e.test.mts | 2 +- src/commands/manifest/bazel/bazel-process.mts | 12 +- .../manifest/bazel/bazel-process.test.mts | 19 +- .../manifest/bazel/bazel-pypi-discovery.mts | 4 +- .../bazel/bazel-pypi-discovery.test.mts | 4 +- .../manifest/bazel/bazel-python-shim.mts | 67 +- .../manifest/bazel/bazel-python-shim.test.mts | 31 +- .../manifest/bazel/bazel-query-runner.mts | 2 +- .../manifest/bazel/bazel-repo-discovery.mts | 2 +- .../bazel/bazel-repo-discovery.test.mts | 4 +- .../manifest/bazel/bazel-workspace-walk.mts | 2 +- .../bazel/bazel-workspace-walk.test.mts | 4 +- .../manifest/bazel/cmd-manifest-bazel.mts | 4 +- .../bazel/cmd-manifest-bazel.test.mts | 2 +- .../manifest/bazel/extract_bazel_to_maven.mts | 2 +- .../bazel/extract_bazel_to_maven.test.mts | 4 +- .../manifest/bazel/extract_bazel_to_pypi.mts | 2 +- ...=> cmd-manifest-auto.integration.test.mts} | 0 src/commands/manifest/cmd-manifest-auto.mts | 4 +- src/commands/manifest/cmd-manifest-cdxgen.mts | 57 +- .../manifest/cmd-manifest-cdxgen.test.mts | 6 +- src/commands/manifest/cmd-manifest-conda.mts | 2 +- src/commands/manifest/cmd-manifest-dotnet.mts | 6 +- .../cmd-manifest-dynamic-sbom-inference.mts | 2 +- src/commands/manifest/cmd-manifest-gradle.mts | 4 +- src/commands/manifest/cmd-manifest-kotlin.mts | 4 +- src/commands/manifest/cmd-manifest-maven.mts | 4 +- src/commands/manifest/cmd-manifest-scala.mts | 4 +- src/commands/manifest/cmd-manifest-setup.mts | 2 +- .../convert-conda-to-requirements.mts | 4 +- .../manifest/convert-dotnet-to-facts.mts | 2 +- .../manifest/convert_gradle_to_maven.mts | 24 +- .../manifest/convert_sbt_to_maven.mts | 27 +- .../manifest/detect-manifest-actions.mts | 2 +- .../manifest/discover-manifest-roots.mts | 2 +- .../manifest/enumerate-workspaces.mts | 2 +- .../manifest/generate-recursive-manifests.mts | 2 +- .../generate-recursive-manifests.test.mts | 2 +- .../manifest/generate_auto_manifest.mts | 2 +- .../manifest/generate_auto_manifest.test.mts | 2 +- ...output-manifest-dynamic-sbom-inference.mts | 2 +- .../manifest/output-manifest-setup.mts | 4 +- src/commands/manifest/output-requirements.mts | 2 +- src/commands/manifest/run-cdxgen.mts | 291 +- src/commands/manifest/run-manifest-facts.mts | 2 +- src/commands/manifest/scripts/build-tool.mts | 59 +- .../scripts/dotnet-tool/build-tool.sh | 4 +- src/commands/manifest/scripts/run.mts | 24 +- src/commands/manifest/scripts/run.test.mts | 6 +- .../manifest/setup-manifest-config.mts | 7 +- .../manifest/setup-manifest-config.test.mts | 6 +- .../setup-recursive-manifest-config.mts | 4 +- .../setup-recursive-manifest-config.test.mts | 6 +- src/commands/native-cli.native.test.mts | 56 + src/commands/npm/cmd-npm.mts | 2 +- .../npm/socket-npm-integration.test.mts | 10 +- src/commands/npx/cmd-npx.mts | 2 +- src/commands/oops/cmd-oops.mts | 2 +- src/commands/optimize/add-overrides.mts | 69 +- src/commands/optimize/apply-optimization.mts | 2 +- .../cmd-optimize-pnpm-versions.test.mts | 9 +- src/commands/optimize/cmd-optimize.mts | 2 +- src/commands/optimize/cmd-optimize.test.mts | 8 +- .../optimize/get-overrides-by-agent.mts | 2 +- src/commands/optimize/handle-optimize.mts | 4 +- .../optimize/lockfile-includes-by-agent.mts | 4 +- src/commands/optimize/ls-by-agent.mts | 4 +- .../optimize/output-optimize-result.mts | 6 +- src/commands/optimize/update-lockfile.mts | 6 +- .../optimize/update-manifest-by-agent.mts | 6 +- .../update-manifest-by-agent.test.mts | 2 +- .../cmd-organization-dependencies.mts | 2 +- .../organization/cmd-organization-list.mts | 2 +- .../cmd-organization-policy-license.mts | 2 +- .../cmd-organization-policy-security.mts | 2 +- .../organization/cmd-organization-quota.mts | 2 +- .../organization/fetch-organization-list.mts | 3 +- .../organization/handle-dependencies.mts | 2 +- .../organization/handle-organization-list.mts | 2 +- .../organization/output-dependencies.mts | 3 +- .../organization/output-license-policy.mts | 3 +- .../organization/output-organization-list.mts | 3 +- src/commands/organization/output-quota.mts | 3 +- .../organization/output-security-policy.mts | 3 +- src/commands/package/cmd-package-score.mts | 2 +- src/commands/package/cmd-package-shallow.mts | 2 +- .../package/fetch-purl-deep-score.mts | 4 +- .../package/fetch-purls-shallow-score.mts | 5 +- .../package/handle-purl-deep-score.mts | 2 +- .../package/handle-purls-shallow-score.mts | 2 +- .../package/output-purls-deep-score.mts | 3 +- .../package/output-purls-shallow-score.mts | 7 +- src/commands/patch/cmd-patch.mts | 104 +- src/commands/pnpm/cmd-pnpm.mts | 2 +- src/commands/pnpm/cmd-pnpm.test.mts | 4 +- src/commands/raw-npm/cmd-raw-npm.mts | 2 +- src/commands/raw-npm/run-raw-npm.mts | 2 +- src/commands/raw-npx/cmd-raw-npx.mts | 2 +- src/commands/raw-npx/run-raw-npx.mts | 2 +- .../repository/cmd-repository-create.mts | 2 +- .../repository/cmd-repository-del.mts | 2 +- .../repository/cmd-repository-list.mts | 2 +- .../repository/cmd-repository-update.mts | 2 +- .../repository/cmd-repository-view.mts | 2 +- .../repository/handle-create-repo.mts | 2 +- .../repository/output-create-repo.mts | 3 +- .../repository/output-delete-repo.mts | 3 +- src/commands/repository/output-list-repos.mts | 3 +- .../repository/output-update-repo.mts | 3 +- src/commands/repository/output-view-repo.mts | 3 +- src/commands/scan/cmd-scan-create.mts | 4 +- src/commands/scan/cmd-scan-create.test.mts | 2 +- src/commands/scan/cmd-scan-del.mts | 2 +- src/commands/scan/cmd-scan-diff.mts | 2 +- src/commands/scan/cmd-scan-github.mts | 2 +- src/commands/scan/cmd-scan-list.mts | 2 +- src/commands/scan/cmd-scan-metadata.mts | 2 +- src/commands/scan/cmd-scan-reach.e2e.test.mts | 2 +- src/commands/scan/cmd-scan-reach.mts | 2 +- src/commands/scan/cmd-scan-report.mts | 2 +- src/commands/scan/cmd-scan-setup.mts | 2 +- src/commands/scan/cmd-scan-view.mts | 2 +- src/commands/scan/create-scan-from-github.mts | 7 +- .../scan/fetch-create-org-full-scan.mts | 2 +- src/commands/scan/fetch-diff-scan.mts | 4 +- src/commands/scan/fetch-report-data.mts | 4 +- src/commands/scan/fetch-scan.mts | 4 +- .../scan/fetch-supported-scan-file-names.mts | 2 +- src/commands/scan/generate-report.mts | 2 +- .../scan/generate-uv-member-sboms.mts | 66 +- .../scan/generate-uv-member-sboms.test.mts | 76 +- src/commands/scan/handle-create-new-scan.mts | 8 +- .../scan/handle-create-new-scan.test.mts | 2 +- src/commands/scan/handle-scan-reach.mts | 4 +- src/commands/scan/handle-scan-reach.test.mts | 2 +- src/commands/scan/output-create-new-scan.mts | 7 +- .../scan/output-create-new-scan.test.mts | 4 +- src/commands/scan/output-delete-scan.mts | 3 +- src/commands/scan/output-diff-scan.mts | 2 +- src/commands/scan/output-list-scans.mts | 3 +- .../scan/output-scan-config-result.mts | 4 +- src/commands/scan/output-scan-github.mts | 3 +- src/commands/scan/output-scan-metadata.mts | 3 +- src/commands/scan/output-scan-reach.mts | 4 +- src/commands/scan/output-scan-reach.test.mts | 4 +- src/commands/scan/output-scan-report.mts | 4 +- src/commands/scan/output-scan-view.mts | 2 +- .../scan/perform-reachability-analysis.mts | 4 +- .../perform-reachability-analysis.test.mts | 2 +- src/commands/scan/reach-advisories.mts | 3 +- src/commands/scan/reachability-flags.mts | 3 +- .../scan/run-dynamic-sbom-inference.mts | 5 +- .../scan/run-dynamic-sbom-inference.test.mts | 2 +- src/commands/scan/setup-scan-config.mts | 5 +- src/commands/scan/stream-scan.mts | 3 +- src/commands/scan/suggest-org-slug.mts | 5 +- .../scan/suggest-to-persist-orgslug.mts | 6 +- src/commands/scan/suggest_branch_slug.mts | 6 +- src/commands/scan/suggest_target.mts | 2 +- .../scan/warn-socket-json-only-flags.mts | 3 +- src/commands/threat-feed/cmd-threat-feed.mts | 4 +- .../threat-feed/output-threat-feed.mts | 2 +- .../uninstall/cmd-uninstall-completion.mts | 2 +- .../uninstall/output-uninstall-completion.mts | 4 +- src/commands/wrapper/add-socket-wrapper.mts | 2 +- .../wrapper/check-socket-wrapper-setup.mts | 2 +- src/commands/wrapper/cmd-wrapper.mts | 2 +- src/commands/wrapper/postinstall-wrapper.mts | 6 +- .../wrapper/remove-socket-wrapper.mts | 2 +- src/commands/yarn/cmd-yarn.mts | 2 +- src/constants.mts | 108 +- src/instrument-with-sentry.mts | 4 +- src/registry-constants.mts | 433 +++ src/sea/README.md | 78 +- src/sea/adapters/cdxgen-worker.mjs | 519 +++ src/sea/adapters/cdxgen.mts | 95 + src/sea/adapters/synp-worker.mjs | 191 ++ src/sea/adapters/synp.mts | 166 + src/sea/archive-paths.mts | 19 + src/sea/bootstrap.mts | 205 +- src/sea/build-lock.mts | 165 + src/sea/build-sea.mts | 1720 +++++++--- src/sea/build-sea.test.mts | 234 ++ src/sea/capabilities.mts | 95 + .../cdxgen-third-party/boolbase-1.0.0-ISC.txt | 13 + .../cdxgen-third-party/err-code-2.0.3-MIT.txt | 18 + .../err-code-2.0.3-README.md | 70 + .../imurmurhash-0.1.4-MIT.txt | 20 + .../spdx-exceptions-2.5.0-CC-BY-3.0.txt | 319 ++ .../spdx-exceptions-2.5.0-README.md | 36 + .../spdx-license-ids-3.0.22-CC0-1.0.txt | 121 + .../spdx-license-ids-3.0.22-README.md | 51 + .../@npmcli-agent-3.0.0-README.md | 40 + .../@npmcli-agent-4.0.0-README.md | 40 + .../core-third-party/ansi-term-0.0.2-ISC.txt | 7 + ...wille-canvas-blessed-contrib-0.1.3-MIT.txt | 18 + ...lle-canvas-blessed-contrib-0.1.3-README.md | 81 + .../npmcli-agent-3.0.0-ISC.txt | 7 + .../npmcli-agent-4.0.0-ISC.txt | 7 + .../sigstore-verify-3.1.1-Apache-2.0.txt | 202 ++ .../sigstore-verify-3.1.1-README.md | 9 + .../core-third-party/x256-0.0.2-MIT.txt | 18 + .../x256-0.0.2-readme.markdown | 83 + src/sea/licenses/socket-patch-MIT.txt | 21 + src/sea/rollup-provenance.mjs | 811 +++++ src/sea/runtime.mts | 465 +++ src/sea/runtime.test.mts | 97 + src/sea/stage-synp.mts | 161 + src/sea/stage-uv.mts | 559 ++++ src/sea/uv-pins.json | 56 + src/shadow/common.mts | 13 +- src/shadow/npm-base.mts | 25 +- src/shadow/npm/arborist-helpers.mts | 8 +- .../npm/arborist/lib/arborist/index.mts | 2 +- src/shadow/npm/bin.mts | 2 +- src/shadow/npm/bin.test.mts | 47 +- src/shadow/npm/install.mts | 18 +- src/shadow/npm/paths.mts | 2 +- src/shadow/npx/bin.mts | 2 +- src/shadow/npx/bin.test.mts | 47 +- src/shadow/pnpm/bin.mts | 10 +- src/shadow/pnpm/bin.test.mts | 48 +- src/shadow/yarn/bin.mts | 8 +- src/shadow/yarn/bin.test.mts | 50 +- src/utils/advisory-ids.mts | 5 +- src/utils/agent.mts | 116 +- src/utils/alert/artifact.mts | 2 +- src/utils/alert/severity.mts | 3 +- src/utils/alerts-map.mts | 13 +- src/utils/api.mts | 24 +- src/utils/api.test.mts | 2 + src/utils/arrays.mts | 30 + src/utils/bin.mts | 142 + src/utils/check-input.mts | 6 +- src/utils/coana-release.mts | 38 +- src/utils/coana-release.test.mts | 3 +- src/utils/coana.mts | 5 +- src/utils/config.mts | 18 +- src/utils/debug.mts | 270 +- src/utils/determine-org-slug.mts | 3 +- src/utils/dlx-binary.mts | 12 +- src/utils/dlx-detection.mts | 3 +- src/utils/dlx.mts | 15 +- src/utils/ecosystem.mts | 14 +- src/utils/env.mts | 59 + src/utils/errors.mts | 3 +- src/utils/escape-regexp.mts | 10 + src/utils/filter-config.mts | 2 +- src/utils/fs.mts | 194 +- src/utils/git.mts | 14 +- src/utils/git.test.mts | 4 +- src/utils/github-errors.mts | 9 +- src/utils/github.mts | 20 +- src/utils/glob-content-dedup.test.mts | 4 +- src/utils/glob.mts | 52 +- src/utils/glob.test.mts | 20 +- src/utils/globs.mts | 31 + src/utils/is-object-object.d.mts | 1 + src/utils/is-object-object.mjs | 4 + src/utils/lockfile.mts | 2 +- src/utils/logger.mts | 238 ++ src/utils/meow-with-subcommands.mts | 23 +- src/utils/npm-paths.mts | 5 +- src/utils/npm-paths.test.mts | 57 +- src/utils/objects.mts | 76 + src/utils/output-formatting.mts | 13 +- src/utils/package-environment.mts | 30 +- src/utils/packages.mts | 209 ++ src/utils/packages.test.mts | 33 + src/utils/path-resolve.mts | 8 +- src/utils/path-resolve.test.mts | 3 +- src/utils/path.mts | 100 + src/utils/pnpm-paths.mts | 3 +- src/utils/pnpm.mts | 8 +- src/utils/promises.mts | 108 + src/utils/prompts.mts | 84 + src/utils/purl-legacy-npm-names.json | 2847 +++++++++++++++++ src/utils/purl.mts | 476 ++- src/utils/registry-manifest.json | 1875 +++++++++++ src/utils/sdk.mts | 11 +- src/utils/sdk.test.mts | 4 - src/utils/self-update.mts | 11 +- src/utils/serialize-result-json.mts | 6 +- src/utils/socket-json.mts | 5 +- src/utils/socket-package-alert.mts | 12 +- src/utils/socket-url.mts | 2 +- src/utils/sorts.mts | 14 + src/utils/spawn-sync.mts | 49 + src/utils/spawn.mts | 266 ++ src/utils/spec.mts | 2 +- src/utils/spinner.mts | 217 ++ src/utils/streams.mts | 24 + src/utils/strings.mts | 66 + src/utils/telemetry/integration.mts | 7 +- src/utils/telemetry/integration.test.mts | 2 +- src/utils/telemetry/service.mts | 3 +- src/utils/telemetry/service.test.mts | 2 +- src/utils/tildify.mts | 3 +- src/utils/url.mts | 17 + src/utils/words.mts | 8 + src/utils/yarn-paths.mts | 3 +- src/utils/yarn-version.mts | 5 +- test/dist-runtime-requires.test.mts | 2 + test/external-bare-requires.test.mts | 10 +- test/package-environment.npm-version.test.mts | 7 +- test/package-matrix.test.mts | 250 ++ test/utils.mts | 137 +- test/utils.test.mts | 18 + tsconfig.dts.json | 2 +- tsconfig.scripts.json | 2 +- vitest.config.mts | 10 + vitest.integration.config.mts | 21 + vitest.native.config.mts | 23 + 385 files changed, 20811 insertions(+), 2251 deletions(-) create mode 100644 .config/rollup.cdxgen-sea.config.mjs create mode 100644 .config/rollup.synp-sea.config.mjs create mode 100644 .npmrc create mode 100644 docs/plans/node27-sea-vfs-socket-package.md delete mode 100644 patches/@socketsecurity__registry@1.1.17.patch create mode 100644 scripts/build-package-matrix.mts create mode 100644 scripts/sea/release/apple/capture.mts create mode 100644 scripts/test/integration.mts create mode 100644 scripts/test/native.mts create mode 100644 scripts/utils/registry-helpers.js rename src/commands/{cli.test.mts => cli.integration.test.mts} (100%) rename src/commands/json/{cmd-json.test.mts => cmd-json.integration.test.mts} (100%) rename src/commands/manifest/{cmd-manifest-auto.test.mts => cmd-manifest-auto.integration.test.mts} (100%) create mode 100644 src/commands/native-cli.native.test.mts create mode 100644 src/registry-constants.mts create mode 100644 src/sea/adapters/cdxgen-worker.mjs create mode 100644 src/sea/adapters/cdxgen.mts create mode 100644 src/sea/adapters/synp-worker.mjs create mode 100644 src/sea/adapters/synp.mts create mode 100644 src/sea/archive-paths.mts create mode 100644 src/sea/build-lock.mts create mode 100644 src/sea/build-sea.test.mts create mode 100644 src/sea/capabilities.mts create mode 100644 src/sea/licenses/cdxgen-third-party/boolbase-1.0.0-ISC.txt create mode 100644 src/sea/licenses/cdxgen-third-party/err-code-2.0.3-MIT.txt create mode 100644 src/sea/licenses/cdxgen-third-party/err-code-2.0.3-README.md create mode 100644 src/sea/licenses/cdxgen-third-party/imurmurhash-0.1.4-MIT.txt create mode 100644 src/sea/licenses/cdxgen-third-party/spdx-exceptions-2.5.0-CC-BY-3.0.txt create mode 100644 src/sea/licenses/cdxgen-third-party/spdx-exceptions-2.5.0-README.md create mode 100644 src/sea/licenses/cdxgen-third-party/spdx-license-ids-3.0.22-CC0-1.0.txt create mode 100644 src/sea/licenses/cdxgen-third-party/spdx-license-ids-3.0.22-README.md create mode 100644 src/sea/licenses/core-third-party/@npmcli-agent-3.0.0-README.md create mode 100644 src/sea/licenses/core-third-party/@npmcli-agent-4.0.0-README.md create mode 100644 src/sea/licenses/core-third-party/ansi-term-0.0.2-ISC.txt create mode 100644 src/sea/licenses/core-third-party/drawille-canvas-blessed-contrib-0.1.3-MIT.txt create mode 100644 src/sea/licenses/core-third-party/drawille-canvas-blessed-contrib-0.1.3-README.md create mode 100644 src/sea/licenses/core-third-party/npmcli-agent-3.0.0-ISC.txt create mode 100644 src/sea/licenses/core-third-party/npmcli-agent-4.0.0-ISC.txt create mode 100644 src/sea/licenses/core-third-party/sigstore-verify-3.1.1-Apache-2.0.txt create mode 100644 src/sea/licenses/core-third-party/sigstore-verify-3.1.1-README.md create mode 100644 src/sea/licenses/core-third-party/x256-0.0.2-MIT.txt create mode 100644 src/sea/licenses/core-third-party/x256-0.0.2-readme.markdown create mode 100644 src/sea/licenses/socket-patch-MIT.txt create mode 100644 src/sea/rollup-provenance.mjs create mode 100644 src/sea/runtime.mts create mode 100644 src/sea/runtime.test.mts create mode 100644 src/sea/stage-synp.mts create mode 100644 src/sea/stage-uv.mts create mode 100644 src/sea/uv-pins.json create mode 100644 src/utils/arrays.mts create mode 100644 src/utils/bin.mts create mode 100644 src/utils/env.mts create mode 100644 src/utils/escape-regexp.mts create mode 100644 src/utils/globs.mts create mode 100644 src/utils/is-object-object.d.mts create mode 100644 src/utils/is-object-object.mjs create mode 100644 src/utils/logger.mts create mode 100644 src/utils/packages.mts create mode 100644 src/utils/packages.test.mts create mode 100644 src/utils/path.mts create mode 100644 src/utils/promises.mts create mode 100644 src/utils/prompts.mts create mode 100644 src/utils/purl-legacy-npm-names.json create mode 100644 src/utils/registry-manifest.json create mode 100644 src/utils/sorts.mts create mode 100644 src/utils/spawn-sync.mts create mode 100644 src/utils/spawn.mts create mode 100644 src/utils/spinner.mts create mode 100644 src/utils/streams.mts create mode 100644 src/utils/url.mts create mode 100644 src/utils/words.mts create mode 100644 test/package-matrix.test.mts create mode 100644 test/utils.test.mts create mode 100644 vitest.integration.config.mts create mode 100644 vitest.native.config.mts diff --git a/.config/rollup.base.config.mjs b/.config/rollup.base.config.mjs index e551e24256..c71c04bdd6 100644 --- a/.config/rollup.base.config.mjs +++ b/.config/rollup.base.config.mjs @@ -9,11 +9,6 @@ import { nodeResolve } from '@rollup/plugin-node-resolve' import replacePlugin from '@rollup/plugin-replace' import { purgePolyfills } from 'unplugin-purge-polyfills' -import { readPackageJsonSync } from '@socketsecurity/registry/lib/packages' -import { escapeRegExp } from '@socketsecurity/registry/lib/regexps' -import { spawnSync } from '@socketsecurity/registry/lib/spawn' -import { stripAnsi } from '@socketsecurity/registry/lib/strings' - import constants from '../scripts/constants.js' import socketModifyPlugin from '../scripts/rollup/socket-modify-plugin.js' import { @@ -21,6 +16,13 @@ import { isBuiltin, normalizeId, } from '../scripts/utils/packages.js' +import { + escapeRegExp, + readPackageJsonSync, + spawnSync, + stripAnsi, +} from '../scripts/utils/registry-helpers.js' +import { includedModulesInventoryPlugin } from '../src/sea/rollup-provenance.mjs' const { INLINED_SOCKET_CLI_CYCLONEDX_CDXGEN_VERSION, @@ -38,11 +40,7 @@ const { VITEST, } = constants -export const EXTERNAL_PACKAGES = [ - '@socketsecurity/registry', - 'blessed', - 'blessed-contrib', -] +export const EXTERNAL_PACKAGES = ['blessed', 'blessed-contrib'] const builtinAliases = builtinModules.reduce((o, n) => { if (!n.startsWith('node:')) { @@ -289,6 +287,15 @@ export default function baseConfig(extendConfig = {}) { }, }), ...extendPlugins, + ...(process.env.SOCKET_SEA_BUILD === 'true' + ? [ + includedModulesInventoryPlugin({ + root: rootPath, + inventoryFile: 'THIRD-PARTY-NOTICES.json', + bundleId: 'core-rollup', + }), + ] + : []), ], } } diff --git a/.config/rollup.cdxgen-sea.config.mjs b/.config/rollup.cdxgen-sea.config.mjs new file mode 100644 index 0000000000..dafe7a62a8 --- /dev/null +++ b/.config/rollup.cdxgen-sea.config.mjs @@ -0,0 +1,530 @@ +/** Bundle the cdxgen API for offline execution from the Node SEA VFS. */ +/* eslint-disable no-await-in-loop -- VFS staging writes shared paths in dependency order. */ +import { createHash } from 'node:crypto' +import { promises as fs } from 'node:fs' +import path from 'node:path' +import url from 'node:url' + +import commonjsPlugin from '@rollup/plugin-commonjs' +import jsonPlugin from '@rollup/plugin-json' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import { parse as parseYaml } from 'yaml' + +const root = path.resolve( + path.dirname(url.fileURLToPath(import.meta.url)), + '..', +) +const curatedLegalRoot = path.join(root, 'src/sea/licenses/cdxgen-third-party') + +const curatedLegalDocuments = { + 'boolbase@1.0.0': [ + { + filename: 'boolbase-1.0.0-ISC.txt', + kind: 'license', + sourcePath: 'LICENSE (upstream file; omitted from npm tarball)', + authority: + 'https://github.com/fb55/boolbase/blob/be0bcd8a4e917a0a5895e95b523fbbed05a64871/LICENSE', + }, + ], + 'err-code@2.0.3': [ + { + filename: 'err-code-2.0.3-MIT.txt', + kind: 'license', + sourcePath: + 'MIT license (npm package README declares MIT; package author used for copyright attribution)', + authority: + 'https://raw.githubusercontent.com/spdx/license-list-data/v3.26.0/text/MIT.txt', + attributionSource: + 'https://raw.githubusercontent.com/IndigoUnited/js-err-code/92511d41a6a926c94c9d11493404867b1e92a77/README.md', + attributionInferredFrom: + 'npm package author field (IndigoUnited); upstream v2.0.3 README declares MIT but no copyright line or license file.', + }, + { + filename: 'err-code-2.0.3-README.md', + kind: 'notice', + sourcePath: 'README.md (published npm package; lock SRI verified)', + authority: 'https://registry.npmjs.org/err-code/2.0.3', + }, + ], + 'imurmurhash@0.1.4': [ + { + filename: 'imurmurhash-0.1.4-MIT.txt', + kind: 'license', + sourcePath: 'LICENSE (upstream file; omitted from npm tarball)', + authority: 'https://github.com/jensyt/imurmurhash-js/blob/0.1.4/LICENSE', + }, + ], + 'spdx-exceptions@2.5.0': [ + { + filename: 'spdx-exceptions-2.5.0-CC-BY-3.0.txt', + kind: 'license', + sourcePath: 'CC-BY-3.0 legal code (npm README declares CC-BY-3.0)', + authority: + 'https://raw.githubusercontent.com/spdx/license-list-data/v3.26.0/text/CC-BY-3.0.txt', + }, + { + filename: 'spdx-exceptions-2.5.0-README.md', + kind: 'notice', + sourcePath: 'README.md (published npm package; lock SRI verified)', + authority: 'https://registry.npmjs.org/spdx-exceptions/2.5.0', + }, + ], + 'spdx-license-ids@3.0.22': [ + { + filename: 'spdx-license-ids-3.0.22-CC0-1.0.txt', + kind: 'license', + sourcePath: 'CC0-1.0 legal code (npm README declares CC0-1.0)', + authority: + 'https://raw.githubusercontent.com/spdx/license-list-data/v3.26.0/text/CC0-1.0.txt', + }, + { + filename: 'spdx-license-ids-3.0.22-README.md', + kind: 'notice', + sourcePath: 'README.md (published npm package; lock SRI verified)', + authority: 'https://registry.npmjs.org/spdx-license-ids/3.0.22', + }, + ], +} + +const legalFilenamePattern = + /^(?:license|licence|copying|copyright|notice|patents?)(?:[._ -].*)?$/i + +function sha256(bytes) { + return createHash('sha256').update(bytes).digest('hex') +} + +function safePart(value) { + return String(value).replace(/[^A-Za-z0-9._-]+/g, '_') || 'unknown' +} + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0 +} + +async function findPackageRoot(modulePath) { + let current = path.dirname(modulePath) + while (current !== path.dirname(current)) { + const packageJsonPath = path.join(current, 'package.json') + try { + const metadata = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')) + if ( + typeof metadata.name === 'string' && + typeof metadata.version === 'string' + ) { + return { directory: current, metadata } + } + } catch (error) { + if (error?.code !== 'ENOENT' && !(error instanceof SyntaxError)) { + throw error + } + } + if (path.basename(current) === 'node_modules') { + break + } + current = path.dirname(current) + } +} + +async function findLegalFiles(packageRoot) { + const files = [] + const skippedLinks = [] + const visit = async (directory, relativeDirectory = '') => { + for (const entry of ( + await fs.readdir(directory, { withFileTypes: true }) + ).sort((left, right) => compareText(left.name, right.name))) { + const relativePath = path.posix.join( + relativeDirectory.split(path.sep).join('/'), + entry.name, + ) + const fullPath = path.join(directory, entry.name) + if (entry.isDirectory()) { + if (entry.name !== 'node_modules' && entry.name !== '.git') { + await visit(fullPath, path.join(relativeDirectory, entry.name)) + } + } else if (entry.isSymbolicLink()) { + if (legalFilenamePattern.test(entry.name)) { + skippedLinks.push(relativePath) + } + } else if (entry.isFile() && legalFilenamePattern.test(entry.name)) { + files.push({ fullPath, relativePath }) + } + } + } + await visit(packageRoot) + return { files, skippedLinks } +} + +function thirdPartyNoticePlugin() { + return { + name: 'sea-cdxgen-third-party-notices', + async generateBundle() { + const packages = new Map() + const sourceModules = new Map() + const unmappedModuleCount = { count: 0 } + const lock = parseYaml( + await fs.readFile(path.join(root, 'pnpm-lock.yaml'), 'utf8'), + ) + if (!lock || typeof lock.packages !== 'object' || !lock.packages) { + throw new Error('pnpm-lock.yaml does not contain a packages graph') + } + const lockPackages = lock.packages + const patchedDependencies = lock.patchedDependencies ?? {} + for (const id of this.getModuleIds()) { + if (id.startsWith('\0')) { + continue + } + const rawPath = id.startsWith('file:') + ? url.fileURLToPath(id) + : id.split('?')[0] + if ( + !path.isAbsolute(rawPath) || + !rawPath.split(path.sep).includes('node_modules') + ) { + continue + } + let modulePath + try { + modulePath = await fs.realpath(rawPath) + } catch (error) { + if (error?.code === 'ENOENT') { + continue + } + throw error + } + const packageInfo = await findPackageRoot(modulePath) + if (!packageInfo) { + unmappedModuleCount.count += 1 + const moduleDigest = sha256(await fs.readFile(modulePath)) + sourceModules.set(modulePath, { + sourcePath: `unmapped/${path.basename(modulePath)}-${moduleDigest.slice(0, 12)}`, + sha256: moduleDigest, + package: null, + verification: 'unverified', + verificationReason: + 'No package metadata root was found for this Rollup module.', + }) + continue + } + const { directory, metadata } = packageInfo + const lockKeyCandidates = Object.keys(lockPackages) + .filter( + key => + key === `${metadata.name}@${metadata.version}` || + key.startsWith(`${metadata.name}@${metadata.version}(`), + ) + .sort(compareText) + const lockKey = + lockKeyCandidates.length === 1 ? lockKeyCandidates[0] : null + const lockRecord = lockKey ? lockPackages[lockKey] : null + const lockContexts = lockKeyCandidates.map(candidate => ({ + packageKey: candidate, + resolution: lockPackages[candidate]?.resolution ?? null, + })) + const patch = + patchedDependencies[`${metadata.name}@${metadata.version}`] ?? null + const instancePath = + lockKey ?? + (lockKeyCandidates.length + ? `ambiguous:${lockKeyCandidates.join('|')}` + : `${metadata.name}@${metadata.version}:missing-lock-entry`) + const key = `${metadata.name}@${metadata.version}\0${instancePath}` + let record = packages.get(key) + if (!record) { + record = { + packageName: metadata.name, + version: metadata.version, + instancePath, + lockKey, + lockContexts, + lockResolution: lockRecord?.resolution ?? null, + patch: patch + ? { path: patch.path ?? null, hash: patch.hash ?? null } + : null, + curatedLegalDocuments: + curatedLegalDocuments[`${metadata.name}@${metadata.version}`] ?? + [], + license: null, + licenseDeclarations: new Map(), + roots: new Map(), + moduleCount: 0, + obligations: [], + } + packages.set(key, record) + } + const licenseDeclaration = metadata.license ?? metadata.licenses ?? null + record.licenseDeclarations.set( + JSON.stringify(licenseDeclaration), + licenseDeclaration, + ) + const declarationValues = [...record.licenseDeclarations.entries()] + .sort(([left], [right]) => compareText(left, right)) + .map(([, value]) => value) + record.license = + declarationValues.length === 1 + ? declarationValues[0] + : declarationValues + record.moduleCount += 1 + const relativeModulePath = path + .relative(directory, modulePath) + .split(path.sep) + .join('/') + sourceModules.set(modulePath, { + sourcePath: `${instancePath}/${relativeModulePath}`, + package: `${metadata.name}@${metadata.version}`, + packageInstance: instancePath, + packagePath: relativeModulePath, + sha256: sha256(await fs.readFile(modulePath)), + lockPackageKey: lockKey, + lockPackageCandidates: lockContexts, + lockResolution: lockRecord?.resolution ?? null, + declaredLockIntegrity: lockRecord?.resolution?.integrity ?? null, + patch: patch + ? { path: patch.path ?? null, hash: patch.hash ?? null } + : null, + verification: 'unverified', + verificationReason: + 'Installed module bytes were hashed but not authenticated against locked tarball or patch output; declared lock integrity does not verify generated bundle bytes.', + }) + if (!record.roots.has(directory)) { + const { files, skippedLinks } = await findLegalFiles(directory) + record.roots.set(directory, { files, skippedLinks }) + } + } + + const inventory = { + schemaVersion: 1, + generator: 'rollup-module-closure', + packages: [], + unmappedModuleCount: unmappedModuleCount.count, + obligations: [], + } + const sourceInventory = { + schemaVersion: 1, + generator: 'rollup-module-source-hashes', + lockfile: { + path: 'pnpm-lock.yaml', + lockfileVersion: lock.lockfileVersion, + }, + verification: 'unverified', + verificationReason: + 'Hashes identify installed module source files. Declared lock SRI is metadata only and does not authenticate installed, patched, or generated bundle bytes.', + modules: [...sourceModules.values()].sort((left, right) => + compareText(left.sourcePath, right.sourcePath), + ), + } + const sourceInventoryJson = `${JSON.stringify(sourceInventory, null, 2)}\n` + const sourceInventorySha256 = sha256(Buffer.from(sourceInventoryJson)) + this.emitFile({ + type: 'asset', + fileName: 'ROLLUP-SOURCE-INVENTORY.json', + source: sourceInventoryJson, + }) + inventory.sourceInventory = { + path: 'tools/cdxgen/ROLLUP-SOURCE-INVENTORY.json', + sha256: sourceInventorySha256, + moduleCount: sourceModules.size, + verification: 'unverified', + } + if (unmappedModuleCount.count > 0) { + inventory.obligations.push({ + code: 'unmapped-rollup-modules', + count: unmappedModuleCount.count, + message: + 'Some bundled node_modules modules could not be mapped to package metadata.', + }) + } + + for (const record of [...packages.values()].sort((left, right) => + compareText( + `${left.packageName}@${left.version}\0${left.instancePath}`, + `${right.packageName}@${right.version}\0${right.instancePath}`, + ), + )) { + if (record.licenseDeclarations.size > 1) { + record.obligations.push({ + code: 'conflicting-license-declarations', + message: + 'The same package name and version resolved with different license declarations.', + }) + } + if ( + record.curatedLegalDocuments.some( + document => document.attributionInferredFrom, + ) + ) { + record.obligations.push({ + code: 'inferred-copyright-attribution', + message: record.curatedLegalDocuments.find( + document => document.attributionInferredFrom, + ).attributionInferredFrom, + }) + } + const licenseIsString = + typeof record.license === 'string' && record.license.trim() !== '' + if (!licenseIsString) { + record.obligations.push({ + code: record.license + ? 'ambiguous-license-declaration' + : 'missing-license-declaration', + message: + 'package.json does not provide one unambiguous nonempty license string.', + }) + } + if ( + Array.isArray(record.license) || + (record.license && typeof record.license === 'object') + ) { + record.obligations.push({ + code: 'ambiguous-license-declaration-format', + message: + 'The license declaration is structured or deprecated and requires review.', + }) + } + + const id = `${record.packageName}@${record.version}\0${record.instancePath}` + const packageSlug = `${safePart(record.packageName)}-${safePart(record.version)}-${sha256(Buffer.from(id)).slice(0, 12)}` + const stagedFiles = new Map() + const skippedLinks = [] + for (const { files, skippedLinks: links } of record.roots.values()) { + skippedLinks.push(...links) + for (const file of files) { + const contents = await fs.readFile(file.fullPath) + const digest = sha256(contents) + const relativePath = file.relativePath.split(path.sep).join('/') + const sourcePath = path.posix.parse(relativePath) + const contentAddressedName = `${sourcePath.name}.${digest.slice(0, 12)}${sourcePath.ext}` + const outputPath = `notices/${packageSlug}/${sourcePath.dir ? `${sourcePath.dir}/` : ''}${contentAddressedName}` + stagedFiles.set(outputPath, { + contents, + sha256: digest, + relativePath, + }) + } + } + + // Several published npm tarballs omit the license text even though + // package.json declares a license. Include version-pinned authoritative + // texts and attribution material collected during the SEA audit. + for (const document of record.curatedLegalDocuments) { + const contents = await fs.readFile( + path.join(curatedLegalRoot, document.filename), + ) + const digest = sha256(contents) + const outputPath = `notices/${packageSlug}/${document.filename}` + stagedFiles.set(outputPath, { + contents, + sha256: digest, + relativePath: document.sourcePath, + kind: document.kind, + authority: document.authority, + ...(document.attributionSource + ? { attributionSource: document.attributionSource } + : {}), + ...(document.attributionInferredFrom + ? { attributionInferredFrom: document.attributionInferredFrom } + : {}), + }) + } + + const licenseFiles = [] + const noticeFiles = [] + for (const [outputPath, file] of [...stagedFiles].sort(([a], [b]) => + compareText(a, b), + )) { + this.emitFile({ + type: 'asset', + fileName: outputPath, + source: file.contents, + }) + const reference = { + path: `tools/cdxgen/${outputPath}`, + sourcePath: file.relativePath, + sha256: file.sha256, + ...(file.authority + ? { + source: file.authority, + ...(file.attributionSource + ? { attributionSource: file.attributionSource } + : {}), + ...(file.attributionInferredFrom + ? { attributionInferredFrom: file.attributionInferredFrom } + : {}), + } + : {}), + } + const basename = path.posix.basename(file.relativePath) + if ( + file.kind === 'notice' || + /^(?:notice|copyright|patents?)/i.test(basename) + ) { + noticeFiles.push(reference) + } else { + licenseFiles.push(reference) + } + } + if (licenseFiles.length === 0) { + record.obligations.push({ + code: 'missing-license-text', + message: + 'No license text file was found in the resolved package tree.', + }) + } + if (skippedLinks.length > 0) { + record.obligations.push({ + code: 'unresolved-license-symlink', + paths: [...new Set(skippedLinks)].sort(compareText), + message: + 'A license or notice symlink was not followed when collecting package texts.', + }) + } + const packageRecord = { + name: record.packageName, + version: record.version, + instancePath: record.instancePath, + lockPackageKey: record.lockKey, + lockContexts: record.lockContexts, + patch: record.patch, + license: record.license, + moduleCount: record.moduleCount, + licenseFiles, + noticeFiles, + obligations: record.obligations, + } + inventory.packages.push(packageRecord) + for (const obligation of record.obligations) { + inventory.obligations.push({ + package: `${record.packageName}@${record.version}`, + ...obligation, + }) + } + } + + this.emitFile({ + type: 'asset', + fileName: 'THIRD-PARTY-NOTICES.json', + source: `${JSON.stringify(inventory, null, 2)}\n`, + }) + }, + } +} + +export default { + input: + process.env.SEA_CDXGEN_INPUT || + path.join(root, 'node_modules/@cyclonedx/cdxgen/lib/cli/index.js'), + output: { + dir: + process.env.SEA_CDXGEN_OUTPUT || path.join(root, 'dist/sea-cdxgen-api'), + format: 'es', + entryFileNames: 'lib/cli/index.js', + chunkFileNames: 'lib/cli/chunks/[name]-[hash].js', + assetFileNames: 'lib/cli/assets/[name]-[hash][extname]', + }, + external: id => id.startsWith('node:'), + plugins: [ + nodeResolve({ preferBuiltins: true, exportConditions: ['node'] }), + jsonPlugin(), + commonjsPlugin(), + thirdPartyNoticePlugin(), + ], +} diff --git a/.config/rollup.dist.config.mjs b/.config/rollup.dist.config.mjs index 1c41116912..e9ca764655 100644 --- a/.config/rollup.dist.config.mjs +++ b/.config/rollup.dist.config.mjs @@ -11,17 +11,6 @@ import { nodeResolve } from '@rollup/plugin-node-resolve' import fastGlob from 'fast-glob' import trash from 'trash' -import { isDirEmptySync } from '@socketsecurity/registry/lib/fs' -import { hasKeys } from '@socketsecurity/registry/lib/objects' -import { - fetchPackageManifest, - readPackageJson, -} from '@socketsecurity/registry/lib/packages' -import { normalizePath } from '@socketsecurity/registry/lib/path' -import { escapeRegExp } from '@socketsecurity/registry/lib/regexps' -import { naturalCompare } from '@socketsecurity/registry/lib/sorts' -import { spawn } from '@socketsecurity/registry/lib/spawn' - import baseConfig, { EXTERNAL_PACKAGES } from './rollup.base.config.mjs' import constants from '../scripts/constants.js' import socketModifyPlugin from '../scripts/rollup/socket-modify-plugin.js' @@ -30,6 +19,20 @@ import { isBuiltin, normalizeId, } from '../scripts/utils/packages.js' +import { + escapeRegExp, + fetchPackageManifest, + hasKeys, + isDirEmptySync, + naturalCompare, + normalizePath, + readPackageJson, + spawnAsync, +} from '../scripts/utils/registry-helpers.js' +import { + includedModulesInventoryPlugin, + writeCopiedPackageInventory, +} from '../src/sea/rollup-provenance.mjs' const { CONSTANTS, @@ -68,10 +71,14 @@ const BLESSED_CONTRIB = 'blessed-contrib' const FLAGS = 'flags' const LICENSE_MD = `LICENSE.md` const SENTRY_NODE = '@sentry/node' +const SEA_BUILD_ENV = 'SOCKET_SEA_BUILD' +const SPAWN_SYNC = 'spawn-sync' +const SPINNER = 'spinner' const SOCKET_DESCRIPTION = 'CLI for Socket.dev' const SOCKET_DESCRIPTION_WITH_SENTRY = `${SOCKET_DESCRIPTION}, includes Sentry error handling, otherwise identical to the regular \`${SOCKET_CLI_BIN_NAME}\` package` -const SOCKET_SECURITY_REGISTRY = '@socketsecurity/registry' +const REGISTRY_CONSTANTS = 'registry-constants' const UTILS = 'utils' +const ENV_HELPERS = 'env-helpers' const VENDOR = 'vendor' // A fresh regexp per call: socketModifyPlugin advances lastIndex, so a shared @@ -155,7 +162,10 @@ async function copyManifestScripts() { jarPath, path.join(destDir, 'maven-extension', 'coana-maven-extension.jar'), ) - } else if (constants.ENV[INLINED_SOCKET_CLI_PUBLISHED_BUILD]) { + } else if ( + constants.ENV[INLINED_SOCKET_CLI_PUBLISHED_BUILD] && + process.env[SEA_BUILD_ENV] !== 'true' + ) { // Fail closed: a published build without the jar would ship a package whose // `socket manifest maven` / Maven reachability silently produces an empty // SBOM. Run `pnpm run build:maven-extension` before `build:dist`. (A local @@ -178,7 +188,7 @@ async function copyBashCompletion() { } async function copyExternalPackages() { - const { blessedContribPath, blessedPath, socketRegistryPath } = constants + const { blessedContribPath, blessedPath } = constants const nmPath = path.join(constants.rootPath, NODE_MODULES) const blessedContribNmPath = path.join(nmPath, BLESSED_CONTRIB) @@ -191,9 +201,7 @@ async function copyExternalPackages() { // Copy the other packages over to ./external/. .map(n => copyPackage(n, { - strict: - // Skip adding 'use strict' directives to Socket packages. - n !== SOCKET_SECURITY_REGISTRY, + strict: true, }), ), // Copy 'blessed-contrib' license over to @@ -218,16 +226,6 @@ async function copyExternalPackages() { // would be dropped too). [blessedPath, ['lib/**/*.js', 'usr/*', 'vendor/**/*.js']], [blessedContribPath, ['lib/**/*.js', 'index.js']], - [ - socketRegistryPath, - [ - 'external/**/*.js', - 'lib/**/*.js', - 'index.js', - 'extensions.json', - 'manifest.json', - ], - ], ].map(async ({ 0: thePath, 1: ignorePatterns }) => { await removeFiles(thePath, { exclude: [...alwaysIgnoredPatterns, ...ignorePatterns], @@ -259,6 +257,24 @@ async function copyExternalPackages() { ) } +function blessedContribInventoryPlugin(filepath) { + if (process.env[SEA_BUILD_ENV] !== 'true') { + return undefined + } + const relativeEntry = path + .relative(constants.srcPath, filepath) + .split(path.sep) + .join('/') + .replace(/\.mjs$/, '') + return includedModulesInventoryPlugin({ + root: constants.rootPath, + inventoryFile: `THIRD-PARTY-NOTICES-${relativeEntry.replaceAll('/', '-')}.json`, + bundleId: `external-${relativeEntry}`, + outputRoot: constants.distPath, + mode: 'stage', + }) +} + async function copyPackage(pkgName, options) { const { strict = true } = { __proto__: null, ...options } const nmPath = path.join(constants.rootPath, NODE_MODULES) @@ -347,7 +363,7 @@ async function updatePackageLockFile() { return } try { - await spawn( + await spawnAsync( 'pnpm', [ 'install', @@ -446,6 +462,14 @@ export default async () => { const { configPath, distPath, rootPath, srcPath } = constants const nmPath = normalizePath(path.join(rootPath, NODE_MODULES)) const constantsSrcPath = normalizePath(path.join(srcPath, 'constants.mts')) + const registryConstantsSrcPath = normalizePath( + path.join(srcPath, 'registry-constants.mts'), + ) + const envHelpersSrcPath = normalizePath(path.join(srcPath, 'utils/env.mts')) + const spawnSyncSrcPath = normalizePath( + path.join(srcPath, 'utils/spawn-sync.mts'), + ) + const spinnerSrcPath = normalizePath(path.join(srcPath, 'utils/spinner.mts')) const externalSrcPath = normalizePath(path.join(srcPath, 'external')) const blessedContribSrcPath = normalizePath( path.join(externalSrcPath, BLESSED_CONTRIB), @@ -502,6 +526,14 @@ export default async () => { switch (id) { case constantsSrcPath: return CONSTANTS + case registryConstantsSrcPath: + return REGISTRY_CONSTANTS + case envHelpersSrcPath: + return ENV_HELPERS + case spawnSyncSrcPath: + return SPAWN_SYNC + case spinnerSrcPath: + return SPINNER case flagsSrcPath: return FLAGS case shadowNpmBinSrcPath: @@ -555,19 +587,33 @@ export default async () => { }), { async writeBundle() { + const updatePackageMetadata = process.env[SEA_BUILD_ENV] !== 'true' await Promise.all([ copyCoanaCache(), copyInitGradle(), copyManifestScripts(), copyBashCompletion(), - updatePackageJson(), + ...(updatePackageMetadata ? [updatePackageJson()] : []), // Remove dist/vendor.js.map file. trash([path.join(distPath, `${VENDOR}.js.map`)]), ]) // Copy external packages AFTER other operations to avoid conflicts. await copyExternalPackages() + if (process.env[SEA_BUILD_ENV] === 'true') { + await writeCopiedPackageInventory({ + root: rootPath, + packageName: BLESSED, + packageRoot: path.join(rootPath, NODE_MODULES, BLESSED), + outputPackageRoot: path.join(constants.externalPath, BLESSED), + outputRoot: distPath, + inventoryFile: 'THIRD-PARTY-NOTICES-external-blessed.json', + bundleId: 'external-blessed', + }) + } // Update package-lock.json AFTER package.json. - await updatePackageLockFile() + if (updatePackageMetadata) { + await updatePackageLockFile() + } }, }, ], @@ -581,11 +627,19 @@ export default async () => { }) ).map(filepath => { const relPath = `${path.relative(srcPath, filepath).slice(0, -4 /*.mjs*/)}.js` + const relParts = relPath.split(path.sep) + if (relParts[0] !== 'external') { + throw new Error( + `Unexpected Blessed source path outside src/external: ${filepath}`, + ) + } + const outputFile = path.join(constants.externalPath, ...relParts.slice(1)) + const provenancePlugin = blessedContribInventoryPlugin(filepath) return { input: filepath, output: [ { - file: path.join(rootPath, relPath), + file: outputFile, exports: 'auto', externalLiveBindings: false, format: 'cjs', @@ -606,10 +660,11 @@ export default async () => { ) }, plugins: [ + ...(provenancePlugin ? [provenancePlugin] : []), // Runs after copyExternalPackages() and overwrites what it rewired. socketModifyPlugin({ find: newBareBlessedRequireRegExp(), - replace: () => relativeBlessedPath(path.join(rootPath, relPath)), + replace: () => relativeBlessedPath(outputFile), }), nodeResolve({ exportConditions: ['node'], diff --git a/.config/rollup.sea.config.mjs b/.config/rollup.sea.config.mjs index b22fe8e32c..4ff2484c62 100644 --- a/.config/rollup.sea.config.mjs +++ b/.config/rollup.sea.config.mjs @@ -1,8 +1,4 @@ -/** - * Rollup configuration for building SEA bootstrap thin wrapper. - * Compiles TypeScript bootstrap to CommonJS for Node.js SEA compatibility. - */ - +/** Rollup the embedded root Socket app launcher for the Node 27 SEA VFS. */ import path from 'node:path' import url from 'node:url' @@ -10,31 +6,24 @@ import { babel as babelPlugin } from '@rollup/plugin-babel' import commonjsPlugin from '@rollup/plugin-commonjs' import { nodeResolve } from '@rollup/plugin-node-resolve' -const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) -const rootDir = path.join(__dirname, '..') - +const root = path.resolve( + path.dirname(url.fileURLToPath(import.meta.url)), + '..', +) export default { - input: - process.env.SEA_BOOTSTRAP || path.join(rootDir, 'src/sea/bootstrap.mts'), + input: process.env.SEA_BOOTSTRAP || path.join(root, 'src/sea/bootstrap.mts'), output: { - file: - process.env.SEA_OUTPUT || path.join(rootDir, 'dist/sea/bootstrap.cjs'), + file: process.env.SEA_OUTPUT || path.join(root, 'dist/sea/bootstrap.cjs'), format: 'cjs', interop: 'auto', }, - external: [ - // Only externalize Node.js built-ins for the thin wrapper. - /^node:/, - ], + external: [/^node:/], plugins: [ - nodeResolve({ - preferBuiltins: true, - exportConditions: ['node'], - }), + nodeResolve({ preferBuiltins: true, exportConditions: ['node'] }), babelPlugin({ babelHelpers: 'runtime', babelrc: false, - configFile: path.join(__dirname, 'babel.config.js'), + configFile: path.join(root, '.config/babel.config.js'), extensions: ['.mjs', '.js', '.ts', '.mts'], }), commonjsPlugin(), diff --git a/.config/rollup.synp-sea.config.mjs b/.config/rollup.synp-sea.config.mjs new file mode 100644 index 0000000000..8d5e6da89d --- /dev/null +++ b/.config/rollup.synp-sea.config.mjs @@ -0,0 +1,222 @@ +/** Bundle the pinned Synp API and its dependency/license closure for SEA VFS. */ +/* eslint-disable no-await-in-loop -- VFS staging writes shared paths in dependency order. */ +import { createHash } from 'node:crypto' +import { promises as fs } from 'node:fs' +import path from 'node:path' +import url from 'node:url' + +import commonjsPlugin from '@rollup/plugin-commonjs' +import { nodeResolve } from '@rollup/plugin-node-resolve' + +const root = path.resolve( + path.dirname(url.fileURLToPath(import.meta.url)), + '..', +) +const legalPattern = + /^(?:license|licence|copying|copyright|notice|patents?)(?:[._ -].*)?$/i + +function digest(bytes) { + return createHash('sha256').update(bytes).digest('hex') +} + +function slug(value) { + return String(value).replace(/[^A-Za-z0-9._-]+/g, '_') || 'unknown' +} + +async function packageRootFor(modulePath) { + let current = path.dirname(modulePath) + while (current !== path.dirname(current)) { + try { + const metadata = JSON.parse( + await fs.readFile(path.join(current, 'package.json'), 'utf8'), + ) + if ( + typeof metadata.name === 'string' && + typeof metadata.version === 'string' + ) { + return { root: current, metadata } + } + } catch (error) { + if (error?.code !== 'ENOENT' && !(error instanceof SyntaxError)) { + throw error + } + } + if (path.basename(current) === 'node_modules') { + break + } + current = path.dirname(current) + } +} + +async function legalFiles(packageRoot) { + const found = [] + const visit = async (directory, relative = '') => { + for (const entry of ( + await fs.readdir(directory, { withFileTypes: true }) + ).sort((a, b) => a.name.localeCompare(b.name))) { + const relativePath = path.posix.join( + relative.split(path.sep).join('/'), + entry.name, + ) + const fullPath = path.join(directory, entry.name) + if (entry.isDirectory()) { + if (entry.name !== 'node_modules' && entry.name !== '.git') { + await visit(fullPath, path.join(relative, entry.name)) + } + } else if ( + (entry.isFile() || entry.isSymbolicLink()) && + legalPattern.test(entry.name) + ) { + const resolvedPath = await fs.realpath(fullPath) + if ( + resolvedPath !== packageRoot && + !resolvedPath.startsWith(`${packageRoot}${path.sep}`) + ) { + throw new Error( + `Synp notice file escapes package root: ${relativePath}`, + ) + } + found.push({ fullPath: resolvedPath, relativePath }) + } + } + } + await visit(packageRoot) + return found +} + +function noticesPlugin() { + return { + name: 'sea-synp-third-party-notices', + async generateBundle() { + const packages = new Map() + const unmapped = [] + for (const id of this.getModuleIds()) { + if (id.startsWith('\0')) { + continue + } + const raw = id.startsWith('file:') + ? url.fileURLToPath(id) + : id.split('?')[0] + if ( + !path.isAbsolute(raw) || + !raw.split(path.sep).includes('node_modules') + ) { + continue + } + let real + try { + real = await fs.realpath(raw) + } catch (error) { + if (error?.code === 'ENOENT') { + continue + } + throw error + } + const info = await packageRootFor(real) + if (!info) { + unmapped.push(real) + continue + } + const key = `${info.metadata.name}@${info.metadata.version}` + if (!packages.has(key)) { + packages.set(key, { ...info, key }) + } + } + if (unmapped.length) { + throw new Error( + `Unable to map ${unmapped.length} bundled Synp module(s) to package metadata`, + ) + } + + const inventory = { + schemaVersion: 1, + generator: 'rollup-module-closure', + packages: [], + obligations: [], + } + for (const record of [...packages.values()].sort((a, b) => + a.key.localeCompare(b.key), + )) { + const files = await legalFiles(record.root) + const obligations = [] + if (!files.length) { + obligations.push({ + code: 'missing-license-text', + message: + 'No license or notice text file is present in the installed package; its package metadata license is retained.', + }) + } + const packageSlug = `${slug(record.metadata.name)}-${slug(record.metadata.version)}` + const licenseFiles = [] + const noticeFiles = [] + for (const file of files) { + const contents = await fs.readFile(file.fullPath) + const filename = `notices/${packageSlug}/${file.relativePath}` + this.emitFile({ type: 'asset', fileName: filename, source: contents }) + const reference = { + path: `tools/synp/${filename}`, + sourcePath: file.relativePath, + sha256: digest(contents), + } + if ( + /^(?:notice|copyright|patents?)/i.test( + path.posix.basename(file.relativePath), + ) + ) { + noticeFiles.push(reference) + } else { + licenseFiles.push(reference) + } + } + inventory.packages.push({ + name: record.metadata.name, + version: record.metadata.version, + license: record.metadata.license ?? record.metadata.licenses ?? null, + licenseFiles, + noticeFiles, + obligations, + }) + for (const obligation of obligations) { + inventory.obligations.push({ package: record.key, ...obligation }) + } + } + this.emitFile({ + type: 'asset', + fileName: 'THIRD-PARTY-NOTICES.json', + source: `${JSON.stringify(inventory, null, 2)}\n`, + }) + }, + } +} + +export default { + input: + process.env.SEA_SYNP_INPUT || + path.join(root, 'src/sea/adapters/synp-worker.mjs'), + output: { + dir: process.env.SEA_SYNP_OUTPUT || path.join(root, 'dist/sea-synp'), + format: 'cjs', + entryFileNames: 'bin/synp.js', + }, + external: id => + id.startsWith('node:') || + [ + 'assert', + 'buffer', + 'crypto', + 'fs', + 'fs/promises', + 'module', + 'os', + 'path', + 'stream', + 'url', + 'util', + 'worker_threads', + ].includes(id), + plugins: [ + nodeResolve({ preferBuiltins: true, exportConditions: ['node'] }), + commonjsPlugin(), + noticesPlugin(), + ], +} diff --git a/.github/workflows/bazel-windows.yml b/.github/workflows/bazel-windows.yml index 6d55233363..bd7620b92d 100644 --- a/.github/workflows/bazel-windows.yml +++ b/.github/workflows/bazel-windows.yml @@ -7,6 +7,10 @@ on: - .github/workflows/bazel-windows.yml - package.json - pnpm-lock.yaml + - .config/rollup.sea.config.mjs + - src/sea/** + - scripts/build-package-matrix.mts + - test/package-matrix.test.mts - src/commands/manifest/bazel/** - test/fixtures/manifest-bazel/** push: @@ -15,6 +19,10 @@ on: - .github/workflows/bazel-windows.yml - package.json - pnpm-lock.yaml + - .config/rollup.sea.config.mjs + - src/sea/** + - scripts/build-package-matrix.mts + - test/package-matrix.test.mts - src/commands/manifest/bazel/** - test/fixtures/manifest-bazel/** @@ -101,7 +109,7 @@ jobs: - name: Test executable handling and prerequisites run: | $PSNativeCommandUseErrorActionPreference = $true - pnpm test:unit src/commands/manifest/bazel/bazel-bin-detect.test.mts src/commands/manifest/bazel/bazel-process.test.mts src/commands/manifest/bazel/bazel-java-shim.test.mts src/commands/manifest/bazel/bazel-python-shim.test.mts src/commands/manifest/bazel/bazel-query-runner.test.mts src/commands/manifest/bazel/bazel-cquery.test.mts + pnpm test:unit src/commands/manifest/bazel/bazel-bin-detect.test.mts src/commands/manifest/bazel/bazel-process.test.mts src/commands/manifest/bazel/bazel-java-shim.test.mts src/commands/manifest/bazel/bazel-python-shim.test.mts src/commands/manifest/bazel/bazel-query-runner.test.mts src/commands/manifest/bazel/bazel-cquery.test.mts src/sea/build-sea.test.mts test/package-matrix.test.mts - name: Install the packaged CLI run: | diff --git a/.gitignore b/.gitignore index b75a474eeb..a55132e0fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,39 +1,1360 @@ -.DS_Store -._.DS_Store -.Trash/ -Thumbs.db +# Ignore everything by default; explicitly allow tracked repository files below. +* +!.gitignore +!/.claude/ +!/.claude/skills/ +!/.claude/skills/bump-coana/ +!/.config/ +!/.husky/ +!/.vscode/ +!/.github/ +!/.github/actions/ +!/.github/actions/repo/ +!/.github/actions/repo/upload-artifact/ +!/.github/scripts/ +!/.github/workflows/ +!/.github/actions/repo/upload-artifact/action.yml +!/.github/actions/repo/upload-artifact/index.mjs +!/.github/scripts/pin-readme-assets.mjs +!/.github/scripts/smoke-test-tarball.sh +!/.github/workflows/bazel-windows.yml +!/.github/workflows/ci.yml +!/.github/workflows/e2e-tests.yml +!/.github/workflows/publish-npm.yml +!/assets/ +!/assets/fleet/ +!/bin/ +!/docs/ +!/docs/plans/ +!/patches/ +!/scripts/ +!/scripts/build-package-matrix.mts +!/scripts/babel/ +!/scripts/ci/ +!/scripts/lib/ +!/scripts/release/ +!/scripts/rollup/ +!/scripts/sea/ +!/scripts/sea/release/ +!/scripts/sea/release/apple/ +!/scripts/test/ +!/scripts/utils/ +!/shadow-bin/ +!/src/ +!/src/commands/ +!/src/commands/analytics/ +!/src/commands/audit-log/ +!/src/commands/cdxgen/ +!/src/commands/ci/ +!/src/commands/config/ +!/src/commands/fix/ +!/src/commands/install/ +!/src/commands/json/ +!/src/commands/login/ +!/src/commands/logout/ +!/src/commands/manifest/ +!/src/commands/manifest/bazel/ +!/src/commands/manifest/scripts/ +!/src/commands/manifest/scripts/dotnet-tool/ +!/src/commands/manifest/scripts/maven-extension/ +!/src/commands/manifest/scripts/maven-extension/.mvn/ +!/src/commands/manifest/scripts/maven-extension/.mvn/wrapper/ +!/src/commands/manifest/scripts/maven-extension/src/ +!/src/commands/manifest/scripts/maven-extension/src/main/ +!/src/commands/manifest/scripts/maven-extension/src/main/java/ +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/ +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/ +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/ext/ +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/ +!/src/commands/manifest/scripts/test/ +!/src/commands/manifest/scripts/test/dotnet-compat/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/shared/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/App/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/Extra/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/Lib/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/test/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/test/App.Tests/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/tools/ +!/src/commands/manifest/scripts/test/dotnet-compat/basic/tools/Nuke/ +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/ +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/ +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/Api/ +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/Core/ +!/src/commands/manifest/scripts/test/dotnet-compat/dev/ +!/src/commands/manifest/scripts/test/dotnet-compat/evaluation/ +!/src/commands/manifest/scripts/test/dotnet-compat/evaluation/Lib/ +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/ +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/app/ +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/app/core/ +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/shared/ +!/src/commands/manifest/scripts/test/dotnet-compat/failures/ +!/src/commands/manifest/scripts/test/dotnet-compat/failures/broken/ +!/src/commands/manifest/scripts/test/dotnet-compat/failures/missing/ +!/src/commands/manifest/scripts/test/dotnet-compat/langs/ +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Fs/ +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Vb/ +!/src/commands/manifest/scripts/test/dotnet-compat/multi/ +!/src/commands/manifest/scripts/test/dotnet-compat/multi/One/ +!/src/commands/manifest/scripts/test/dotnet-compat/multi/Two/ +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/ +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Legacy/ +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Legacy/Properties/ +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Modern/ +!/src/commands/manifest/scripts/test/dotnet-compat/pair/ +!/src/commands/manifest/scripts/test/dotnet-compat/rid/ +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/ +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/sln/ +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/src/ +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/src/A/ +!/src/commands/manifest/scripts/test/gradle-compat/ +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/ +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/app/ +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/app/core/ +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/shared/ +!/src/commands/manifest/scripts/test/gradle-compat/failures/ +!/src/commands/manifest/scripts/test/gradle-compat/failures/app/ +!/src/commands/manifest/scripts/test/gradle-compat/failures/gradle/ +!/src/commands/manifest/scripts/test/gradle-compat/failures/lib/ +!/src/commands/manifest/scripts/test/gradle-compat/project/ +!/src/commands/manifest/scripts/test/maven-compat/ +!/src/commands/manifest/scripts/test/maven-compat/descriptor-failure/ +!/src/commands/manifest/scripts/test/maven-compat/descriptor-failure/a/ +!/src/commands/manifest/scripts/test/maven-compat/descriptor-failure/b/ +!/src/commands/manifest/scripts/test/maven-compat/duplicate-failure/ +!/src/commands/manifest/scripts/test/maven-compat/duplicate-failure/m1/ +!/src/commands/manifest/scripts/test/maven-compat/duplicate-failure/m2/ +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/ +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/app/ +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/app/core/ +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/shared/ +!/src/commands/manifest/scripts/test/maven-compat/graph-failure/ +!/src/commands/manifest/scripts/test/maven-compat/project/ +!/src/commands/manifest/scripts/test/maven-compat/project/app/ +!/src/commands/manifest/scripts/test/maven-compat/project/app/src/ +!/src/commands/manifest/scripts/test/maven-compat/project/app/src/main/ +!/src/commands/manifest/scripts/test/maven-compat/project/app/src/main/java/ +!/src/commands/manifest/scripts/test/maven-compat/project/app/src/main/java/demo/ +!/src/commands/manifest/scripts/test/maven-compat/project/lib/ +!/src/commands/manifest/scripts/test/maven-compat/project/lib/src/ +!/src/commands/manifest/scripts/test/maven-compat/project/lib/src/main/ +!/src/commands/manifest/scripts/test/maven-compat/project/lib/src/main/java/ +!/src/commands/manifest/scripts/test/maven-compat/project/lib/src/main/java/demo/ +!/src/commands/manifest/scripts/test/maven-compat/project/mid/ +!/src/commands/manifest/scripts/test/maven-compat/project/mid/src/ +!/src/commands/manifest/scripts/test/maven-compat/project/mid/src/main/ +!/src/commands/manifest/scripts/test/maven-compat/project/mid/src/main/java/ +!/src/commands/manifest/scripts/test/maven-compat/project/mid/src/main/java/demo/ +!/src/commands/manifest/scripts/test/maven-compat/repo-inheritance/ +!/src/commands/manifest/scripts/test/maven-compat/repo-inheritance/liba/ +!/src/commands/manifest/scripts/test/maven-compat/repo-inheritance/libb/ +!/src/commands/manifest/scripts/test/sbt-compat/ +!/src/commands/manifest/scripts/test/sbt-compat/artifact-failure/ +!/src/commands/manifest/scripts/test/sbt-compat/exclude-base/ +!/src/commands/manifest/scripts/test/sbt-compat/exclude-base/app/ +!/src/commands/manifest/scripts/test/sbt-compat/failure/ +!/src/commands/manifest/scripts/test/sbt-compat/project/ +!/src/commands/manifest/scripts/test/sbt-compat/project/src/ +!/src/commands/manifest/scripts/test/sbt-compat/project/src/main/ +!/src/commands/manifest/scripts/test/sbt-compat/project/src/main/scala/ +!/src/commands/manifest/scripts/test/sbt-compat/relocation/ +!/src/commands/npm/ +!/src/commands/npx/ +!/src/commands/oops/ +!/src/commands/optimize/ +!/src/commands/organization/ +!/src/commands/package/ +!/src/commands/package/fixtures/ +!/src/commands/patch/ +!/src/commands/pnpm/ +!/src/commands/raw-npm/ +!/src/commands/raw-npx/ +!/src/commands/repository/ +!/src/commands/scan/ +!/src/commands/threat-feed/ +!/src/commands/uninstall/ +!/src/commands/wrapper/ +!/src/commands/yarn/ +!/src/external/ +!/src/external/blessed-contrib/ +!/src/external/blessed-contrib/lib/ +!/src/external/blessed-contrib/lib/layout/ +!/src/external/blessed-contrib/lib/widget/ +!/src/external/blessed-contrib/lib/widget/charts/ +!/src/sea/ +!/src/sea/archive-paths.mts +!/src/sea/adapters/ +!/src/sea/build-lock.mts +!/src/sea/build-sea.test.mts +!/src/sea/capabilities.mts +!/src/sea/runtime.test.mts +!/src/sea/licenses/ +!/src/sea/licenses/cdxgen-third-party/ +!/src/sea/licenses/core-third-party/ +!/src/shadow/ +!/src/shadow/npm/ +!/src/shadow/npm/arborist/ +!/src/shadow/npm/arborist/lib/ +!/src/shadow/npm/arborist/lib/arborist/ +!/src/shadow/npx/ +!/src/shadow/pnpm/ +!/src/shadow/yarn/ +!/src/test/ +!/src/test/mocks/ +!/src/utils/ +!/src/utils/packages.test.mts +!/src/utils/alert/ +!/src/utils/telemetry/ +!/src/vendor/ +!/test/ +!/test/package-matrix.test.mts +!/test/fixtures/ +!/test/fixtures/commands/ +!/test/fixtures/commands/cdxgen/ +!/test/fixtures/commands/fix/ +!/test/fixtures/commands/fix/e2e-test-js/ +!/test/fixtures/commands/fix/e2e-test-multipm/ +!/test/fixtures/commands/fix/e2e-test-multipm/npm-app/ +!/test/fixtures/commands/fix/e2e-test-multipm/pnpm-app/ +!/test/fixtures/commands/fix/e2e-test-py/ +!/test/fixtures/commands/fix/npm/ +!/test/fixtures/commands/fix/npm/monorepo/ +!/test/fixtures/commands/fix/npm/monorepo/packages/ +!/test/fixtures/commands/fix/npm/monorepo/packages/app/ +!/test/fixtures/commands/fix/npm/monorepo/packages/lib/ +!/test/fixtures/commands/fix/npm/vulnerable-deps/ +!/test/fixtures/commands/fix/pnpm/ +!/test/fixtures/commands/fix/pnpm/monorepo/ +!/test/fixtures/commands/fix/pnpm/monorepo/packages/ +!/test/fixtures/commands/fix/pnpm/monorepo/packages/app/ +!/test/fixtures/commands/fix/pnpm/monorepo/packages/lib/ +!/test/fixtures/commands/fix/pnpm/vulnerable-deps/ +!/test/fixtures/commands/fix/yarn/ +!/test/fixtures/commands/fix/yarn/monorepo/ +!/test/fixtures/commands/fix/yarn/monorepo/packages/ +!/test/fixtures/commands/fix/yarn/monorepo/packages/app/ +!/test/fixtures/commands/fix/yarn/monorepo/packages/lib/ +!/test/fixtures/commands/fix/yarn/vulnerable-deps/ +!/test/fixtures/commands/json/ +!/test/fixtures/commands/manifest/ +!/test/fixtures/commands/manifest/conda/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/dual-marker-dir/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleA/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleA/nested-gradle/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleB/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleB/independent-submodule/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/standalone-gradle/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/bare/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/upper/ +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/vendored/ +!/test/fixtures/commands/manifest/python/ +!/test/fixtures/commands/npm/ +!/test/fixtures/commands/npm/lacking-typosquat/ +!/test/fixtures/commands/npm/npm10/ +!/test/fixtures/commands/npm/npm11/ +!/test/fixtures/commands/npm/npm9/ +!/test/fixtures/commands/optimize/ +!/test/fixtures/commands/optimize/npm/ +!/test/fixtures/commands/optimize/pnpm/ +!/test/fixtures/commands/optimize/pnpm8/ +!/test/fixtures/commands/optimize/pnpm9/ +!/test/fixtures/commands/optimize/yarn/ +!/test/fixtures/commands/patch/ +!/test/fixtures/commands/patch/npm/ +!/test/fixtures/commands/patch/npm/.socket/ +!/test/fixtures/commands/patch/npm/.socket/blobs/ +!/test/fixtures/commands/patch/pnpm/ +!/test/fixtures/commands/patch/pnpm/.socket/ +!/test/fixtures/commands/patch/pnpm/.socket/blobs/ +!/test/fixtures/commands/patch/yarn/ +!/test/fixtures/commands/patch/yarn/.socket/ +!/test/fixtures/commands/patch/yarn/.socket/blobs/ +!/test/fixtures/commands/scan/ +!/test/fixtures/commands/scan/npm-test-workspace-mono/ +!/test/fixtures/commands/scan/npm-test-workspace-mono/packages/ +!/test/fixtures/commands/scan/npm-test-workspace-mono/packages/package-a/ +!/test/fixtures/commands/scan/npm-test-workspace-mono/packages/package-b/ +!/test/fixtures/commands/scan/plain-requirements-txt/ +!/test/fixtures/commands/scan/simple-npm/ +!/test/fixtures/commands/scan/uv-workspace/ +!/test/fixtures/commands/scan/uv-workspace/packages/ +!/test/fixtures/commands/scan/uv-workspace/packages/api/ +!/test/fixtures/commands/scan/uv-workspace/packages/other/ +!/test/fixtures/commands/scan/uv-workspace/packages/shared/ +!/test/fixtures/manifest-bazel/ +!/test/fixtures/manifest-bazel/bzlmod-only/ +!/test/fixtures/manifest-bazel/custom-name-bzlmod/ +!/test/fixtures/manifest-bazel/legacy-only/ +!/test/fixtures/manifest-bazel/legacy-with-load/ +!/test/fixtures/manifest-bazel/migration/ +!/test/fixtures/manifest-bazel/multi-repo-bzlmod/ +!/test/fixtures/manifest-bazel/native/ +!/test/fixtures/manifest-bazel/native/bzlmod/ +!/test/fixtures/manifest-bazel/native/workspace/ +!/test/fixtures/manifest-bazel/python-pypi/ +!/.claude/skills/bump-coana/SKILL.md +!/.config/babel.config.js +!/.config/rollup.base.config.mjs +!/.config/rollup.cdxgen-sea.config.mjs +!/.config/rollup.dist.config.mjs +!/.config/rollup.sea.config.mjs +!/.config/rollup.synp-sea.config.mjs +!/.config/tsconfig.base.json +!/.editorconfig +!/.env.dist +!/.env.external +!/.env.test +!/.env.testu +!/.gitattributes +!/.gitignore +!/.husky/commit-msg +!/.husky/pre-commit +!/.npmrc +!/.oxlintignore +!/.oxlintrc.json +!/.pnpmrc +!/.vscode/extensions.json +!/CHANGELOG.md +!/CLAUDE.md +!/DISCLOSURE +!/LICENSE +!/README.md +!/assets/fleet/badge-follow-bluesky.svg +!/assets/fleet/badge-follow-x.svg +!/assets/fleet/socket-combomark-dark.svg +!/assets/fleet/socket-combomark-light.svg +!/bin/cli.js +!/bin/npm-cli.js +!/bin/npx-cli.js +!/bin/pnpm-cli.js +!/bin/yarn-cli.js +!/biome.json +!/docs/plans/node27-sea-vfs-socket-package.md +!/eslint.config.js +!/knip.json +!/package.json +!/patches/@rollup__plugin-commonjs@28.0.6.patch +!/patches/ansi-term@0.0.2.patch +!/patches/blessed-contrib@4.11.0.patch +!/patches/blessed@0.1.81.patch +!/patches/brace-expansion@2.0.2.patch +!/patches/bresenham@0.0.3.patch +!/patches/drawille-blessed-contrib@1.0.0.patch +!/patches/drawille-canvas-blessed-contrib@0.1.3.patch +!/patches/graceful-fs@4.2.11.patch +!/patches/lodash@4.17.21.patch +!/patches/meow@13.2.0.patch +!/patches/rollup@4.50.1.patch +!/patches/string_decoder@0.10.31.patch +!/patches/tiny-updater@3.5.3.patch +!/pnpm-lock.yaml +!/requirements.json +!/scripts/babel/transform-set-proto-plugin.js +!/scripts/babel/transform-url-parse-plugin.js +!/scripts/check-commit-pii.js +!/scripts/check.mts +!/scripts/ci/check-actions.mts +!/scripts/ci/setup-node.mjs +!/scripts/ci/setup-uv.mts +!/scripts/ci/upload-artifact.mjs +!/scripts/constants.js +!/scripts/lib/is-main-module.mts +!/scripts/lib/linters.mts +!/scripts/lib/run-main.mts +!/scripts/lib/scope.mts +!/scripts/lint.mts +!/scripts/release/add-unreleased.mts +!/scripts/release/bump.mts +!/scripts/release/changelog.mts +!/scripts/release/github-api.mts +!/scripts/release/history.mts +!/scripts/release/mint-app-token.mjs +!/scripts/release/open-release-pr.mts +!/scripts/release/preflight.mts +!/scripts/release/registry.mts +!/scripts/release/release-branch.mts +!/scripts/release/version.mts +!/scripts/rollup/socket-modify-plugin.js +!/scripts/sea/release/apple/capture.mts +!/scripts/test/native.mts +!/scripts/test/integration.mts +!/scripts/update.mts +!/scripts/utils/fs.js +!/scripts/utils/packages.js +!/scripts/utils/registry-helpers.js +!/sd +!/shadow-bin/npm +!/shadow-bin/npx +!/shadow-bin/pnpm +!/shadow-bin/yarn +!/socket.yml +!/src/cli.mts +!/src/commands.mts +!/src/commands/analytics/analytics-fixture.json +!/src/commands/analytics/cmd-analytics.mts +!/src/commands/analytics/cmd-analytics.test.mts +!/src/commands/analytics/fetch-org-analytics.mts +!/src/commands/analytics/fetch-repo-analytics.mts +!/src/commands/analytics/handle-analytics.mts +!/src/commands/analytics/output-analytics.mts +!/src/commands/analytics/output-analytics.test.mts +!/src/commands/audit-log/audit-fixture.json +!/src/commands/audit-log/cmd-audit-log.mts +!/src/commands/audit-log/cmd-audit-log.test.mts +!/src/commands/audit-log/fetch-audit-log.mts +!/src/commands/audit-log/handle-audit-log.mts +!/src/commands/audit-log/output-audit-log.mts +!/src/commands/audit-log/output-audit-log.test.mts +!/src/commands/cdxgen/cmd-cdxgen.test.mts +!/src/commands/ci/cmd-ci.mts +!/src/commands/ci/cmd-ci.test.mts +!/src/commands/ci/fetch-default-org-slug.mts +!/src/commands/ci/fetch-default-org-slug.test.mts +!/src/commands/ci/handle-ci.mts +!/src/commands/ci/handle-ci.test.mts +!/src/commands/cli.test.mts +!/src/commands/cli.integration.test.mts +!/src/commands/config/cmd-config-auto.mts +!/src/commands/config/cmd-config-auto.test.mts +!/src/commands/config/cmd-config-get.mts +!/src/commands/config/cmd-config-get.test.mts +!/src/commands/config/cmd-config-list.mts +!/src/commands/config/cmd-config-list.test.mts +!/src/commands/config/cmd-config-set.mts +!/src/commands/config/cmd-config-set.test.mts +!/src/commands/config/cmd-config-unset.mts +!/src/commands/config/cmd-config-unset.test.mts +!/src/commands/config/cmd-config.mts +!/src/commands/config/cmd-config.test.mts +!/src/commands/config/discover-config-value.mts +!/src/commands/config/handle-config-auto.mts +!/src/commands/config/handle-config-get.mts +!/src/commands/config/handle-config-set.mts +!/src/commands/config/handle-config-unset.mts +!/src/commands/config/output-config-auto.mts +!/src/commands/config/output-config-get.mts +!/src/commands/config/output-config-list.mts +!/src/commands/config/output-config-set.mts +!/src/commands/config/output-config-unset.mts +!/src/commands/fix/branch-cleanup.integration.test.mts +!/src/commands/fix/branch-cleanup.mts +!/src/commands/fix/branch-cleanup.test.mts +!/src/commands/fix/cmd-fix.e2e.test.mts +!/src/commands/fix/cmd-fix.integration.test.mts +!/src/commands/fix/cmd-fix.mts +!/src/commands/fix/coana-fix-dynamic-sbom-inference.test.mts +!/src/commands/fix/coana-fix-pr-files.test.mts +!/src/commands/fix/coana-fix.mts +!/src/commands/fix/env-helpers.mts +!/src/commands/fix/env-helpers.test.mts +!/src/commands/fix/generated-socket-facts.mts +!/src/commands/fix/generated-socket-facts.test.mts +!/src/commands/fix/git.mts +!/src/commands/fix/handle-fix-id.test.mts +!/src/commands/fix/handle-fix-limit.test.mts +!/src/commands/fix/handle-fix.mts +!/src/commands/fix/output-fix-result.mts +!/src/commands/fix/pull-request.mts +!/src/commands/fix/types.mts +!/src/commands/install/cmd-install-completion.mts +!/src/commands/install/cmd-install-completion.test.mts +!/src/commands/install/cmd-install.mts +!/src/commands/install/cmd-install.test.mts +!/src/commands/install/handle-install-completion.mts +!/src/commands/install/output-install-completion.mts +!/src/commands/install/setup-tab-completion.mts +!/src/commands/install/socket-completion.bash +!/src/commands/json/cmd-json.mts +!/src/commands/json/cmd-json.test.mts +!/src/commands/json/cmd-json.integration.test.mts +!/src/commands/json/handle-cmd-json.mts +!/src/commands/json/output-cmd-json.mts +!/src/commands/login/apply-login.mts +!/src/commands/login/attempt-login.mts +!/src/commands/login/cmd-login-smoke.test.mts +!/src/commands/login/cmd-login.mts +!/src/commands/login/cmd-login.test.mts +!/src/commands/logout/apply-logout.mts +!/src/commands/logout/attempt-logout.mts +!/src/commands/logout/cmd-logout.mts +!/src/commands/logout/cmd-logout.test.mts +!/src/commands/manifest/README.md +!/src/commands/manifest/bazel/bazel-bin-detect.mts +!/src/commands/manifest/bazel/bazel-bin-detect.test.mts +!/src/commands/manifest/bazel/bazel-cleanup.mts +!/src/commands/manifest/bazel/bazel-cquery.mts +!/src/commands/manifest/bazel/bazel-cquery.test.mts +!/src/commands/manifest/bazel/bazel-java-shim.mts +!/src/commands/manifest/bazel/bazel-java-shim.test.mts +!/src/commands/manifest/bazel/bazel-native.e2e.test.mts +!/src/commands/manifest/bazel/bazel-output-base-check.mts +!/src/commands/manifest/bazel/bazel-output-base-check.test.mts +!/src/commands/manifest/bazel/bazel-process.mts +!/src/commands/manifest/bazel/bazel-process.test.mts +!/src/commands/manifest/bazel/bazel-pypi-discovery.mts +!/src/commands/manifest/bazel/bazel-pypi-discovery.test.mts +!/src/commands/manifest/bazel/bazel-pypi-parser.mts +!/src/commands/manifest/bazel/bazel-pypi-parser.test.mts +!/src/commands/manifest/bazel/bazel-python-shim.mts +!/src/commands/manifest/bazel/bazel-python-shim.test.mts +!/src/commands/manifest/bazel/bazel-query-runner.mts +!/src/commands/manifest/bazel/bazel-query-runner.test.mts +!/src/commands/manifest/bazel/bazel-repo-discovery.mts +!/src/commands/manifest/bazel/bazel-repo-discovery.test.mts +!/src/commands/manifest/bazel/bazel-workspace-detect.mts +!/src/commands/manifest/bazel/bazel-workspace-detect.test.mts +!/src/commands/manifest/bazel/bazel-workspace-walk.mts +!/src/commands/manifest/bazel/bazel-workspace-walk.test.mts +!/src/commands/manifest/bazel/cmd-manifest-bazel.mts +!/src/commands/manifest/bazel/cmd-manifest-bazel.test.mts +!/src/commands/manifest/bazel/extract_bazel_to_maven.mts +!/src/commands/manifest/bazel/extract_bazel_to_maven.test.mts +!/src/commands/manifest/bazel/extract_bazel_to_pypi.constructed.test.mts +!/src/commands/manifest/bazel/extract_bazel_to_pypi.mts +!/src/commands/manifest/bazel/extract_bazel_to_pypi.test.mts +!/src/commands/manifest/cmd-manifest-auto.mts +!/src/commands/manifest/cmd-manifest-auto.test.mts +!/src/commands/manifest/cmd-manifest-auto.integration.test.mts +!/src/commands/native-cli.native.test.mts +!/src/commands/manifest/cmd-manifest-cdxgen.mts +!/src/commands/manifest/cmd-manifest-cdxgen.test.mts +!/src/commands/manifest/cmd-manifest-conda.mts +!/src/commands/manifest/cmd-manifest-conda.test.mts +!/src/commands/manifest/cmd-manifest-dotnet.mts +!/src/commands/manifest/cmd-manifest-dotnet.test.mts +!/src/commands/manifest/cmd-manifest-dynamic-sbom-inference.mts +!/src/commands/manifest/cmd-manifest-dynamic-sbom-inference.test.mts +!/src/commands/manifest/cmd-manifest-gradle.mts +!/src/commands/manifest/cmd-manifest-gradle.test.mts +!/src/commands/manifest/cmd-manifest-kotlin.mts +!/src/commands/manifest/cmd-manifest-kotlin.test.mts +!/src/commands/manifest/cmd-manifest-maven.mts +!/src/commands/manifest/cmd-manifest-maven.test.mts +!/src/commands/manifest/cmd-manifest-scala.mts +!/src/commands/manifest/cmd-manifest-scala.test.mts +!/src/commands/manifest/cmd-manifest-setup.mts +!/src/commands/manifest/cmd-manifest-setup.test.mts +!/src/commands/manifest/cmd-manifest.mts +!/src/commands/manifest/cmd-manifest.test.mts +!/src/commands/manifest/convert-conda-to-requirements.mts +!/src/commands/manifest/convert-conda-to-requirements.test.mts +!/src/commands/manifest/convert-dotnet-to-facts.mts +!/src/commands/manifest/convert-gradle-to-facts.mts +!/src/commands/manifest/convert-maven-to-facts.mts +!/src/commands/manifest/convert-sbt-to-facts.mts +!/src/commands/manifest/convert_gradle_to_maven.mts +!/src/commands/manifest/convert_sbt_to_maven.mts +!/src/commands/manifest/detect-manifest-actions.mts +!/src/commands/manifest/detect-manifest-actions.test.mts +!/src/commands/manifest/discover-manifest-roots.mts +!/src/commands/manifest/discover-manifest-roots.test.mts +!/src/commands/manifest/enumerate-workspaces.mts +!/src/commands/manifest/enumerate-workspaces.test.mts +!/src/commands/manifest/expand-env-var-refs.mts +!/src/commands/manifest/expand-env-var-refs.test.mts +!/src/commands/manifest/generate-recursive-manifests.mts +!/src/commands/manifest/generate-recursive-manifests.test.mts +!/src/commands/manifest/generate_auto_manifest.mts +!/src/commands/manifest/generate_auto_manifest.test.mts +!/src/commands/manifest/handle-manifest-conda.mts +!/src/commands/manifest/handle-manifest-dynamic-sbom-inference.mts +!/src/commands/manifest/handle-manifest-dynamic-sbom-inference.test.mts +!/src/commands/manifest/handle-manifest-setup.mts +!/src/commands/manifest/init.gradle +!/src/commands/manifest/manifest-flags.mts +!/src/commands/manifest/output-manifest-dynamic-sbom-inference.mts +!/src/commands/manifest/output-manifest-setup.mts +!/src/commands/manifest/output-requirements.mts +!/src/commands/manifest/parse-build-tool-opts.mts +!/src/commands/manifest/parse-build-tool-opts.test.mts +!/src/commands/manifest/run-cdxgen.mts +!/src/commands/manifest/run-manifest-facts.mts +!/src/commands/manifest/run-manifest-facts.test.mts +!/src/commands/manifest/scripts/assemble.mts +!/src/commands/manifest/scripts/assemble.test.mts +!/src/commands/manifest/scripts/build-tool.mts +!/src/commands/manifest/scripts/build-tool.test.mts +!/src/commands/manifest/scripts/dotnet-tool/.gitignore +!/src/commands/manifest/scripts/dotnet-tool/FactsRunner.cs +!/src/commands/manifest/scripts/dotnet-tool/NuGetShim.cs +!/src/commands/manifest/scripts/dotnet-tool/Patterns.cs +!/src/commands/manifest/scripts/dotnet-tool/Program.cs +!/src/commands/manifest/scripts/dotnet-tool/Reader.cs +!/src/commands/manifest/scripts/dotnet-tool/RecordsWriter.cs +!/src/commands/manifest/scripts/dotnet-tool/Restorer.cs +!/src/commands/manifest/scripts/dotnet-tool/SolutionContext.cs +!/src/commands/manifest/scripts/dotnet-tool/ToolOptions.cs +!/src/commands/manifest/scripts/dotnet-tool/build-tool.sh +!/src/commands/manifest/scripts/dotnet-tool/packages.lock.json +!/src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csproj +!/src/commands/manifest/scripts/exclude-paths-glob.mts +!/src/commands/manifest/scripts/exclude-paths-glob.test.mts +!/src/commands/manifest/scripts/facts.mts +!/src/commands/manifest/scripts/maven-extension/.gitignore +!/src/commands/manifest/scripts/maven-extension/.mvn/wrapper/maven-wrapper.properties +!/src/commands/manifest/scripts/maven-extension/build-jar.sh +!/src/commands/manifest/scripts/maven-extension/mvnw +!/src/commands/manifest/scripts/maven-extension/mvnw.cmd +!/src/commands/manifest/scripts/maven-extension/pom.xml +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/ext/CoanaFactsEventSpy.java +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/ext/CoanaFactsLifecycleParticipant.java +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/ext/CoanaWorkspacesLifecycleParticipant.java +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/CollectionObserver.java +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketFactsRecordsEngine.java +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketSupport.java +!/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketWorkspacesRecordsEngine.java +!/src/commands/manifest/scripts/records.mts +!/src/commands/manifest/scripts/resolution-report-gradle.mts +!/src/commands/manifest/scripts/resolution-report-ivy.mts +!/src/commands/manifest/scripts/resolution-report-maven.mts +!/src/commands/manifest/scripts/resolution-report-nuget.mts +!/src/commands/manifest/scripts/resolution-report-nuget.test.mts +!/src/commands/manifest/scripts/resolution-report-render.mts +!/src/commands/manifest/scripts/resolution-report-render.test.mts +!/src/commands/manifest/scripts/resolution-report.mts +!/src/commands/manifest/scripts/run.mts +!/src/commands/manifest/scripts/run.test.mts +!/src/commands/manifest/scripts/sidecar.mts +!/src/commands/manifest/scripts/sidecar.test.mts +!/src/commands/manifest/scripts/socket-facts.init.gradle +!/src/commands/manifest/scripts/socket-facts.plugin.scala +!/src/commands/manifest/scripts/socket-workspaces.init.gradle +!/src/commands/manifest/scripts/socket-workspaces.plugin.scala +!/src/commands/manifest/scripts/test/README.md +!/src/commands/manifest/scripts/test/assert-reachability.py +!/src/commands/manifest/scripts/test/compat-cache.sh +!/src/commands/manifest/scripts/test/dotnet-compat/.gitignore +!/src/commands/manifest/scripts/test/dotnet-compat/assert-dotnet-list.py +!/src/commands/manifest/scripts/test/dotnet-compat/assert-facts.py +!/src/commands/manifest/scripts/test/dotnet-compat/basic/Basic.sln +!/src/commands/manifest/scripts/test/dotnet-compat/basic/shared/Linked.cs +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/App/App.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/App/Program.cs +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/Extra/E.cs +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/Extra/Extra.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/Lib/L.cs +!/src/commands/manifest/scripts/test/dotnet-compat/basic/src/Lib/Lib.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/basic/test/App.Tests/App.Tests.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/basic/test/App.Tests/T.cs +!/src/commands/manifest/scripts/test/dotnet-compat/basic/tools/Nuke/Nuke.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/Cpm.slnx +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/Directory.Build.props +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/Directory.Packages.props +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/Api/A.cs +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/Api/Api.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/Core/C.cs +!/src/commands/manifest/scripts/test/dotnet-compat/cpm/src/Core/Core.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/dev/Dev.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/dev/Program.cs +!/src/commands/manifest/scripts/test/dotnet-compat/evaluation/Build.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/evaluation/Lib/Class.cs +!/src/commands/manifest/scripts/test/dotnet-compat/evaluation/Lib/Lib.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/app/App.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/app/App.sln +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/app/core/Core.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/exclude-base/shared/Shared.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/failures/broken/Broken.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/failures/missing/Missing.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Fs/First.fs +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Fs/Fs.fsproj +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Fs/Library.fs +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Vb/V.vb +!/src/commands/manifest/scripts/test/dotnet-compat/langs/Vb/Vb.vbproj +!/src/commands/manifest/scripts/test/dotnet-compat/lib.sh +!/src/commands/manifest/scripts/test/dotnet-compat/make-stub-feed.py +!/src/commands/manifest/scripts/test/dotnet-compat/multi/One.sln +!/src/commands/manifest/scripts/test/dotnet-compat/multi/One.slnx +!/src/commands/manifest/scripts/test/dotnet-compat/multi/One/One.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/multi/Stray.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/multi/Two.sln +!/src/commands/manifest/scripts/test/dotnet-compat/multi/Two/Two.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/nuget.config +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Legacy/Class1.cs +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Legacy/Legacy.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Legacy/Properties/AssemblyInfo.cs +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Legacy/packages.config +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Mixed.sln +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Modern/M.cs +!/src/commands/manifest/scripts/test/dotnet-compat/packages-config/Modern/Modern.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/pair/A.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/pair/B.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/rid/R.cs +!/src/commands/manifest/scripts/test/dotnet-compat/rid/Rid.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/sln/All.sln +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/src/A/A.cs +!/src/commands/manifest/scripts/test/dotnet-compat/sibling/src/A/A.csproj +!/src/commands/manifest/scripts/test/dotnet-compat/smoke-test-exclude-base.sh +!/src/commands/manifest/scripts/test/dotnet-compat/smoke-test-workspaces.sh +!/src/commands/manifest/scripts/test/dotnet-compat/smoke-test.sh +!/src/commands/manifest/scripts/test/gradle-compat/.gitignore +!/src/commands/manifest/scripts/test/gradle-compat/README.md +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/app/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/app/core/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/app/settings.gradle +!/src/commands/manifest/scripts/test/gradle-compat/exclude-base/shared/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/failures/app/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/failures/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/failures/gradle/verification-metadata.xml +!/src/commands/manifest/scripts/test/gradle-compat/failures/lib/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/failures/settings.gradle +!/src/commands/manifest/scripts/test/gradle-compat/failures/transforms.gradle +!/src/commands/manifest/scripts/test/gradle-compat/project/build.gradle +!/src/commands/manifest/scripts/test/gradle-compat/project/settings.gradle +!/src/commands/manifest/scripts/test/gradle-compat/smoke-test-exclude-base.sh +!/src/commands/manifest/scripts/test/gradle-compat/smoke-test-failures.sh +!/src/commands/manifest/scripts/test/gradle-compat/smoke-test-workspaces.sh +!/src/commands/manifest/scripts/test/gradle-compat/smoke-test.sh +!/src/commands/manifest/scripts/test/make-stub-repo.sh +!/src/commands/manifest/scripts/test/maven-compat/.gitignore +!/src/commands/manifest/scripts/test/maven-compat/assert-fail-closed.py +!/src/commands/manifest/scripts/test/maven-compat/assert-no-invented-failures.py +!/src/commands/manifest/scripts/test/maven-compat/assert-records.py +!/src/commands/manifest/scripts/test/maven-compat/descriptor-failure/a/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/descriptor-failure/b/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/descriptor-failure/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/duplicate-failure/m1/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/duplicate-failure/m2/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/duplicate-failure/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/app/core/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/app/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/exclude-base/shared/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/graph-failure/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/project/app/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/project/app/src/main/java/demo/App.java +!/src/commands/manifest/scripts/test/maven-compat/project/lib/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/project/lib/src/main/java/demo/Lib.java +!/src/commands/manifest/scripts/test/maven-compat/project/mid/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/project/mid/src/main/java/demo/Mid.java +!/src/commands/manifest/scripts/test/maven-compat/project/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/repo-inheritance/liba/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/repo-inheritance/libb/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/repo-inheritance/pom.xml +!/src/commands/manifest/scripts/test/maven-compat/smoke-test-descriptor-failure.sh +!/src/commands/manifest/scripts/test/maven-compat/smoke-test-duplicate-failure.sh +!/src/commands/manifest/scripts/test/maven-compat/smoke-test-exclude-base.sh +!/src/commands/manifest/scripts/test/maven-compat/smoke-test-graph-failure.sh +!/src/commands/manifest/scripts/test/maven-compat/smoke-test-repo-inheritance.sh +!/src/commands/manifest/scripts/test/maven-compat/smoke-test-workspaces.sh +!/src/commands/manifest/scripts/test/maven-compat/smoke-test.sh +!/src/commands/manifest/scripts/test/run-compat.sh +!/src/commands/manifest/scripts/test/sbt-compat/.gitignore +!/src/commands/manifest/scripts/test/sbt-compat/artifact-failure/build.sbt +!/src/commands/manifest/scripts/test/sbt-compat/exclude-base/app/build.sbt +!/src/commands/manifest/scripts/test/sbt-compat/failure/build.sbt +!/src/commands/manifest/scripts/test/sbt-compat/project/Base.scala +!/src/commands/manifest/scripts/test/sbt-compat/project/build.sbt +!/src/commands/manifest/scripts/test/sbt-compat/project/src/main/scala/App.scala +!/src/commands/manifest/scripts/test/sbt-compat/relocation/build.sbt +!/src/commands/manifest/scripts/test/sbt-compat/smoke-test-exclude-base.sh +!/src/commands/manifest/scripts/test/sbt-compat/smoke-test-failure.sh +!/src/commands/manifest/scripts/test/sbt-compat/smoke-test-relocation.sh +!/src/commands/manifest/scripts/test/sbt-compat/smoke-test-workspaces.sh +!/src/commands/manifest/scripts/test/sbt-compat/smoke-test.sh +!/src/commands/manifest/setup-manifest-config.mts +!/src/commands/manifest/setup-manifest-config.test.mts +!/src/commands/manifest/setup-recursive-manifest-config.mts +!/src/commands/manifest/setup-recursive-manifest-config.test.mts +!/src/commands/npm/cmd-npm-malware.test.mts +!/src/commands/npm/cmd-npm.mts +!/src/commands/npm/cmd-npm.test.mts +!/src/commands/npm/socket-npm-integration.test.mts +!/src/commands/npx/cmd-npx-malware.test.mts +!/src/commands/npx/cmd-npx.mts +!/src/commands/npx/cmd-npx.test.mts +!/src/commands/oops/cmd-oops.mts +!/src/commands/oops/cmd-oops.test.mts +!/src/commands/optimize/add-overrides.mts +!/src/commands/optimize/apply-optimization.mts +!/src/commands/optimize/cmd-optimize-pnpm-versions.test.mts +!/src/commands/optimize/cmd-optimize.mts +!/src/commands/optimize/cmd-optimize.test.mts +!/src/commands/optimize/deps-includes-by-agent.mts +!/src/commands/optimize/get-dependency-entries.mts +!/src/commands/optimize/get-overrides-by-agent.mts +!/src/commands/optimize/handle-optimize.mts +!/src/commands/optimize/lockfile-includes-by-agent.mts +!/src/commands/optimize/ls-by-agent.mts +!/src/commands/optimize/output-optimize-result.mts +!/src/commands/optimize/shared.mts +!/src/commands/optimize/types.mts +!/src/commands/optimize/update-lockfile.mts +!/src/commands/optimize/update-manifest-by-agent.mts +!/src/commands/optimize/update-manifest-by-agent.test.mts +!/src/commands/organization/cmd-organization-dependencies.mts +!/src/commands/organization/cmd-organization-dependencies.test.mts +!/src/commands/organization/cmd-organization-list.mts +!/src/commands/organization/cmd-organization-list.test.mts +!/src/commands/organization/cmd-organization-policy-license.mts +!/src/commands/organization/cmd-organization-policy-license.test.mts +!/src/commands/organization/cmd-organization-policy-security.mts +!/src/commands/organization/cmd-organization-policy-security.test.mts +!/src/commands/organization/cmd-organization-policy.mts +!/src/commands/organization/cmd-organization-policy.test.mts +!/src/commands/organization/cmd-organization-quota.mts +!/src/commands/organization/cmd-organization-quota.test.mts +!/src/commands/organization/cmd-organization.mts +!/src/commands/organization/cmd-organization.test.mts +!/src/commands/organization/fetch-dependencies.mts +!/src/commands/organization/fetch-license-policy.mts +!/src/commands/organization/fetch-organization-list.mts +!/src/commands/organization/fetch-quota.mts +!/src/commands/organization/fetch-security-policy.mts +!/src/commands/organization/handle-dependencies.mts +!/src/commands/organization/handle-dependencies.test.mts +!/src/commands/organization/handle-license-policy.mts +!/src/commands/organization/handle-organization-list.mts +!/src/commands/organization/handle-quota.mts +!/src/commands/organization/handle-quota.test.mts +!/src/commands/organization/handle-security-policy.mts +!/src/commands/organization/output-dependencies.mts +!/src/commands/organization/output-license-policy.mts +!/src/commands/organization/output-organization-list.mts +!/src/commands/organization/output-quota.mts +!/src/commands/organization/output-security-policy.mts +!/src/commands/package/cmd-package-score.mts +!/src/commands/package/cmd-package-score.test.mts +!/src/commands/package/cmd-package-shallow.mts +!/src/commands/package/cmd-package-shallow.test.mts +!/src/commands/package/cmd-package.mts +!/src/commands/package/cmd-package.test.mts +!/src/commands/package/fetch-purl-deep-score.mts +!/src/commands/package/fetch-purls-shallow-score.mts +!/src/commands/package/fixtures/go_deep.json +!/src/commands/package/fixtures/go_shallow.json +!/src/commands/package/fixtures/maven_deep.json +!/src/commands/package/fixtures/maven_shallow.json +!/src/commands/package/fixtures/npm_deep.json +!/src/commands/package/fixtures/npm_malware.json +!/src/commands/package/fixtures/npm_shallow.json +!/src/commands/package/fixtures/nuget_deep.json +!/src/commands/package/fixtures/nuget_shallow.json +!/src/commands/package/fixtures/python_deep.json +!/src/commands/package/fixtures/python_dupes.json +!/src/commands/package/fixtures/python_shallow.json +!/src/commands/package/fixtures/ruby_deep.json +!/src/commands/package/fixtures/ruby_shallow.json +!/src/commands/package/handle-purl-deep-score.mts +!/src/commands/package/handle-purls-shallow-score.mts +!/src/commands/package/output-purls-deep-score.mts +!/src/commands/package/output-purls-deep-score.test.mts +!/src/commands/package/output-purls-shallow-malware.test.mts +!/src/commands/package/output-purls-shallow-score.mts +!/src/commands/package/output-purls-shallow-score.test.mts +!/src/commands/package/parse-package-specifiers.mts +!/src/commands/package/parse-package-specifiers.test.mts +!/src/commands/patch/cmd-patch.mts +!/src/commands/pnpm/cmd-pnpm-malware.test.mts +!/src/commands/pnpm/cmd-pnpm.mts +!/src/commands/pnpm/cmd-pnpm.test.mts +!/src/commands/raw-npm/cmd-raw-npm.mts +!/src/commands/raw-npm/cmd-raw-npm.test.mts +!/src/commands/raw-npm/run-raw-npm.mts +!/src/commands/raw-npx/cmd-raw-npx.mts +!/src/commands/raw-npx/cmd-raw-npx.test.mts +!/src/commands/raw-npx/run-raw-npx.mts +!/src/commands/repository/cmd-repository-create.mts +!/src/commands/repository/cmd-repository-create.test.mts +!/src/commands/repository/cmd-repository-del.mts +!/src/commands/repository/cmd-repository-del.test.mts +!/src/commands/repository/cmd-repository-list.mts +!/src/commands/repository/cmd-repository-list.test.mts +!/src/commands/repository/cmd-repository-smoke.test.mts +!/src/commands/repository/cmd-repository-update.mts +!/src/commands/repository/cmd-repository-update.test.mts +!/src/commands/repository/cmd-repository-view.mts +!/src/commands/repository/cmd-repository-view.test.mts +!/src/commands/repository/cmd-repository.mts +!/src/commands/repository/cmd-repository.test.mts +!/src/commands/repository/fetch-create-repo.mts +!/src/commands/repository/fetch-delete-repo.mts +!/src/commands/repository/fetch-list-all-repos.mts +!/src/commands/repository/fetch-list-repos.mts +!/src/commands/repository/fetch-update-repo.mts +!/src/commands/repository/fetch-view-repo.mts +!/src/commands/repository/handle-create-repo.mts +!/src/commands/repository/handle-delete-repo.mts +!/src/commands/repository/handle-list-repos.mts +!/src/commands/repository/handle-update-repo.mts +!/src/commands/repository/handle-view-repo.mts +!/src/commands/repository/output-create-repo.mts +!/src/commands/repository/output-delete-repo.mts +!/src/commands/repository/output-list-repos.mts +!/src/commands/repository/output-update-repo.mts +!/src/commands/repository/output-view-repo.mts +!/src/commands/repository/types.mts +!/src/commands/scan/cmd-scan-create.mts +!/src/commands/scan/cmd-scan-create.test.mts +!/src/commands/scan/cmd-scan-del.mts +!/src/commands/scan/cmd-scan-del.test.mts +!/src/commands/scan/cmd-scan-diff.mts +!/src/commands/scan/cmd-scan-diff.test.mts +!/src/commands/scan/cmd-scan-github.mts +!/src/commands/scan/cmd-scan-github.test.mts +!/src/commands/scan/cmd-scan-list.mts +!/src/commands/scan/cmd-scan-list.test.mts +!/src/commands/scan/cmd-scan-metadata.mts +!/src/commands/scan/cmd-scan-metadata.test.mts +!/src/commands/scan/cmd-scan-reach.e2e.test.mts +!/src/commands/scan/cmd-scan-reach.mts +!/src/commands/scan/cmd-scan-reach.test.mts +!/src/commands/scan/cmd-scan-report.mts +!/src/commands/scan/cmd-scan-report.test.mts +!/src/commands/scan/cmd-scan-setup.mts +!/src/commands/scan/cmd-scan-setup.test.mts +!/src/commands/scan/cmd-scan-view.mts +!/src/commands/scan/cmd-scan-view.test.mts +!/src/commands/scan/cmd-scan.mts +!/src/commands/scan/cmd-scan.test.mts +!/src/commands/scan/create-scan-from-github.mts +!/src/commands/scan/create-scan-from-github.test.mts +!/src/commands/scan/exclude-paths.mts +!/src/commands/scan/exclude-paths.test.mts +!/src/commands/scan/fetch-create-org-full-scan.mts +!/src/commands/scan/fetch-delete-org-full-scan.mts +!/src/commands/scan/fetch-diff-scan.mts +!/src/commands/scan/fetch-list-scans.mts +!/src/commands/scan/fetch-report-data.mts +!/src/commands/scan/fetch-scan-metadata.mts +!/src/commands/scan/fetch-scan.mts +!/src/commands/scan/fetch-scan.test.mts +!/src/commands/scan/fetch-supported-scan-file-names.mts +!/src/commands/scan/finalize-tier1-scan.mts +!/src/commands/scan/generate-report.mts +!/src/commands/scan/generate-report.test.mts +!/src/commands/scan/generate-uv-member-sboms.e2e.test.mts +!/src/commands/scan/generate-uv-member-sboms.mts +!/src/commands/scan/generate-uv-member-sboms.test.mts +!/src/commands/scan/handle-create-github-scan.mts +!/src/commands/scan/handle-create-new-scan.mts +!/src/commands/scan/handle-create-new-scan.test.mts +!/src/commands/scan/handle-delete-scan.mts +!/src/commands/scan/handle-diff-scan.mts +!/src/commands/scan/handle-list-scans.mts +!/src/commands/scan/handle-scan-config.mts +!/src/commands/scan/handle-scan-metadata.mts +!/src/commands/scan/handle-scan-reach.mts +!/src/commands/scan/handle-scan-reach.test.mts +!/src/commands/scan/handle-scan-report.mts +!/src/commands/scan/handle-scan-view.mts +!/src/commands/scan/output-create-new-scan.mts +!/src/commands/scan/output-create-new-scan.test.mts +!/src/commands/scan/output-delete-scan.mts +!/src/commands/scan/output-diff-scan.mts +!/src/commands/scan/output-list-scans.mts +!/src/commands/scan/output-scan-config-result.mts +!/src/commands/scan/output-scan-github.mts +!/src/commands/scan/output-scan-metadata.mts +!/src/commands/scan/output-scan-reach.mts +!/src/commands/scan/output-scan-reach.test.mts +!/src/commands/scan/output-scan-report.mts +!/src/commands/scan/output-scan-report.test.mts +!/src/commands/scan/output-scan-view.mts +!/src/commands/scan/perform-reachability-analysis.mts +!/src/commands/scan/perform-reachability-analysis.test.mts +!/src/commands/scan/reach-advisories.mts +!/src/commands/scan/reach-advisories.test.mts +!/src/commands/scan/reachability-flags.mts +!/src/commands/scan/reachability-flags.test.mts +!/src/commands/scan/reachability-units.mts +!/src/commands/scan/reachability-units.test.mts +!/src/commands/scan/run-dynamic-sbom-inference.mts +!/src/commands/scan/run-dynamic-sbom-inference.test.mts +!/src/commands/scan/setup-scan-config.mts +!/src/commands/scan/stream-scan.mts +!/src/commands/scan/suggest-org-slug.mts +!/src/commands/scan/suggest-to-persist-orgslug.mts +!/src/commands/scan/suggest_branch_slug.mts +!/src/commands/scan/suggest_target.mts +!/src/commands/scan/types.mts +!/src/commands/scan/validate-reachability-target.mts +!/src/commands/scan/warn-socket-json-only-flags.mts +!/src/commands/threat-feed/cmd-threat-feed.mts +!/src/commands/threat-feed/cmd-threat-feed.test.mts +!/src/commands/threat-feed/fetch-threat-feed.mts +!/src/commands/threat-feed/handle-threat-feed.mts +!/src/commands/threat-feed/output-threat-feed.mts +!/src/commands/threat-feed/types.mts +!/src/commands/uninstall/cmd-uninstall-completion.mts +!/src/commands/uninstall/cmd-uninstall-completion.test.mts +!/src/commands/uninstall/cmd-uninstall.mts +!/src/commands/uninstall/cmd-uninstall.test.mts +!/src/commands/uninstall/handle-uninstall-completion.mts +!/src/commands/uninstall/output-uninstall-completion.mts +!/src/commands/uninstall/teardown-tab-completion.mts +!/src/commands/wrapper/add-socket-wrapper.mts +!/src/commands/wrapper/check-socket-wrapper-setup.mts +!/src/commands/wrapper/cmd-wrapper.mts +!/src/commands/wrapper/cmd-wrapper.test.mts +!/src/commands/wrapper/postinstall-wrapper.mts +!/src/commands/wrapper/remove-socket-wrapper.mts +!/src/commands/yarn/cmd-yarn-malware.test.mts +!/src/commands/yarn/cmd-yarn.mts +!/src/commands/yarn/cmd-yarn.test.mts +!/src/constants.mts +!/src/external/blessed-contrib/lib/layout/grid.mjs +!/src/external/blessed-contrib/lib/widget/charts/bar.mjs +!/src/external/blessed-contrib/lib/widget/charts/line.mjs +!/src/external/blessed-contrib/lib/widget/table.mjs +!/src/flags.mts +!/src/instrument-with-sentry.mts +!/src/npm-cli.mts +!/src/npx-cli.mts +!/src/pnpm-cli.mts +!/src/registry-constants.mts +!/src/sea/README.md +!/src/sea/adapters/cdxgen-worker.mjs +!/src/sea/adapters/cdxgen.mts +!/src/sea/adapters/synp-worker.mjs +!/src/sea/adapters/synp.mts +!/src/sea/bootstrap.mts +!/src/sea/build-sea.mts +!/src/sea/licenses/cdxgen-third-party/boolbase-1.0.0-ISC.txt +!/src/sea/licenses/cdxgen-third-party/err-code-2.0.3-MIT.txt +!/src/sea/licenses/cdxgen-third-party/err-code-2.0.3-README.md +!/src/sea/licenses/cdxgen-third-party/imurmurhash-0.1.4-MIT.txt +!/src/sea/licenses/cdxgen-third-party/spdx-exceptions-2.5.0-CC-BY-3.0.txt +!/src/sea/licenses/cdxgen-third-party/spdx-exceptions-2.5.0-README.md +!/src/sea/licenses/cdxgen-third-party/spdx-license-ids-3.0.22-CC0-1.0.txt +!/src/sea/licenses/cdxgen-third-party/spdx-license-ids-3.0.22-README.md +!/src/sea/licenses/core-third-party/@npmcli-agent-3.0.0-README.md +!/src/sea/licenses/core-third-party/@npmcli-agent-4.0.0-README.md +!/src/sea/licenses/core-third-party/ansi-term-0.0.2-ISC.txt +!/src/sea/licenses/core-third-party/drawille-canvas-blessed-contrib-0.1.3-MIT.txt +!/src/sea/licenses/core-third-party/drawille-canvas-blessed-contrib-0.1.3-README.md +!/src/sea/licenses/core-third-party/npmcli-agent-3.0.0-ISC.txt +!/src/sea/licenses/core-third-party/npmcli-agent-4.0.0-ISC.txt +!/src/sea/licenses/core-third-party/sigstore-verify-3.1.1-Apache-2.0.txt +!/src/sea/licenses/core-third-party/sigstore-verify-3.1.1-README.md +!/src/sea/licenses/core-third-party/x256-0.0.2-MIT.txt +!/src/sea/licenses/core-third-party/x256-0.0.2-readme.markdown +!/src/sea/licenses/socket-patch-MIT.txt +!/src/sea/rollup-provenance.mjs +!/src/sea/runtime.mts +!/src/sea/stage-synp.mts +!/src/sea/stage-uv.mts +!/src/sea/uv-pins.json +!/src/shadow/common.mts +!/src/shadow/npm-base.mts +!/src/shadow/npm-base.test.mts +!/src/shadow/npm/arborist-helpers.mts +!/src/shadow/npm/arborist/index.mts +!/src/shadow/npm/arborist/lib/arborist/index.mts +!/src/shadow/npm/arborist/types.mts +!/src/shadow/npm/bin.mts +!/src/shadow/npm/bin.test.mts +!/src/shadow/npm/inject.mts +!/src/shadow/npm/install.mts +!/src/shadow/npm/paths.mts +!/src/shadow/npx/bin.mts +!/src/shadow/npx/bin.test.mts +!/src/shadow/pnpm/bin.mts +!/src/shadow/pnpm/bin.test.mts +!/src/shadow/stdio-ipc.mts +!/src/shadow/yarn/bin.mts +!/src/shadow/yarn/bin.test.mts +!/src/test/cli.test.mts +!/src/test/json-output-validation.mts +!/src/test/mocks/socket-auth.mts +!/src/types.mts +!/src/utils/advisory-ids.mts +!/src/utils/agent.mts +!/src/utils/alert/artifact.mts +!/src/utils/alert/fix.mts +!/src/utils/alert/severity.mts +!/src/utils/alerts-map.mts +!/src/utils/alerts-map.test.mts +!/src/utils/api.mts +!/src/utils/api.test.mts +!/src/utils/arrays.mts +!/src/utils/bin.mts +!/src/utils/check-input.mts +!/src/utils/cmd.mts +!/src/utils/coana-release.mts +!/src/utils/coana-release.test.mts +!/src/utils/coana.mts +!/src/utils/coana.test.mts +!/src/utils/color-or-markdown.mts +!/src/utils/completion.mts +!/src/utils/config.mts +!/src/utils/config.test.mts +!/src/utils/cve-to-ghsa.mts +!/src/utils/debug.mts +!/src/utils/determine-org-slug.mts +!/src/utils/dlx-binary.mts +!/src/utils/dlx-binary.test.mts +!/src/utils/dlx-detection.mts +!/src/utils/dlx.mts +!/src/utils/dlx.test.mts +!/src/utils/ecosystem.mts +!/src/utils/editable-json.mts +!/src/utils/env.mts +!/src/utils/errors.mts +!/src/utils/errors.test.mts +!/src/utils/escape-regexp.mts +!/src/utils/extract-names.mts +!/src/utils/extract-names.test.mts +!/src/utils/fail-msg-with-badge.mts +!/src/utils/filter-config.mts +!/src/utils/fs.mts +!/src/utils/get-or-insert.mts +!/src/utils/get-output-kind.mts +!/src/utils/git.mts +!/src/utils/git.test.mts +!/src/utils/github-errors.mts +!/src/utils/github-errors.test.mts +!/src/utils/github.mts +!/src/utils/glob-content-dedup.test.mts +!/src/utils/glob.mts +!/src/utils/glob.test.mts +!/src/utils/globs.mts +!/src/utils/lockfile.mts +!/src/utils/logger.mts +!/src/utils/map-to-object.mts +!/src/utils/map-to-object.test.mts +!/src/utils/markdown.mts +!/src/utils/markdown.test.mts +!/src/utils/meow-with-subcommands.mts +!/src/utils/ms-at-home.mts +!/src/utils/npm-config.mts +!/src/utils/npm-package-arg.mts +!/src/utils/npm-paths.mts +!/src/utils/npm-paths.test.mts +!/src/utils/npm-spec.mts +!/src/utils/objects.mts +!/src/utils/is-object-object.mjs +!/src/utils/is-object-object.d.mts +!/src/utils/organization.mts +!/src/utils/output-formatting.mts +!/src/utils/package-environment.mts +!/src/utils/package-manager.mts +!/src/utils/packages.mts +!/src/utils/path-resolve.mts +!/src/utils/path-resolve.test.mts +!/src/utils/path.mts +!/src/utils/pnpm-paths.mts +!/src/utils/pnpm-scanning.test.mts +!/src/utils/pnpm.mts +!/src/utils/promises.mts +!/src/utils/prompts.mts +!/src/utils/purl-legacy-npm-names.json +!/src/utils/purl-to-ghsa.mts +!/src/utils/purl.mts +!/src/utils/registry-manifest.json +!/src/utils/requirements.mts +!/src/utils/sdk.mts +!/src/utils/sdk.test.mts +!/src/utils/self-update.mts +!/src/utils/self-update.test.mts +!/src/utils/semver.mts +!/src/utils/serialize-result-json.mts +!/src/utils/shadow-links.mts +!/src/utils/socket-json.mts +!/src/utils/socket-json.test.mts +!/src/utils/socket-package-alert.mts +!/src/utils/socket-url.mts +!/src/utils/sorts.mts +!/src/utils/spawn-sync.mts +!/src/utils/spawn.mts +!/src/utils/spec.mts +!/src/utils/spinner.mts +!/src/utils/streams.mts +!/src/utils/strings.mts +!/src/utils/telemetry/integration.mts +!/src/utils/telemetry/integration.test.mts +!/src/utils/telemetry/service.mts +!/src/utils/telemetry/service.test.mts +!/src/utils/telemetry/types.mts +!/src/utils/terminal-link.mts +!/src/utils/tildify.mts +!/src/utils/translations.mts +!/src/utils/url.mts +!/src/utils/walk-nested-map.mts +!/src/utils/walk-nested-map.test.mts +!/src/utils/words.mts +!/src/utils/yarn-paths.mts +!/src/utils/yarn-version.mts +!/src/vendor/coana-cache.mjs +!/src/yarn-cli.mts +!/taze.config.mts +!/test/blessed-node24-strict.test.mts +!/test/dist-runtime-requires.test.mts +!/test/external-bare-requires.test.mts +!/test/fixtures/commands/cdxgen/package.json +!/test/fixtures/commands/fix/e2e-test-js/package-lock.json +!/test/fixtures/commands/fix/e2e-test-js/package.json +!/test/fixtures/commands/fix/e2e-test-multipm/npm-app/package-lock.json +!/test/fixtures/commands/fix/e2e-test-multipm/npm-app/package.json +!/test/fixtures/commands/fix/e2e-test-multipm/pnpm-app/package.json +!/test/fixtures/commands/fix/e2e-test-multipm/pnpm-app/pnpm-lock.yaml +!/test/fixtures/commands/fix/e2e-test-py/requirements.txt +!/test/fixtures/commands/fix/npm/monorepo/package-lock.json +!/test/fixtures/commands/fix/npm/monorepo/package.json +!/test/fixtures/commands/fix/npm/monorepo/packages/app/package.json +!/test/fixtures/commands/fix/npm/monorepo/packages/lib/package.json +!/test/fixtures/commands/fix/npm/vulnerable-deps/package-lock.json +!/test/fixtures/commands/fix/npm/vulnerable-deps/package.json +!/test/fixtures/commands/fix/pnpm/monorepo/package.json +!/test/fixtures/commands/fix/pnpm/monorepo/packages/app/package.json +!/test/fixtures/commands/fix/pnpm/monorepo/packages/lib/package.json +!/test/fixtures/commands/fix/pnpm/monorepo/pnpm-lock.yaml +!/test/fixtures/commands/fix/pnpm/vulnerable-deps/package.json +!/test/fixtures/commands/fix/pnpm/vulnerable-deps/pnpm-lock.yaml +!/test/fixtures/commands/fix/yarn/monorepo/package.json +!/test/fixtures/commands/fix/yarn/monorepo/packages/app/package.json +!/test/fixtures/commands/fix/yarn/monorepo/packages/lib/package.json +!/test/fixtures/commands/fix/yarn/monorepo/yarn.lock +!/test/fixtures/commands/fix/yarn/vulnerable-deps/package.json +!/test/fixtures/commands/fix/yarn/vulnerable-deps/yarn.lock +!/test/fixtures/commands/json/socket.json +!/test/fixtures/commands/manifest/conda/environment.yml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/dual-marker-dir/build.gradle +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/dual-marker-dir/pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleA/nested-gradle/build.gradle +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleA/pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleB/independent-submodule/pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/moduleB/pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/reactor/pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/standalone-gradle/build.gradle.kts +!/test/fixtures/commands/manifest/dynamic-sbom-inference/monorepo/standalone-gradle/settings.gradle.kts +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/app-dev.pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/bare/pom +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/other.pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/pom.xml +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/pom.xml.bak +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/upper/POM.XML +!/test/fixtures/commands/manifest/dynamic-sbom-inference/pom-names/vendored/lib-1.0.pom +!/test/fixtures/commands/manifest/python/requirements.txt +!/test/fixtures/commands/npm/lacking-typosquat/package-lock.json +!/test/fixtures/commands/npm/lacking-typosquat/package.json +!/test/fixtures/commands/npm/npm10/package-lock.json +!/test/fixtures/commands/npm/npm10/package.json +!/test/fixtures/commands/npm/npm11/package-lock.json +!/test/fixtures/commands/npm/npm11/package.json +!/test/fixtures/commands/npm/npm9/package-lock.json +!/test/fixtures/commands/npm/npm9/package.json +!/test/fixtures/commands/optimize/npm/package-lock.json +!/test/fixtures/commands/optimize/npm/package.json +!/test/fixtures/commands/optimize/pnpm/package.json +!/test/fixtures/commands/optimize/pnpm/pnpm-lock.yaml +!/test/fixtures/commands/optimize/pnpm8/package.json +!/test/fixtures/commands/optimize/pnpm8/pnpm-lock.yaml +!/test/fixtures/commands/optimize/pnpm9/package.json +!/test/fixtures/commands/optimize/pnpm9/pnpm-lock.yaml +!/test/fixtures/commands/optimize/yarn/package.json +!/test/fixtures/commands/optimize/yarn/yarn.lock +!/test/fixtures/commands/patch/npm/.socket/blobs/76682a9fc3bbe62975176e2541f39a8168877d828d5cad8b56461fc36ac2b856 +!/test/fixtures/commands/patch/npm/.socket/manifest.json +!/test/fixtures/commands/patch/npm/package-lock.json +!/test/fixtures/commands/patch/npm/package.json +!/test/fixtures/commands/patch/pnpm/.socket/blobs/76682a9fc3bbe62975176e2541f39a8168877d828d5cad8b56461fc36ac2b856 +!/test/fixtures/commands/patch/pnpm/.socket/manifest.json +!/test/fixtures/commands/patch/pnpm/package.json +!/test/fixtures/commands/patch/pnpm/pnpm-lock.yaml +!/test/fixtures/commands/patch/yarn/.socket/blobs/76682a9fc3bbe62975176e2541f39a8168877d828d5cad8b56461fc36ac2b856 +!/test/fixtures/commands/patch/yarn/.socket/manifest.json +!/test/fixtures/commands/patch/yarn/package.json +!/test/fixtures/commands/patch/yarn/yarn.lock +!/test/fixtures/commands/scan/npm-test-workspace-mono/.gitignore +!/test/fixtures/commands/scan/npm-test-workspace-mono/package-lock.json +!/test/fixtures/commands/scan/npm-test-workspace-mono/package.json +!/test/fixtures/commands/scan/npm-test-workspace-mono/packages/package-a/package.json +!/test/fixtures/commands/scan/npm-test-workspace-mono/packages/package-b/index.js +!/test/fixtures/commands/scan/npm-test-workspace-mono/packages/package-b/package.json +!/test/fixtures/commands/scan/plain-requirements-txt/requirements.txt +!/test/fixtures/commands/scan/simple-npm/index.js +!/test/fixtures/commands/scan/simple-npm/package.json +!/test/fixtures/commands/scan/uv-workspace/packages/api/pyproject.toml +!/test/fixtures/commands/scan/uv-workspace/packages/other/pyproject.toml +!/test/fixtures/commands/scan/uv-workspace/packages/shared/pyproject.toml +!/test/fixtures/commands/scan/uv-workspace/pyproject.toml +!/test/fixtures/commands/scan/uv-workspace/uv.lock +!/test/fixtures/manifest-bazel/bzlmod-only/MODULE.bazel +!/test/fixtures/manifest-bazel/custom-name-bzlmod/MODULE.bazel +!/test/fixtures/manifest-bazel/legacy-only/WORKSPACE +!/test/fixtures/manifest-bazel/legacy-with-load/WORKSPACE +!/test/fixtures/manifest-bazel/legacy-with-load/maven_deps.bzl +!/test/fixtures/manifest-bazel/migration/MODULE.bazel +!/test/fixtures/manifest-bazel/migration/WORKSPACE +!/test/fixtures/manifest-bazel/multi-repo-bzlmod/MODULE.bazel +!/test/fixtures/manifest-bazel/native/bzlmod/.bazelversion +!/test/fixtures/manifest-bazel/native/bzlmod/BUILD.bazel +!/test/fixtures/manifest-bazel/native/bzlmod/MODULE.bazel +!/test/fixtures/manifest-bazel/native/maven.expected.json +!/test/fixtures/manifest-bazel/native/workspace/.bazelversion +!/test/fixtures/manifest-bazel/native/workspace/BUILD.bazel +!/test/fixtures/manifest-bazel/native/workspace/WORKSPACE +!/test/fixtures/manifest-bazel/python-pypi/requirements.expected.txt +!/test/glob.test.mts +!/test/json-output-validation.mts +!/test/manifest-reachability-assertions.test.mts +!/test/maven-compat-smoke-assertions.test.mts +!/test/mock-auth.mts +!/test/mock-auth.test.mts +!/test/mock-malware-api.mts +!/test/mock-malware-api.test.mts +!/test/package-environment.npm-version.test.mts +!/test/pin-readme-assets.test.mts +!/test/reachability-options.mts +!/test/release-add-unreleased.test.mts +!/test/release-artifact-download.test.mts +!/test/release-bump.test.mts +!/test/release-history.test.mts +!/test/release-open-pr.test.mts +!/test/release-registry.test.mts +!/test/release-version.test.mts +!/test/release-workflow.test.mts +!/test/run-with-config.mts +!/test/script-run-main.test.mts +!/test/script-scope.test.mts +!/test/script-update.test.mts +!/test/setup-node.test.mts +!/test/setup-uv.test.mts +!/test/smoke.sh +!/test/upload-artifact.test.mts +!/test/utils.mts +!/test/utils.test.mts +!/test/workflow-actions.test.mts +!/translations.json +!/tsconfig.dts.json +!/tsconfig.json +!/tsconfig.scripts.json +!/vitest.config.mts +!/vitest.e2e.config.mts +!/vitest.integration.config.mts +!/vitest.native.config.mts + +# Local and generated files remain excluded even when they match an allowlist path. /.env /.env.local -/.nvm -/.pnpm-store -/.rollup.cache -/.type-coverage -/.vscode -/coverage -/external -/npm-debug.log -**/.cache -**/dist -**/node_modules +/.env.precommit +/.nvm/ +/.pnpm-store/ +/.rollup.cache/ +/.type-coverage/ +/build/ +/coverage/ +/coverage-e2e/ +/coverage-unit/ +/external/ +**/.cache/ +**/dist/ +**/node_modules/ *.d.ts *.d.ts.map *.tsbuildinfo -test/fixtures/commands/fix/e2e-test-js-temp-* -test/fixtures/commands/fix/e2e-test-py-temp-* - -/.claude/* -!/.claude/agents/ -!/.claude/commands/ -!/.claude/hooks/ -!/.claude/ops/ -!/.claude/settings.json -!/.claude/skills/ - -!/.vscode/extensions.json - -# Generated by the JVM compat fixtures (src/commands/manifest/scripts/test). -# The stub repos and caches are rebuilt on every run; smoke-test-workspaces.sh -# still keeps its Gradle user home inside the fixture directory. +/.repo-map/ +/upstream/ +/docs/fleet/ +/scripts/fleet/ +/test/fleet/ +/.claude/ops/ +/.claude/worktrees/ +/.github/copilot-instructions.md /src/commands/manifest/scripts/test/gradle-compat/.gradle-home/ /src/commands/manifest/scripts/test/gradle-compat/**/.gradle/ /src/commands/manifest/scripts/test/gradle-compat/project/build/ @@ -53,10 +1374,6 @@ test/fixtures/commands/fix/e2e-test-py-temp-* /src/commands/manifest/scripts/test/sbt-compat/relocation/records.tsv /src/commands/manifest/scripts/test/sbt-compat/relocation/scala-version.sbt /src/commands/manifest/scripts/test/sbt-compat/relocation/target/ - -# Generated when the dynamic SBOM inference tests walk their fixtures -# (test/fixtures/commands/manifest/dynamic-sbom-inference). Those fixtures are -# build-tool marker files only, so any build output under them is debris. /test/fixtures/commands/manifest/dynamic-sbom-inference/**/.gradle/ /test/fixtures/commands/manifest/dynamic-sbom-inference/**/build/ /test/fixtures/commands/manifest/dynamic-sbom-inference/**/target/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..c236ef7a7c --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +# Avoid advisory-feed lookups as a side effect of npm install. +audit=false diff --git a/README.md b/README.md index 8ace54a8d1..e9c7583389 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Supports version 2 format with `projectIgnorePaths` for excluding files from rep - `SOCKET_CLI_GITHUB_TOKEN` - GitHub token with repo access (alias: `GITHUB_TOKEN`) - `SOCKET_CLI_NO_API_TOKEN` - Disable default API token - `SOCKET_CLI_NPM_PATH` - Path to npm directory +- `SOCKET_CLI_SOCKET_PATCH_PATH` - Path to an executable socket-patch binary for standalone builds - `SOCKET_CLI_ORG_SLUG` - Socket organization slug - `SOCKET_CLI_ACCEPT_RISKS` - Accept npm/npx risks - `SOCKET_CLI_VIEW_ALL_RISKS` - Show all npm/npx risks diff --git a/bin/cli.js b/bin/cli.js index 65a478640e..a5e36a2e4c 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -11,9 +11,7 @@ void (async () => { const { default: constants } = require( path.join(rootPath, 'dist/constants.js'), ) - const { spawn } = require( - path.join(rootPath, 'external/@socketsecurity/registry/lib/spawn.js'), - ) + const { spawn } = require(path.join(rootPath, 'dist/utils.js')) process.exitCode = 1 diff --git a/docs/plans/node27-sea-vfs-socket-package.md b/docs/plans/node27-sea-vfs-socket-package.md new file mode 100644 index 0000000000..d76fa15a07 --- /dev/null +++ b/docs/plans/node27-sea-vfs-socket-package.md @@ -0,0 +1,534 @@ +# Plan: self-contained `socket` CLI using Node 27 SEA and VFS + +## Status and scope + +Implementation plan for a new artifact built from the root `socket` package on the `v1.x` line. This is a separate distribution variant: do not change or replace `@socketsecurity/cli`, `@socketsecurity/cli-with-sentry`, their package identities, public behavior, npm approval/trusted-publishing behavior, or current JavaScript launchers. The requested removal of `@socketsecurity/registry` and `@socketregistry/packageurl-js` is an intentional dependency/content change in the root `socket` package; preserve the existing npm release contract and avoid unrelated package changes. The standalone asset lifecycle is a separate SEA release/tag namespace with an independently incremented revision mapped to Socket version and source SHA, avoiding immutable npm release coupling. The deliverable is a platform-specific standalone Socket CLI application built with the latest Node.js 27 release available when implementation starts, using Node SEA and VFS support, and signed/released by adapting the established `socket-cli-native` workflow contract. + +### Implementation progress (2026-11-09) + +The implementation is on `feat/v1x-node27-sea-vfs-socket`, rebased on `origin/v1.x` at Socket `1.14.1`. The `--prototype` builder pins Node `v27.0.0-alpha.0.0.0` and verifies its archive against official `SHASUMS256.txt`. It uses Node's direct `--build-sea` output, stages inputs in private OS temporary directories outside checkout `dist`, preserves relative VFS-main loading, and packages the root `socket` distribution, external tree, runtime data, verified Node license, target-native socket-patch, the first-party .NET facts helper, and darwin-arm64 cdxgen/Synp bundles. It builds the .NET facts helper before Rollup copies the distribution; independent tool payload preparation runs concurrently and is awaited with `Promise.allSettled` before cleanup, while the main distribution build waits for the .NET helper. The helper is embedded, but its command uses the user's project-selected .NET SDK at runtime; the SDK is not part of the SEA. `.npmrc` disables npm install audit lookups. The pinned pnpm 10 install does not run vulnerability auditing automatically; `pnpm audit` is explicit and absent from this build path. The helper's `dotnet restore` disables NuGet auditing; pinned input integrity checks remain enabled. `SOCKET_SEA_BUILD=true` skips ordinary package/lockfile build-hook rewrites. The prototype is macOS arm64 evidence only; it is not production-signed or target-qualified. + +**Latest integrated build (2026-11-09; source version 1.14.1).** `pnpm build:sea -- --prototype` completed for darwin-arm64 with Node `v27.0.0-alpha.0.0.0`. The 181,738,144-byte executable SHA-256 is `54c36b1620eeaea007daa4583a4a98cd4b2dacff5efc63492d12e0b2add1c3ff`; `codesign --verify` succeeds for its ad-hoc signature, and `--version` reports `1.14.1`. Its manifest records the embedded `socket-facts-dotnet.dll` helper closure and documents the external .NET SDK requirement. NuGet restore succeeded from cached packages with auditing disabled. Checkout `dist` remains isolated from the SEA build. The VFS includes the verified Node archive `LICENSE`, target socket-patch, cdxgen 12.1.2, Synp 1.9.14, pinned uv 0.12.15, and core/external source-and-notice inventory. Its sidecar records six distribution inventories and 256 notice documents; uv is advertised for this prototype target with a recorded unresolved Rust transitive-license inventory obligation. cdxgen and Synp remain unavailable pending authenticated source bytes and unresolved legal obligations. npm lock v3 and Yarn Classic lock v1 adapter smokes succeeded. The adapter validates required lock edges, permits absent optional/peer dependencies, isolates cdxgen from project `node_modules` and host fallback files, preserves project identity and source paths, cleans owned lock/temp files before exit, and maps cancellation to conventional signal exit codes. Static review found no remaining adapter blockers. No repository test suites were run. This is still an ad-hoc signed prototype, not Developer ID/notarized or target-qualified release output. + +**Restricted cdxgen/Synp implementation and smoke (qualification-gated).** The builder packages the pinned `@cyclonedx/cdxgen@12.1.2` API and Synp 1.9.14 API in the darwin-arm64 VFS bundle, with relative Rollup chunks, package metadata, data, Workers, and notices. A restricted Worker calls `createNodejsBom()` directly; it never invokes cdxgen's CLI `prepareEnv()` or manager-selection path. The cdxgen adapter accepts one root npm `package-lock.json` v3 project or Yarn Classic lock v1 through Synp's v1 converter. It rejects Berry, workspaces, local/link dependencies, unsupported modes, malformed lock graphs and unresolved required edges; optional/peer absences are allowed. It calls the API against a sanitized temporary project with only `package.json` and the lockfile, so host `node_modules`, `bower.json`, minified JS, plugins and fallback scans cannot affect results. It preserves unnamed-project identity and rewrites supported source/bin paths back to the original project. Synp requires existing `node_modules`, creates the output lock exclusively, verifies its inode/size/digest, and removes only the exact lock it owns before command exit. Cancellation reaches both Workers and cleanup, including SIGHUP/SIGINT/SIGTERM status propagation. Direct API smokes produced CycloneDX 1.6 BOMs from npm v3 and Synp v1 fixtures. A hostile ambient `NODE_OPTIONS` preload, `NODE_PATH`, `CDXGEN_ALLOWED_COMMANDS=*`, external `CDXGEN_PLUGINS_DIR`, and `FETCH_LICENSE=true` did not widen the Worker environment; `--deep` returns a clear unsupported-option error. The cdxgen and Synp payloads remain unavailable in the manifest until source provenance and remaining notice obligations are qualified. If enabled later, the cdxgen capability is limited to one npm project, `pre-build`, no installs/Babel/recursion/evidence/deep/plugins/native analyzers, only darwin-arm64. Shrinkwrap, workspaces, Yarn Berry, other lock versions, and all other cdxgen modes remain unavailable. + +**Proof limits and promotion gates.** The Worker blocks `spawn`, `spawnSync`, `exec`, `execSync`, `execFile`, `execFileSync`, `fork`, HTTP(S) request/get, direct TCP/TLS connects, HTTP/2 connects, UDP socket creation, and global fetch before API import; Node builtin ESM exports are synchronized after patching. This is a strict guard around the exercised API path, not an OS sandbox or a claim against arbitrary `process.binding()` use. Valid/empty/malformed lock behavior, unsupported flags, hostile environment settings, output/source identity, optional/peer graph edges, cleanup and direct npm/Yarn API results have focused smoke evidence. Before promotion, repeat those checks on each declared target runner, establish complete module/network observation, authenticate package source bytes against locked tarballs and applied patches, resolve legal/copyright obligations, and verify the actual signed release bytes. cdxgen's API can otherwise log a partial BOM and scan local project files; sanitized project isolation and strict graph validation prevent those observed fallbacks in the supported path. The Worker uses `execArgv: []` plus replacement env, and the SEA uses `execArgvExtension: "none"` with `--no-global-search-paths`. + +**Current source and notice inventory.** The cdxgen Rollup closure records 140 package instances and deterministic installed-module source hashes with package/lock locator, declared SRI, and patch context. Source authentication is explicitly `unverified`; lock SRI does not authenticate installed, patched or generated bytes. Curated legal documents cleared the five former missing-text items (`boolbase@1.0.0`, `err-code@2.0.3`, `imurmurhash@0.1.4`, `spdx-exceptions@2.5.0`, `spdx-license-ids@3.0.22`), but `err-code@2.0.3` still has an inferred copyright-holder obligation. The core Rollup closure covers 1,035 module files across 229 package instances; the copied Blessed closure and four Blessed-contrib entrypoints have separate inventories. Curated texts cleared six missing-text gaps (`@npmcli/agent@3.0.0`, `@npmcli/agent@4.0.0`, `@sigstore/verify@3.1.1`, `x256@0.0.2`, `ansi-term@0.0.2`, `drawille-canvas-blessed-contrib@0.1.3`), while five inferred copyright-holder obligations remain for both `@npmcli/agent` versions, `x256`, `ansi-term`, and `drawille-canvas-blessed-contrib`. The six distribution sidecars and 256 notice documents are VFS-addressed and hashed in the external build manifest. Synp's 25-package notice inventory has two missing-license-text obligations, and its staged payload hash does not authenticate installed/transformed module sources. Keep cdxgen and Synp unavailable; their source/authentication and legal evidence are still incomplete. Core distribution notices also need final legal review before any production release. + +**Coana source spike (2026-11-09).** The active product version is `15.14.0` (`src/constants.mts`), invoked by both reachability analysis and `socket fix`. It is not DLX: `src/utils/coana-release.mts` honors `SOCKET_CLI_COANA_LOCAL_PATH`, otherwise resolves the versioned Socket component through the authenticated Socket API, caches it, and launches `cli-wrapper.mjs`. The CLI itself can fetch its `analyzers` component and bootstrap Python/uv/Go tools. The local cache inspected for evidence contains 15.14.0 CLI digest `ac9dc9c7d49f6af238b9004ccdf2635822bbbc7a409a1ee211cc51e04b7803dd` (6.7 MiB) and analyzer digest `9497418bf673d2f0b02667e8a4bdc7d0de3dda87a7f6b9c405f2c69c54d2837b` (112 MiB / 181 files); these user-cache bytes are not reproducible CI inputs and must not be treated as source-authenticated payloads. The bundle request does not carry a platform key, so the component must be independently inventoried before use. Coana supports macOS x64/arm64 and Linux glibc x64/arm64; Windows is explicitly rejected. Linux ARM64 Ruby is unavailable because its packaged Ruby analyzer is an x86-64 ELF despite its ARM64 path. Darwin tree-sitter addons are ARM64 Mach-O with ad-hoc linker signatures; all native signature states and loaders need individual inspection. Coana invokes JS analyzers through child Node processes (`process.execPath`) and can install Python/Go/tooling at runtime (`uv tool run`, venv/pip, pyenv/uv, Go); it cannot run unchanged inside a Worker or call the outer SEA executable as `node`. A bundled plain Node child runtime or narrowly refactored child dispatcher is required, in dependency order with Python/uv closure. Its CLI/analyzer component roots lack LICENSE/NOTICE files; recursive redistribution rights and notices are unresolved. Implement with target capabilities split by ecosystem, explicit override > embedded precedence, and no Coana/API/cache/toolchain fallback when the bundled target payload is absent. Windows, Linux musl, unsupported Ruby and any analyzer with unresolved native/license closure must fail clearly without acquisition. + +**uv/Python source spike (2026-11-09).** `--uv-members` is a single production uv path in `src/commands/scan/generate-uv-member-sboms.mts`; it invokes `uv export --format cyclonedx1.5 --frozen --offline --no-python-downloads --all-extras` twice. Pin uv `0.12.15` and embed independently SHA-256-verified assets for all six Node target triples (darwin x64/arm64, Linux GNU x64/arm64, Windows x64/arm64); upstream `scripts/ci/setup-uv.mts` only pins Linux, so SEA needs its own complete exact pin table and release/license source. Preserve `SOCKET_CLI_UV_PATH` override precedence, validate a selected override without fallback, and extract only the target-native embedded executable for child launch. Python is used only by Bazel Maven/PyPI extraction shims (`src/commands/manifest/bazel/bazel-python-shim.mts` and its two extraction callers), not by uv SBOM export. These SEA paths currently require explicit `SOCKET_CLI_PYTHON_PATH`; future embedded Python must follow override > target payload and be a relocatable runtime with stdlib/shared-library/license closure. Do not install host/system Python. Verify Bazel queries do not trigger Socket-owned Python/toolchain acquisition and keep project-declared remote repositories distinct. Python artifact selection/redistribution across all six targets remains unqualified; do not advertise Python support until a runtime smoke succeeds per target. + +**Build trust and startup hardening.** The Node build cache is keyed by the official archive checksum, but a matching directory name alone is not integrity evidence. Each build downloads and verifies the Node archive against official `SHASUMS256.txt`, extracts into a private owned tree, and compares the complete cached file/symlink/mode tree against that extraction before reuse. A mismatched cache is left untouched and that build uses its private verified runtime, avoiding concurrent destructive repair races; corrupt-cache cleanup remains maintenance work. Set SEA `execArgvExtension: "none"` and `execArgv: ["--no-global-search-paths"]` to exclude ambient Node startup options and global module search paths; a hostile `NODE_OPTIONS` preload and `NODE_PATH` sentinel did not affect the integrated cdxgen run. The `constants.spinner` getter loads the dedicated `dist/spinner.js` leaf's default singleton so prompt pause/resume and normal command progress share one spinner instance. + +**Archived signing workflow audit.** The archived repository at `/Users/jdalton/projects/socket-cli-native` (HEAD `96d439e1ab786d6500e085560c2dcf115289a22b`) provides reusable contracts in `.github/workflows/publish-native.yml`, `scripts/repo/build/sea/sign.mts`, `scripts/fleet/apple-sign.mts`, and `scripts/fleet/apple-notarize.mts`. Follow their signing, notarization, and qualification contracts; verify every helper is tracked in the target checkout before importing it. The SEA wrapper requires macOS Developer ID Application signing with hardened runtime, strict expected Team ID verification, notarization `Accepted` plus receipt UUID, and post-notary signature verification; bare binaries cannot be stapled, so a stapled DMG/pkg is a separate offline-first-launch decision. Preserve/sign inner payloads before embedding when evidence requires it, then outer sign → strict verify → notary submit/accepted receipt → verify again → final SHA/receipt → native-runner qualification of the transferred bytes. Required secrets include the P12/cert password, Team ID and Apple notarization credentials (Apple ID/app-specific password or ASC key credentials). The archived build job currently exposes signing secrets before its script-level requested-source-SHA comparison and has no protected environment declaration; the new SEA workflow must validate tag/version/source SHA and clean detached checkout before secrets are made available, put credentials only on a protected macOS signing job, and keep qualification/release jobs credential-free. Existing workflow artifacts are not by themselves a SEA release coordinator, and no Authenticode requirement is inferred. + +**Clean-checkout signing implementation boundary (Astra review, 2026-11-09).** The current checkout contains Apple helpers under ignored `scripts/fleet/`, but `git ls-files` confirms they are untracked and `.git/info/exclude` ignores them; `@socketsecurity/lib-stable` is not an installable dependency here. Clean CI cannot import those files or the archived local setup action. Port the narrow Apple operations into tracked `scripts/sea/release/apple/` modules using Node builtins and explicit bounded subprocesses, with source attribution to the inspected native revision. The archived uploader only handles exactly three npm tarballs; SEA needs a distinct artifact archive/receipt path. The workflow must be manually authorized from protected `v1.x`, validate full source SHA/version and a clean detached checkout before any Apple secrets are available, build the exact darwin-arm64 artifact without credentials, transfer it immutably, then sign/notarize only those transferred bytes in a protected macOS Environment. Require a private temporary keychain, one unambiguous Developer ID Application identity, hardened runtime, explicit JIT entitlements, strict Team ID/chain/entitlement verification, accepted notary status with UUID, and post-notary hash/signature verification. Submit a ZIP of the bare Mach-O to `notarytool`; do not claim that the executable itself is stapled. A separate credential-free macOS job verifies immutable artifact hashes, applies/readbacks quarantine on its test copy, performs online Gatekeeper assessment, and qualifies declared capabilities. Keep `prototype-qualification` separate from production eligibility: the current `--prototype` build, unverified package sources, unresolved notices and absent embedded manifest/release attestation cannot become a production release just because notarization succeeds. The final receipt binds repository/workflow/source SHA, Socket and standalone revision, Node/target/run, embedded-manifest and sidecar digests, pre/post-sign executable digests and size, Team ID, entitlements, accepted notary UUID/status and submission-ZIP hash. The embedded manifest must be produced before archive assembly; the post-sign receipt is separate because the final executable cannot embed its own final digest. Defer publication and immutable release revision allocation until legal/source gates and target qualification are enforceable. + +The generic `spawnDlx()` rejects SEA calls before package-manager detection or launching a shadow manager, preventing future helper call sites from silently adding a DLX install path. The builder embeds the target-compatible socket-patch binary in the VFS archive, validates package metadata and lockfile integrity at build time, records its license, and its runtime digest-check/extraction/execution/cleanup path has local smoke evidence. Coana fails closed before cache/API/download work unless `SOCKET_CLI_COANA_LOCAL_PATH` selects an explicitly supported executable; its JavaScript mode remains unavailable until its Worker/runtime and child-launch behavior are qualified. Startup npm update metadata checks are disabled inside SEA. Synp 1.9.14's API returns serialized lock data while its CLI performs validation and file writing. The bundled adapter creates `package-lock.json` exclusively, tracks its digest and file identity, and removes only that owned file before exit. Synp and cdxgen payloads are embedded but remain capability-gated pending source authentication and notice/legal qualification. + +`@socketregistry/packageurl-js` and `@socketsecurity/registry` are both removed from the root package graph. Runtime and Rollup helper imports were replaced with narrow local attributed ports; prompt handling uses exact-pinned direct `@inquirer` dependencies instead of vendored registry files. `pnpm why` confirms neither removed package remains in the installed dependency graph. The Optimize editable-package wrapper still differs in JSON comments/order behavior. No tests have been run. Prototype verification is macOS arm64 only; production signing and other-target verification remain outstanding. + +Local ports cover currently consumed methods and retain upstream notices. Node SEA does not permit `vfsArchive` with named `assets`, so socket-patch and its SHA-256 are files within the VFS archive; the runtime adapter reads them through VFS and extracts the binary only for native execution. The initial build confirms staging isolation. Node 27 VFS startup required removing a `constants -> utils -> constants` runtime load and providing an explicit bootstrap VFS root. The current three-command smoke pass confirms the issue is resolved for core CLI and socket-patch help. Blessed outputs honor the staged external directory. + +**Node release availability at research time (2026-11-08):** the official Node distribution index lists `v27.0.0-alpha.0.0.0` as the only Node 27 release and `v26.13.0` as the latest stable release. Node 27 is currently Alpha until Current is scheduled for 2027-04-22; prerelease APIs/ABI may change and are not intended for production. The user requested the latest Node 27 SEA, not stable-only. Therefore discovery and implementation should select the latest Node 27 release available at each pinned build, whether prerelease or stable, record its exact version/commit/checksum, and label any artifact built from prerelease Node as experimental/pre-release with its support limits. Do not silently substitute another major or use a floating `latest` download. Recheck the [official release index](https://nodejs.org/dist/index.json) and [Node release schedule](https://github.com/nodejs/Release/blob/main/README.md); verify every SEA/VFS behavior against the exact selected Node build before relying on it. + +The artifact must be self-contained for every executable, runtime, package, library, or support file that Socket CLI or a child tool would otherwise download or install at runtime in order to perform a supported Socket command. Nothing in this category may be fetched, installed, or updated at runtime. This includes the Socket application and production JS dependency graph, Node 27, cdxgen, Synp, Coana CLI, socket-patch, uv, the Python runtime/CLI/modules actually required by supported paths, Blessed and its patched dependency closure, and any toolchain distribution that a Socket-invoked wrapper would otherwise download (including supported Gradle/Maven/sbt distributions). Put loadable JS/data in SEA VFS; package native executables, runtimes and path-dependent files inside the signed artifact and extract them safely only when the OS requires a real path. + +Keep project data resolution distinct: scanning or building a user project can require fetching that project’s own dependencies, plugins, SDK artifacts, or remote source. Those are project inputs, not Socket’s helper installation. However, a Socket-launched tool must not silently download its own executable/runtime or a toolchain distribution. If a project selects a tool version that is not bundled, fail with a clear unsupported-version message; never fall back to downloading it. Allowed runtime network purposes are explicit: Socket API requests; GitHub/project manifest-file retrieval requested by a scan; user-project dependency/plugin/artifact resolution required by the selected analysis; and patch payload data requested by socket-patch for apply/rollback/repair. Forbidden purposes are Socket app updates that replace executable bytes, helper/runtime/toolchain installation, child-process bootstrap, and self-update of embedded tools. Do not define this rule as a ban on executable bytes or particular hosts: an allowed project dependency/plugin/patch may itself contain executable code and may share a CDN/registry host with build payloads. Treat patch blobs as requested project data (not tool acquisition), verify via the patch protocol, and do not permit socket-patch `--update` to replace its bundled executable. Classify the startup npm self-update metadata check separately; it may query metadata but cannot download/install the newer app, and SEA should disable it by default or make it an explicit non-blocking metadata-only option. + +Inventory every direct and transitive executable/runtime launch. Bundle the best compatible binary/runtime variants for each declared target. A tool or feature may be unavailable on one target when no compatible bundled variant works there; record that capability as unavailable, expose a clear command-time diagnostic, and do not attempt a download or incompatible fallback. This does not block publishing that target or other working features. Socket-owned helper acquisition remains forbidden at runtime on every target. Arbitrary project-selected versions outside the target's embedded matrix fail before launching. Project-selected dependency downloads may remain, but wrapper/tool self-installation is forbidden. Do not silently classify an application-managed download as “external.” + +### Target-specific initial capability set + +These are the capabilities to evaluate for the first standalone release, not a requirement that every platform support every feature. Each artifact must include a generated, documented capability manifest listing supported commands/features, exact bundled tool versions and variants, and unavailable features with concise reasons. Select only binary/runtime variants that match the target OS, architecture, ABI/libc, and required loader. A missing or incompatible variant disables only the affected capability on that artifact. It does not block that platform's artifact or unrelated capabilities. Runtime selection must never probe another platform's payload or download a substitute. + +Capability-manifest availability describes the embedded default for that target. Resolve explicit environment-variable/CLI overrides first: a valid user-selected external path may satisfy a capability whose embedded default is unavailable, following the existing override contract. If the override is absent and the embedded capability is unavailable, fail clearly before helper launch. If an explicit override is invalid, fail on that selection and do not fall back to the embedded tool or a download. Core Node/SEA availability is not overridden by a helper path. + +- Core `socket` CLI startup, help/version, config/auth, API-backed scan operations, and built-in command routing. +- `manifest cdxgen`, including cdxgen plus Synp conversion for supported Yarn lock formats. +- Scan/fix reachability through the pinned Coana CLI and `socket patch` through the pinned socket-patch binary. +- Python/Bazel manifest paths and explicit `scan create --uv-members` through embedded Python/uv versions. +- Gradle/Maven/sbt manifest and facts paths for an explicit supported wrapper/tool version matrix, including the Maven extension JAR and Java runtime/toolchain needed by those commands. Project dependencies/plugins remain project inputs; bundled launchers alone do not make arbitrary project builds offline. +- Blessed threat-feed TUI and the repository-patched JS dependency closure. +- Explicitly invoked `socket npm/npx/pnpm/yarn` and `raw-npx` remain user-directed package-manager operations; they are not the mechanism for acquiring hidden Socket helpers. Document their arbitrary package execution/network semantics as a distinct user request. + +Missing or invalid assets for a capability declared embedded-available must fail that target build. At invocation, validate an explicit external override before checking embedded availability; a valid selected override may run even if the manifest says the embedded default is unavailable. Without that override, an unavailable embedded capability fails clearly before helper launch or network bootstrap. An invalid explicit override fails without fallback. None of these capability states may prevent unrelated features or the artifact from building. Never advertise an embedded feature whose payload has not passed target-native validation. + +### Initial command-to-capability map + +This map sets the audit granularity. Discovery may split or combine rows where source behavior proves the same payload closure; it must not collapse distinct ecosystem or mode closures into a single broad “tool works” claim. + +| Command family | Capability branches to inventory | +| --- | --- | +| Core help/config/auth/API scan/audit/package/org/repo commands | SEA core JS/VFS, config and credential handling, Socket API; metadata/self-update lookup tracked separately from executable updates. | +| Scan create/setup and CI | Core API; optional `git.metadata` only when repository/branch is inferred; optional manifest generation, dynamic JVM inference, `uv-members`, Coana reachability and browser opening each have independent capability IDs. | +| Scan reach and fix | Coana by analyzer/ecosystem and platform; Python/uv/JDK/Go/.NET helper closures as required. Fix additionally needs Coana `compute-fixes` plus separate `git.mutation/transport` and any manager install behavior. | +| `manifest cdxgen` | Base cdxgen per ecosystem and mode; Synp Yarn conversion; separate deep, SQLite evidence/include-crypto, .NET/DOSAI, Swift/SourceKitten, Atom/Java and project-tool bootstrap branches. Unsupported modes must be rejected before cdxgen `prepareEnv()` runs. | +| Gradle/Kotlin/Maven/Scala/sbt/auto/dynamic inference | Per-tool bounded distribution/version matrix, Java version, project wrapper handling, compiler/launcher boot closure (including sbt Scala under fresh global base), and Socket emitter scripts/JARs materialized at real paths. Legacy and facts paths are separate call sites to inventory. | +| Bazel manifest | Bazel/Bazelisk exact version plus separate Maven and PyPI emitters; Java and Python shims; workspace toolchain bootstrap disabled; Windows process cancellation (`taskkill`) separately handled. | +| `socket optimize` | Manager-specific query/list, lockfile parse and install/update capabilities for npm, pnpm, Yarn Classic/Berry and Bun; Bun `bun.lockb` fallback; Vlt is detected but unsupported by Optimize. Do not route through Synp. | +| Explicit manager commands and shadows | `npm`, `npx`, `pnpm`, `yarn`, `raw-npm`, `raw-npx`; selected manager/runtime, IPC injection, completion/shadow files and Windows shim behavior. These user-directed package operations are distinct from hidden helper acquisition. | +| Threat feed | API/data request independent of interactive Blessed TUI; TUI is a separate capability with terminal/terminfo/tmux/Windows command integration. | +| `socket patch` | Target-native socket-patch binary, signature and real-path extraction; patch payload API traffic allowed; binary self-update forbidden. | +| Conda manifest conversion, completion, report opening | Conda-to-requirements is in-process JS; completion shell script needs a persistent real path; browser opening is optional OS integration with URL fallback. | + +## Repo facts + +- Root `package.json` is named `socket`; its bins include `bin/cli.js`, `bin/npm-cli.js`, `bin/npx-cli.js`, `bin/pnpm-cli.js`, and `bin/yarn-cli.js`. +- `pnpm build:sea` already exists (`src/sea/build-sea.mts`), but `src/sea/README.md` describes a thin wrapper that downloads `@socketsecurity/cli` on first run. That does not meet this request. Replace/redefine that path or rename the old experiment so `build:sea` unambiguously creates the bundled root `socket` product. +- A pre-existing `.claude/plans/socket-sea-package.md` describes an older “single published package”/node-smol target approach. Treat it as superseded for this work: the current request keeps npm variants and release behavior intact, builds the root `socket` package as a separate Node 27 SEA/VFS artifact, and allows target-specific capability omissions. Do not copy the old single-package or node-smol assumptions into implementation. +- `src/utils/dlx.mts` launches CycloneDX and Synp through package-manager DLX paths. `src/utils/coana-release.mts` downloads a Coana component into a cache. `src/commands/patch/cmd-patch.mts` launches the Rust `socket-patch` executable. `src/commands/scan/generate-uv-member-sboms.mts` invokes `uv`; other manifest paths probe or launch Python. +- `src/constants.mts` pins `COANA_CLI_VERSION`; `INLINED_SOCKET_CLI_CYCLONEDX_CDXGEN_VERSION` is build-time injected. `package.json` has `@cyclonedx/cdxgen` as a dev dependency and `@socketsecurity/socket-patch` as a production dependency. Avoid duplicate unmanaged version sources. +- The archived `/Users/jdalton/projects/socket-cli-native` repo at inspected revision `96d439e1ab786d6500e085560c2dcf115289a22b` provides the signing/release precedent: `.github/workflows/publish-native.yml` builds a source/version-bound artifact on macOS CI with CI-only Apple credentials, `scripts/repo/build/sea/sign.mts` performs Developer ID signing, strict verification and notarization, the workflow hashes/receipts and transfers immutable artifacts, and native target runners execute the transferred bytes before publication. Its eight targets are not automatically the SEA target set: exact Node 27 SEA platform support controls which Socket SEA targets can ship. Existing evidence signs/notarizes macOS artifacts; use the same fleet signing helpers and receipt contract for the SEA product, and do not claim Windows Authenticode unless a separate approved signer path is actually found and added. Preserve credential CI-only handling and clean temporary keychains. Local `codesign --sign -` remains only an ad-hoc development signature, not production signing. + +## Decisions required in a feasibility spike + +The remaining decisions are organized as a bounded gap-closure program below. These are discovery/prototype tasks; they do not require blocking product design for every target at once. Close product-level gaps (production-feasible selected Node 27 build, SEA behavior, artifact identity/integrity and a valid release path) before implementation. Resolve helper feasibility per capability and target; an unavailable helper marks only its feature unavailable on that artifact. + +1. **Node 27 version:** as of 2026-11-08 the latest Node 27 release is Alpha. Pin the latest available 27.x release at each build by exact version/commit and verified checksum/signature; do not fetch a floating `latest` artifact. If the selected build is prerelease, label the resulting artifact pre-release/experimental and validate its actual API/ABI rather than waiting for stable or silently using another major. If no Node 27 build is available, pause artifact assembly until one is published. +2. **SEA/VFS contract:** use the exact Node 27 alpha source/docs for discovery, then verify every API and behavior against the exact latest Node 27 build selected for the artifact (stable or prerelease). Node 27 provides `node --build-sea ` with `main`, `mainFormat`, `executable`, `output`, `useVfs`, `vfsArchive`, `assets`, `execArgv`, and `execArgvExtension`; the VFS module loader serves CommonJS/ESM modules from the mount. `vfsArchive` embeds a ZIP as-is, inflates files on access, and Node 27 alpha documents Worker-thread remounting from the archive; plain `assets` mode does not offer that worker remount. VFS is Stability 1 / early development, SEA is Stability 1.1 / active development, and `node:vfs` itself is experimental. `useVfs` cannot be combined with `useSnapshot` or `useCodeCache`. Node docs conflict on native addons: SEA docs say `.node` files must be materialized for `process.dlopen()`, while the Node 27 VFS loader/source/tests show automatic loading through a private real image. Do not bake either assumption in: spike native addons and their dependent shared libraries on the exact target release; native executables and tools that demand a real path still require signed payload materialization. `vfsArchive` and `assets` are mutually exclusive; archive entries are read through `fs`, not `sea.getAsset()`. Validate the full ZIP yourself because the builder's archive validation may be shallow. Node VFS is not a security sandbox, and a source-level Node 27 implementation discrepancy suggests the in-memory ZIP VFS may be writable despite read-only documentation; test that property and do not rely on it as an integrity boundary. The mount path is runtime-selected, and in VFS mode the main script's `__dirname`/`import.meta.dirname` is the VFS root. CJS resolution can still consult `NODE_PATH` and global folders; set `--no-global-search-paths` and package `execArgvExtension: "none"` unless compatibility evidence requires a documented alternative. Prove helper entrypoint and child-process behavior. Verify Node 27 compatibility despite cdxgen declaring engines through Node 25. Use `--build-sea`, not the older `--experimental-sea-config`, unless the pinned docs establish a necessary exception. Record evidence and limits in the reviewed ADR. +3. **OS/architecture matrix:** evaluate macOS arm64/x64, Linux glibc x64/arm64, Windows x64/arm64 against Node SEA and each helper's availability, launch semantics and signing support. Reviewed Node 27 docs/source describe macOS x64 SEA as unsupported/experimental and skip SEA tests there; treat darwin-x64 as provisional and publish only if the exact selected Node 27 runtime passes a release-grade SEA build, signature injection, and smoke validation. Alpine/musl is excluded by the reviewed SEA docs; do not promise a musl target unless a supported Node SEA build is demonstrated. The current upstream `BUILDING.md` states Linux glibc minimums of 2.34/kernel 5.14, macOS 13.5+, Windows 10/Server 2016+; confirm these against the exact selected Node 27 binary and expose the minimums in artifact metadata. Windows ARM64 is Tier 2 in that source and needs native runner coverage. These are core-runtime/target artifact constraints, unlike a missing helper, which disables only its own capability. Publish a per-artifact capability manifest. Discovery found a Coana defect: cached Coana 15.14.0 `tree-sitter-ruby` under `analyzers/bundle/node_modules/tree-sitter-ruby/prebuilds/linux-arm64/` is x86-64 ELF (same build ID as x64), while adjacent tree-sitter core is AArch64. Either replace it with a working AArch64 payload or mark Coana Ruby analysis unavailable on Linux ARM64. Require ELF/Mach-O/PE header and architecture checks for every native payload. +4. **Signing and release (decision fixed from archived native repo):** adapt `/Users/jdalton/projects/socket-cli-native` CI-only signing path and receipt model. Reuse `fleet/apple-sign.mts`, `fleet/apple-notarize.mts`, strict Apple signature verification and temporary-keychain helpers through tracked workflow code; credentials stay in CI. Preserve and verify upstream signatures on inner native payloads where present; only apply ad-hoc signing to a helper when the existing install/launch baseline or target runtime requires it. Then hash/embed final payload bytes, build/inject the outer SEA, Developer ID sign it, and submit a ZIP containing the bare Mach-O for notarization (Apple does not staple a ticket to a bare CLI Mach-O). Verify expected identity and notarization on downloaded/quarantined bytes, then compute final hashes and provenance. Preserve an accepted notary submission receipt and notary log where available; do not infer that an outer SEA notarization fully evaluated opaque VFS members. The existing native workflow's cross-target jobs qualify transferred artifacts on native runners and its coordinator binds artifact hashes to a source SHA/run. Its inspected workflow checks the requested tag and its build script compares the selected source SHA, but it does not declare an explicit protected GitHub Environment; the SEA workflow must add that protection and reject unauthorized source SHAs before exposing signing credentials. Create a separate immutable SEA revision/tag namespace; bind each revision to root Socket version, exact source SHA, Node/helper manifest and target. Do not make Authenticode a prerequisite because the established native release does not provide it; only claim such signing if a distinct approved Windows signer is introduced. Target omission follows Node SEA support and actual native qualification. This is no longer a provider discovery gate; remaining work is to implement the SEA-specific jobs/receipts and verify the exact produced bytes. The default is to preserve the bytes/signatures and launch behavior of tools already acquired and executed through the current npmx/DLX/package-manager paths. Ad-hoc inner signing or app-owned quarantine cleanup is conditional on target evidence, not a blanket rewrite. +5. **Python scope:** identify which exact Python CLI(s)/commands are intended. Choose a redistributable runtime per platform/architecture and include required standard library, extension modules, shared libraries, modules, and licenses. Python is not a portable lone executable; test loader paths, certificates, symlinks, and extension ABI. +6. **Coana redistribution:** verify whether every supported Coana component can be staged at build time and redistributed. Preserve size/SHA-256 validation and licensing. Runtime fetch is forbidden; `--reach-version` accepts only a version embedded in the signed artifact and otherwise fails before execution. +7. **Release distribution:** current `publish-npm.yml` creates and publishes immutable `vX.Y.Z` GitHub releases without binary assets; live releases have empty asset sets, and active tag rules prevent updating/deleting `v*`. The existing artifact transfer action only accepts exactly three npm tarballs. Prefer a separate SEA release/tag namespace and monotonically increasing standalone revision so Node/helper security rebuilds do not require an npm release/version change; map every artifact to the exact Socket version/source SHA. If sharing a GitHub release is chosen, add a coordinator that stages every declared SEA target plus npm tarballs before the single draft publication. Define target allowlist/completeness, collisions, retries, partial failure recovery, provenance source SHA, and `v1.x latest=false`. Do not attach SEA assets after publishing an immutable npm release; changed bytes require a new identity. +8. **Artifact budget:** agree on max per-target compressed/uncompressed size and cold-start extraction cost after inventory reports real numbers. + +9. **Capability taxonomy and UI:** map each user-visible command/flag to one or more capabilities and required payload IDs. Decide whether partial `manifest cdxgen` coverage is presented as ecosystem-level sub-capabilities or a single cdxgen capability, and make unsupported reasons discoverable through help/version/diagnostics. The CLI must not imply broad cdxgen, Coana, JVM, Bazel, or Python support when only a subset of the relevant native/tool closure is present. +10. **Tool download closure:** trace every child tool's own provisioning behavior, including cdxgen Atom, nvm Node, SDKMAN Java/build tools, rbenv Ruby and `gem install bundler`; Coana analyzer fetches, `uv tool run --from installer`, `uv python install`, pyenv/Python and Go toolchain provisioning; Bazelisk Bazel; Maven/Gradle/sbt wrappers; Python package managers; container engines; and package-manager shadows. cdxgen calls `prepareEnv()` from its CLI entrypoint even though Socket defaults lifecycle to `pre-build`; verify and remove every reachable helper bootstrap. Its Maven resolver invokes a project `mvnw wrapper:wrapper` before selecting `MVN_CMD`/`MAVEN_CMD`. The sbt facts path creates a fresh global base and sbt provisions Scala under its boot directory, so a warm `~/.sbt` is not proof of closure. Coana Python also runs external `which` (replace with direct executable resolution or classify that sub-capability unavailable), installs helper packages with `uv tool run --from installer`, creates a fresh Mambalade venv, and has pip/wheel fallback paths; bundle the helper wheels/installer or disable that sub-capability. Also trace rustup-mediated Cargo, Gradle toolchain resolvers and Bazel repository rules for automatic runtime acquisition. For each launch choose one: ship the selected tool/runtime distribution; use a direct API or in-process library; honor the user's explicit external override; or mark only the affected capability unavailable. For Coana Go analysis, project Go modules may resolve as project inputs, but Go toolchain acquisition is prohibited; select a bundled Go version and set `GOTOOLCHAIN=local`, or mark that analyzer capability unavailable. Disable automatic pyenv/uv Python acquisition in embedded-default mode. Project dependency/plugin downloads explicitly requested by analysis remain a separate allowed category. +11. **Override and inherited environment contract:** the current plan preserves explicit tool paths; finalize precedence and determine which ambient `PATH`, `JAVA_HOME`, Python, npm config, proxy/certificate and wrapper variables intentionally override embedded defaults. A valid explicit override must select the external tool; unset defaults use embedded bytes; invalid overrides fail without fallback. Define which child environment variables are forwarded and how to prevent accidental shadowing. Audit the copied `@socketsecurity/registry` spawn semantics: its `options.env` is merged over ambient `process.env`, so a nominal allowlist may still leak omitted variables. SEA-owned spawn paths need true replace-env semantics; inspect `coana-release.mts` and socket-patch which currently spread ambient env. Test with sentinel secrets and loader-injection variables (`NODE_OPTIONS`, `JAVA_TOOL_OPTIONS`, `PYTHONPATH`) to prove only intentionally forwarded values reach children. +12. **Package-manager operations versus helper resolution (decision fixed):** preserve today's `npm`, `npx`/`npmx`, `pnpm`, `yarn`, raw manager and `socket optimize` semantics to the extent those flows work with the target's bundled, platform-compatible Node/npmx runtime and selected package manager. Bundle the best compatible target variants of executable/runtime/package-manager components that these Socket command paths currently require; do not introduce a new restriction merely because a component is normally obtained through the existing `npmx`/`dlx` mechanism. If a selected variant cannot be embedded or does not work on one target, mark only the affected command capability unavailable there with a clear diagnostic. Do not let a supported command bootstrap Socket-owned tools at runtime. Arbitrary user-requested package resolution remains the same user-directed network/package behavior as today. `socket optimize` detects npm, pnpm, Yarn Classic/Berry and Bun; Vlt is detected but Optimize rejects it because it lacks needed override behavior. Bun may parse `bun.lockb`; Optimize runs the chosen manager to modify/install the project lockfile. Honor explicit manager/runtime paths according to the override policy. +13. **Native dependency and ABI closure:** define checks for executable format/architecture, libc/loader, Node ABI/N-API, shared-library dependencies, macOS deployment target, Windows runtime DLLs, executable modes, symlinks and codesigning. Fail only the affected capability if validation fails. Generate the matrix from actual payload headers and target-native smoke results, not package metadata claims. +14. **Redistribution and notices:** establish license provenance for Coana CLI/analyzers and its wheels/native payloads, cdxgen's embedded JARs (including Soot/JNA), Java/Python distributions, plugin binaries and all helper closures. Missing license terms can make that payload unavailable; preserve other capabilities. Define required notices/source offers and SBOM component granularity. +15. **Runtime update lifecycle:** set ownership and cadence for updating Node 27 and every embedded helper; define CVE response SLA, support branches, rebuild reproducibility, and behavior for stale artifact detection. Embedded tools do not self-update; updates ship as a newly signed standalone artifact. +16. **Artifact layout/install/uninstall:** settle executable naming, archive/package format per OS, install paths, extracted resource cache location and permissions, multi-version coexistence, upgrade/rollback, uninstall cleanup, and package form for the archived ZIP-based notary submission (a bare Mach-O cannot be stapled). Keep user cache and project files outside app-owned cleanup. +17. **Credential/API flow:** verify Socket auth/config lookup and token refresh from SEA, redact secrets in child env/logs, support proxy/custom CA behavior, and ensure a bundled helper cannot inherit credentials it does not need. Define API-backed core CLI behavior as distinct from helper download/network policy. +18. **Supported command boundary:** inventory the full cdxgen CLI options actually passed by Socket and all reachable modes after merging CLI flags, project `.cdxgenrc`/`.cdxgen.json/.yml/.yaml`, environment and defaults. Socket's `pre-build` lifecycle does not prove `prepareEnv()` cannot bootstrap; deep mode can invoke Cargo independently of `install-deps`. Decide which modes need OS package managers, container runtimes, .NET 10, Swift/Xcode, Ruby/Composer/Go/Cargo, SDKMAN/nvm/rbenv or remote services. Any mode not represented by a working target payload must be rejected before preparation starts, not after it launches a downloader. +19. **Release artifact identity and source authorization:** prefer separate SEA version/tag identity with an independently incremented standalone revision mapped to Socket version and source SHA. Specify target allowlist/omissions, capability-manifest inclusion, checksum/provenance verifier, draft retry rules and no-replacement policy. The signing workflow must validate that the selected source SHA is authorized by protected release branch/tag policy; workflow dispatch SHA and checked-out source SHA are distinct. Keep trusted workflow code on a protected ref, reject unauthorized source commits before exposing signing credentials, and attest final downloadable subjects with workflow identity/run, source SHA, Node/helper input-manifest digest, capability manifest and SBOM. Test substitution of wrong source, target, run, manifest and final bytes. A capability change after signing requires rebuilding/re-signing/re-attesting the artifact, not editing a sidecar. Publishing a subset of targets must accurately disclose omissions. + +#### Provisional Node SEA target baseline + +These are discovery statuses from Node commit [`fe34c8e`](https://github.com/nodejs/node/tree/fe34c8eae5514797d6dc21a4bdec39c9913d9322), not release promises. Recheck against the exact selected Node 27 binaries/docs before building. Upstream [`SEA platform support`](https://github.com/nodejs/node/blob/fe34c8eae5514797d6dc21a4bdec39c9913d9322/doc/api/single-executable-applications.md#platform-support), [`SEA test exclusions`](https://github.com/nodejs/node/blob/fe34c8eae5514797d6dc21a4bdec39c9913d9322/test/sea/sea.status) and [`platform requirements`](https://github.com/nodejs/node/blob/fe34c8eae5514797d6dc21a4bdec39c9913d9322/BUILDING.md#platform-list) produce this initial core matrix: + +| Artifact target | Provisional baseline | Core SEA disposition | +| --- | --- | --- | +| `darwin-arm64` | macOS 13.5+, Node Tier 1 | Candidate; validate target-native VFS, injection, signing and first-launch behavior. | +| `darwin-x64` | macOS 13.5+, Node Experimental | Provisional/unavailable until the selected Node build demonstrably supports SEA; current source says unsupported and skips SEA tests. | +| `linux-x64-glibc` | kernel 5.14+, glibc 2.34+ | Candidate; validate Node binary/runtime and artifact on minimum baseline. | +| `linux-arm64-glibc` | kernel 5.14+, glibc 2.34+ | Candidate; validate target-native Node/SEA build and artifact. | +| `win32-x64` | Windows 10/Server 2016+, Node Tier 1 | Candidate; validate injection, Authenticode and native process behavior. | +| `win32-arm64` | Windows 10+, Node Tier 2 | Candidate only with native runner coverage and verified signing route. | +| `linux-x64-musl` / `linux-arm64-musl` | Distinct libc targets | No artifact until a supported Node SEA build and complete helper closure are demonstrated; Alpine is excluded by current docs. | + +The SEA injector recognizes target ELF/PE/Mach-O bytes rather than inferring them from the builder host. Pin builder and target Node to the exact same version and validate the upstream build configuration includes SEA/LIEF support. For custom builds verify shared Node/ICU/OpenSSL configuration and record the exact binary hashes. Node support for a core target is a product-level artifact gate; helper failures remain capability-local. + +#### Initial helper capability findings + +These are candidate dispositions from static payload/header review only; “candidate” is not a support claim until native-host integration and signing tests pass. `darwin-x64` rows are conditional on core SEA becoming supported. Windows Coana limits are independent of other Windows features. + +| Capability | `darwin-arm64` | `darwin-x64` | `linux-x64-glibc` | `linux-arm64-glibc` | `win32-x64/arm64` | +| --- | --- | --- | --- | --- | --- | +| Core/API commands | Candidate | Core SEA unavailable/provisional | Candidate | Candidate | Candidate | +| `socket patch` apply/rollback | Matching Mach-O candidate | Matching Mach-O payload, core SEA gate | Static PIE candidate | glibc-linked AArch64 candidate | Matching PE candidates | +| Coana reach JS/Go/PHP/Rust | Matching payload candidates | Matching payload, core SEA gate | Matching payload candidates | Matching payload candidates | Unavailable: Coana rejects Windows | +| Coana Ruby reach | Matching addon header candidate | Matching addon, core SEA gate | Matching addon candidate | Unavailable until mispacked x86-64 addon is replaced | Unavailable: Coana rejects Windows | +| Coana fix computation | Candidate, separate smoke needed | Candidate, core SEA gate | Candidate, separate smoke needed | Candidate; Ruby reach defect does not imply all fixes fail | Unavailable: explicit Coana Windows guard | +| cdxgen base + Synp | Candidate | Conditional on core SEA | Candidate | Candidate | Candidate | +| cdxgen .NET deep/DOSAI | Requires bundled .NET 10 shared runtime | Same, and core SEA gate | Same | Same | Same | +| cdxgen evidence/include-crypto | SQLite N-API closure pending | Same, and core SEA gate | Same | Same | Same | +| cdxgen Swift semantic/evidence | SourceKitten mode and runtime closure pending | Same, and core SEA gate | Swift runtime libraries missing | Swift runtime libraries missing | Unavailable with current plugin closure | +| `scan create --uv-members` | Bundled uv 0.12.15 staged and archive-checksum/version-verified; integrated SEA build verified | Core SEA gate | Bundled uv 0.12.15 staged and archive-checksum/version-verified; host-native SEA qualification pending | Bundled uv 0.12.15 staged and archive-checksum/version-verified; host-native SEA qualification pending | Bundled uv 0.12.15 staged and archive-checksum/version-verified; host-native SEA qualification pending | +| Python/Bazel/JVM | Separate runtime/tool/version closure pending | Core SEA gate | Separate runtime/tool/version closure pending | Separate runtime/tool/version closure pending | Separate runtime/tool/version closure pending | + +The Linux ARM64 `socket-patch` package requires glibc's `/lib/ld-linux-aarch64.so.1`; the npm package name does not imply musl support. Coana's SPAR/Goana files being statically linked or named `musl` does not make its tree-sitter/Python closure musl-compatible. The Linux-musl cdxgen packages also need staging fixes for Trivy executable mode and DOSAI resolver names; those defects do not affect glibc cdxgen rows. Promote candidate rows only after checking final signed hashes, actual slices/headers, loader and dynamic dependencies, minimum OS/libc, modes, and a representative command for the exact feature trigger. + +## Source-derived helper and external-tool inventory + +This inventory is based on production source call sites, not package-name guesses. It is a starting verified list; implementation must repeat the scan after changes and classify every process spawn that can affect a user command. + +| Tool/path | Exact source behavior | Current version source | Standalone packaging direction | Boundary / caveat | +| --- | --- | --- | --- | --- | +| `@cyclonedx/cdxgen` | `src/utils/dlx.mts` `spawnCdxgenDlx`; called by `src/commands/manifest/run-cdxgen.mts` for `manifest cdxgen`. | Root devDependency `12.1.2`, inlined from package metadata by `.config/rollup.base.config.mjs`. | Bundle exact JS package closure and target-compatible native/data assets; invoke directly through resolver. | cdxgen declares Node engines `^20, ^22, ^24 or ^25`, excluding Node 27. The CLI calls `prepareEnv()` before `createBom`; Socket's `pre-build` lifecycle is not itself proof that no tool bootstrap runs. It can use nvm Node, SDKMAN Java/build tools, rbenv Ruby and `gem install bundler`; Maven resolution probes a project `mvnw wrapper:wrapper`. Remove/disable those acquisition paths for embedded operation or make only the corresponding ecosystems unavailable. Inventory every cdxgen launch and license. Optional plugin contents vary by target: the x64 plugin package omits osquery (the ARM64 package contains a universal x64/arm64 osquery candidate, relevant only if x64 SEA becomes viable), Linux musl has missing tools and resolver naming/permission gaps, dosai requires the .NET 10 shared runtime on every packaged OS/architecture variant, and Atom brings Java 21+ with a large native/JAR closure. cdxgen's Ruby parser package contains Linux x64 native extensions, not a portable Ruby runtime. SQLite is loaded for evidence/include-crypto paths and its package currently has no shipped `.node` binary, so gate those options until the target N-API closure is built and verified. SourceKitten payloads are non-executable mode 0644 and their Linux binaries require Swift/Foundation libraries absent from the plugin package; gate Swift semantic/evidence support until the complete runtime closure works. Define support at ecosystem/feature granularity and clearly disable only the missing ecosystem features on affected targets; npm package presence alone does not prove ecosystem feature parity. | +| `synp` | `spawnSynpDlx`; only production call is `manifest run-cdxgen.mts`. For Node ecosystem manifests with a Yarn lock and no package-lock, runs `synp --source-file ./yarn.lock`; on success tells cdxgen to analyze as npm. Current cleanup uses an exit callback and an ownership boolean; standalone implementation must use an owned temporary path or safe ownership check, and cleanup on success, failure, cancellation and spawn errors without deleting a user-created lockfile. It is not used by `socket optimize`. | Root devDependency `1.9.14`, inlined from package metadata. | Bundle exact JS package closure; preserve exact args, project cwd, success/failure fallback and temporary-file cleanup. | Synp API `yarnToNpm(packageDir)` reads `yarn.lock`, `package.json`, and existing `node_modules`; it does not install/download. Initial support should be Yarn Classic only. Gate Yarn Berry (the parser is `@yarnpkg/lockfile` v1), workspace conversion (`withWorkspace` is experimental), and incomplete install trees because Synp infers actual installed packages. Cleanup must use ownership-digest/identity tokens and a `finally` around cdxgen Worker completion. | +| `@coana-tech/cli` (Coana) | `spawnCoana` from scan reachability and fix flows; custom Socket API component resolution/cache, not generic npx. | `COANA_CLI_VERSION` in `src/constants.mts` (`15.14.0` at research time); optional command override. | Stage the pinned default component plus every analyzer/helper subcomponent it would otherwise acquire into the signed target payload; remove runtime acquisition/fallback for embedded defaults. Honor explicit supported local-path or version selectors as external overrides; never fetch a missing override implicitly. | Coana 15.14.0 source calls `fetchReleaseComponents(...['analyzers'])` when `REPOS_PATH` is absent; transitive analyzer payloads are therefore in scope. It also runs external `which`, can invoke `uv tool run --from installer==0.7.0`, creates a fresh Mambalade venv and can install pip/wheel, provisions Python through uv/pyenv, and can fetch a Go toolchain even in dependency-offline mode. Resolve `COANA_UV_EXECUTABLE`, `COANA_POETRY_EXECUTABLE`, and `REPOS_PATH` explicitly; disabling project dependency downloads does not disable these helper/runtime bootstraps. Its source rejects Windows for both reachability analysis and fix computation/upgrading, so both Coana-backed capabilities are unavailable there unless another supported backend is bundled. The cached Linux ARM64 Ruby analyzer contains x86-64 ELF instead of AArch64; either repair it or disable the affected Ruby analysis capability on that target. Coana's cached release lacks LICENSE files; verify redistribution rights before claiming Coana support. | +| `@socketsecurity/socket-patch` | `src/commands/patch/cmd-patch.mts` resolves package binary and spawns it. | Root production dependency `2.0.0`. | Include correct Rust executable for each supported target; invoke through resolver without `node_modules/.bin`. | Verify package artifact contents, native ABI/target coverage, license and platform signing. | +| Git | Scan/CI infer repository, remote, branch and commit data; fix flows perform checkout/add/commit/push/reset/clean/diff; see `src/utils/git.mts`, `src/commands/scan/cmd-scan-create.mts`, `src/commands/ci/handle-ci.mts`, `src/commands/fix/coana-fix.mts`. | Currently resolved from host PATH; project/user installation. | Either bundle pinned per-target Git plus required transport/credential integration, replace bounded metadata calls in-process, or mark only Git-dependent sub-capabilities unavailable. | Separate `git.metadata` from `git.mutation/transport`; SSH, credential helpers, hooks and remote transports are separate closure items. API-backed scan still works when optional Git inference is unavailable. | +| `uv` | `src/commands/scan/generate-uv-member-sboms.mts` spawns `uv export` for explicit `--uv-members`. | Embedded build pin `0.12.15` in `src/sea/uv-pins.json`; explicit `SOCKET_CLI_UV_PATH` override remains supported. | Build staging fetches target-specific GitHub release archives, verifies pinned SHA-256, safely extracts only the executable, validates architecture/version, includes MIT/Apache texts and digest metadata in VFS, and extracts to an app-owned temporary directory at runtime when no override is set. Preserves `export --frozen --offline --no-python-downloads`; no fallback to PATH/network. | Integrated darwin-arm64 SEA build succeeded. Linux glibc and Windows pins are staged by the same helper but need native-host SEA validation. Rust transitive-crate license inventory is unresolved; uv capability is technically available in the prototype but production redistribution remains unqualified. Bundling uv does not bundle Python or all Python scanning support. | +| Bazelisk/Bazel | Bazel manifest discovery prefers Bazelisk, which honors workspace `.bazelversion`; that can bootstrap/download a Bazel binary. | User PATH/workspace pin today; repo CI currently pins Bazelisk 1.26.0 and Bazel 7.4.1. | Embed approved Bazelisk and a bounded set of Bazel versions; route Bazelisk to embedded versions only, or resolve supported version and fail before network bootstrap. | Required Bazel path cannot fall back to downloading Bazel. Workspace repository/rule downloads are project-input resolution and need separate network policy. | +| Java/JDK | Bazel JVM extraction checks `JAVA_HOME`/PATH; Maven, Gradle and sbt launchers need a Java runtime, and Maven wrapper's downloader may use javac/java. | User environment/project toolchain today. | Bundle the best compatible per-target Java runtime/toolchain; if unavailable, mark only affected JVM/Bazel capabilities unavailable. | Validate native library needs, licensing, architecture and any toolchain minimums; tests must run with no host Java. | +| cdxgen optional/native packages | Locked `@cyclonedx/cdxgen` closure includes optional `@appthreat/atom`, `atom-parsetools`, `@appthreat/sqlite3`, `@cdxgen/cdxgen-plugins-bin` and OS-specific plugin-bin packages. | cdxgen `12.1.2`, optional packages pinned by its package manifest/lockfile. | Generate per-target closure from lockfile/package metadata, including native addons, plugin executables, and required Node/Java runtimes; do not use only the developer host's installed optional packages. Preserve executable modes and verify cdxgen's platform-specific binary resolver names against shipped files. | cdxgen declares Node engines `^20, ^22, ^24 or ^25`, excluding Node 27. `@appthreat/atom` invokes Node via `NODE_CMD`/PATH and requires Java 21+; pre-generation may call `nvm install`, which must be disabled/replaced or explicitly fail when the requested project Node version is not locally supported. Native addon loading differs between SEA/VFS docs and source. Audit nested notices: the Atom closure includes LGPL-licensed Soot and JNA's dual license, and Coana's cached release has no license file. | +| Python / `python3` | Python probing/shim in Bazel manifest discovery (`bazel-python-shim.mts`); Python also appears in cdxgen ecosystem subprocesses and test scripts. | Currently resolved from the environment or helper-specific dependency; SEA must resolve Socket-owned Python work to the embedded runtime. | Bundle the pinned Python runtime and modules needed by capabilities declared available; if unavailable on a target, report affected Python-backed features as unavailable without blocking other features or downloading Python at runtime. | Tests/scripts using Python are not production runtime evidence; separate test tooling from shipped behavior. | +| Gradle, Maven, sbt and project wrappers | Manifest conversion/facts commands invoke wrappers or user-selected PATH tools; Maven wrapper may download Maven, Gradle/sbt projects may download their pinned distributions/dependencies. | Project wrapper/config or user PATH. | Bundle the supported tool distributions and prevent wrappers from downloading another distribution at runtime. Keep project dependencies/plugins as project inputs. Enumerate supported project-declared versions; reject unbundled versions before execution. | The standalone artifact supports an explicit matrix of bundled tool versions; arbitrary wrapper-selected versions are rejected before wrapper startup, which prevents the wrapper from downloading its own distribution. Sbt provisions Scala under its fresh `sbt.global.base/boot`; bundle that selected compiler/launcher closure or mark the affected sbt facts capability unavailable. Do not rely on a warm user `~/.sbt` cache. | +| Blessed TUI (`blessed`, `blessed-contrib`) | Dynamic requires in `src/commands/threat-feed/output-threat-feed.mts`. | Root pinned dependencies (`blessed` `0.1.81`, `blessed-contrib` `4.11.0`) with repo patches. | Include patched JS dependency closure in SEA/VFS; preserve dynamic require paths. | No native Blessed executable identified. Validate terminfo and pseudo-terminal behavior. | +| User package-manager operations | `socket npm/npx/pnpm/yarn`, `raw-npm`/`raw-npx`, and shadow launchers wrap the user-selected manager. `socket optimize` invokes manager-specific queries and installation in `src/commands/optimize/ls-by-agent.mts`/`src/utils/agent.mts`; it applies Socket overrides and does not call Synp or generic DLX. | User-installed manager and user-supplied package spec. Optimize supports npm, pnpm, Yarn Classic/Berry and Bun; Bun may parse `bun.lockb`; vlt is detected but rejected by Optimize. | Treat these as user-directed operations: use the explicitly selected/installed package manager, and fail clearly if the required manager/runtime is absent rather than downloading it. A separately bundled plain Node runtime may serve as the JS execution host only where invocation semantics require it; never execute manager scripts by treating the SEA executable as `node`. Do not use these operations as hidden fallbacks to acquire Socket-owned helpers. | Arbitrary user-selected packages cannot be prebundled; this exception does not permit helper/runtime/toolchain downloads. Corepack/packageManager resolution must not bootstrap a missing manager implicitly. | +| OS service integrations | Opening generated report URL (`open`, PowerShell, `xdg-open`), Blessed's optional tmux/version and terminal commands, Windows Bazel cancellation via `taskkill`, completion script sourcing, and shadow launcher shim files. | Host OS/service PATH and copied `dist` assets. | Split optional service integrations from core commands. Use browser URL fallback if opener unavailable; package completion/shadow scripts as persistent real-path assets or private SEA dispatch; invoke only documented OS services and report unavailable optional integrations cleanly. | These are not Socket helper downloads, but must be classified and tested. Threat-feed API JSON remains available independently of interactive TUI. | +| `dlxBinary` helper | `src/utils/dlx-binary.mts` implements URL binary caching, but current production-source search found no caller. | No active call-site pin. | Do not bundle it as a tool until a real production caller is found. | Re-run import/call graph scan during implementation. | + +### cdxgen source audit and first SEA capability boundary (2026-11-09) + +The installed root devDependency is `@cyclonedx/cdxgen@12.1.2`, Apache-2.0, lock integrity `sha512-kOyK3kdDhZDtRAhJ7/GpOPu6PWdc6622Jc9DPNHiua67m3hvEisUgptM7ssyOAdiycXmG9rDpy8t13E4doh/9A==`. Its CLI entry is `bin/cdxgen.js`; its ESM API is `lib/cli/index.js`. The package declares Node engines `^20 || ^22 || ^24 || ^25`, so Node 27 needs explicit qualification. Package-relative layout matters: helpers derive package root from `import.meta.url`, and eager data reads cover licenses/SPDX, ecosystem/framework inventories, aliases, OS data, crypto mappings, and schemas. Preserve the package tree and dynamic import paths in VFS. + +Do not invoke the general CLI for the first standalone capability. `bin/cdxgen.js` calls `prepareEnv()` before BOM generation even with `--no-install-deps`; that can install Node via NVM, and Rush has an unguarded install path. Broad API imports also probe the host by running Linux `ldd` and `pnpm root -g`. Generic `createBom()` performs container detection before ecosystem selection. The first candidate is direct `createNodejsBom()` with explicit npm project type, an existing `package-lock.json`, no dependency install, no Babel, no recursion, and no versioned runtime. Disable/suppress plugin import-time probes, reject unknown or widening `CDXGEN_*`/cwd config, and reject deep/evidence/crypto/formulation/server/protobuf/archive/container/Rush modes before cdxgen code can bootstrap anything. This remains unavailable until the API adapter and exact VFS closure pass a target-native smoke with helper process/network acquisition instrumented to fail. + +The npm-only boundary excludes substantial closures: Atom/Java plus JARs and Java/PHP/Ruby/Scala launchers; Python `piptree.js` plus interpreter/pip modules; SQLite native addon for evidence; SourceKitten/Swift runtime; Trivy/osquery/dosai native plugins; SDKMAN/NVM/rbenv/bundler and project tool wrappers. `uv sync` can install a managed Python. These are separate capabilities and remain unavailable until their full helper/runtime/data closure is bundled and qualified. Native plugin package signature files are not signature verification. cdxgen's Linux musl package also has missing tools/resolver and permission issues; dosai needs .NET 10; Ruby parser extensions are Linux x64-specific. Per-platform capability records must name the missing closure rather than infer support from npm package presence. + +The VFS Worker proof does not establish cdxgen compatibility: a Worker shares PID/cwd, and cdxgen or dependencies may launch native/JS children directly. Audit child execution for the npm mode, reject unexpected launches, and preserve explicit argv/env/stdin/out/error/exit semantics. Keep `runCdxgenDlx()` guarded for all unsupported modes so future callers cannot fall through to npm/pnpm/yarn DLX. + +Synp 1.9.14 is MIT with lock SRI `sha512-0e4u7KtrCrMqvuXvDN4nnHSEQbPlONtJuoolRWzut0PfuT2mEOvIFnYFHEpn5YPIOv7S5Ubher0b04jmYRQOzQ==`. Its API returns serialized package-lock content; the CLI adds validation/write/exit behavior. The local adapter currently uses exclusive creation and digest plus device/inode ownership checks. Preserve current failure fallback or surface a clear standalone diagnostic; never use broad cleanup that could remove a user lockfile. Its conversion depends on the installed `node_modules` graph and may omit optional packages absent on the machine that prepared it, so fixtures must establish accuracy and the user-project network policy must remain separate. + +### Existing override and executable-selection policy + +The embedded payload is the default, not a forced choice when the user has explicitly configured a tool path. For each existing environment-variable or CLI override, preserve its intended precedence: when unset, resolve the pinned embedded tool; when set to a valid path/version, use that explicit selection instead of the embedded tool. Do not reinterpret an explicit override as permission for Socket to download or install a missing tool. If the selected path is missing, invalid, incompatible, or cannot be executed, fail clearly without silently falling back to the embedded version or a download. Record override-specific compatibility and network behavior in the ADR and user docs. This policy applies to Socket-owned helper selection; user-project build-tool and interpreter selection remains subject to the frozen supported matrix and no-bootstrap rule. + +| Existing selector | Current source | SEA policy | +| --- | --- | --- | +| `SOCKET_CLI_COANA_LOCAL_PATH` | `src/utils/coana-release.mts` | When unset, use the embedded pinned Coana component. When set, execute the configured local path (including a deliberate wrapper path) instead of the embedded component, after validating it exists and is executable for the target. Never download as fallback. Document that the override selects externally managed code and may have its own network behavior. | +| `COANA_UV_EXECUTABLE`, `COANA_POETRY_EXECUTABLE` | Coana 15.14.0 CLI environment handling | When unset, resolve the bundled compatible executable/runtime; when explicitly set, honor the selected external path and validate it. Never use uv/Poetry to install a missing Socket helper. | +| `REPOS_PATH` | Coana analyzer repository path | When set, honor the explicit local analyzer path; when unset, use bundled analyzer payloads. Never fetch analyzer components in standalone mode, including when the supplied path is invalid. | +| `GO`, `GOTOOLCHAIN` and Go-related PATH | Coana Go analyzer | Resolve the bundled Go version when not explicitly overridden; prevent Go's auto-toolchain acquisition (`GOTOOLCHAIN=local`). Project Go modules remain project inputs. An unavailable Go version disables only Go analysis. | +| `--reach-version`, `--fix-version` | `src/commands/scan` and `src/commands/fix/cmd-fix.mts` | `SOCKET_CLI_COANA_LOCAL_PATH` has highest precedence and, when set, selects that validated external executable. Otherwise default to the embedded version. A version option may select only a version already embedded for the target or already available through a user-managed local installation supported by the existing CLI contract; it must never trigger Socket-managed fetch/install. An unavailable version fails clearly before execution. Apply the same precedence and validation to both flags; no fallback after an explicit invalid selection. | +| `--bazel` | `src/commands/manifest/bazel/bazel-bin-detect.mts` | Honor an explicit executable path instead of the embedded Bazel selection, including an intentional user wrapper, subject to documented invocation semantics. Do not mistake explicit selection for permission to let Bazelisk bootstrap an unbundled Bazel; reject or disable that bootstrap before execution. | +| Maven/Gradle/sbt `bin` and project wrappers | `src/commands/manifest/scripts/build-tool.mts` | Honor explicit project wrapper/bin selection instead of the embedded distribution where that is current CLI behavior. Inspect the selected version and prevent wrapper-driven tool distribution downloads; use a local distribution already present or fail with an actionable message. Project dependencies/plugins remain project-input resolution. Current wrapper names are POSIX-specific; decide and test Windows behavior before declaring that target supported. | +| `PATH`, `JAVA_HOME`, Python/uv environment | `src/commands/manifest/bazel/bazel-process.mts`, `bazel-java-shim.mts`, `bazel-python-shim.mts`, uv call sites | For Socket-owned helpers with no explicit selector, prefer the embedded path. Where the existing contract intentionally uses PATH/JAVA_HOME or a project-selected interpreter, honor that explicit environment selection instead of the embedded tool, validate availability/compatibility, and fail rather than download if absent. Construct child environments deliberately and document precedence so unrelated inherited PATH entries cannot accidentally shadow embedded helpers. | + +The ADR must list every environment variable and CLI selector by name, current source behavior, whether it overrides the embedded default, precedence, supported path/version formats, executable type, compatibility checks, and whether the selected tool may perform its own network requests. Distinguish intentional user-selected external execution from hidden helper acquisition in the network-purpose policy. Test each selector unset/set, precedence against the embedded default, valid and missing paths, malicious PATH/JAVA_HOME, sentinel secret variables, `NODE_OPTIONS`/`NODE_PATH`, `JAVA_TOOL_OPTIONS`, `PYTHONPATH` and native loader variables, symlinked and wrapper executables, `.cmd`/shell scripts, wrong version, and absence of download fallback. Verify the spawn adapter truly replaces inherited `process.env`; the support-library spawn helper merges ambient values beneath `options.env`, while current Coana and socket-patch paths explicitly spread ambient env. Explicit selectors should be honored when valid; tests must not require every selected executable to be embedded. + +**Source-crawl completion check:** search production source (excluding tests/fixtures) for `spawnDlx`, `spawnCdxgenDlx`, `spawnSynpDlx`, `dlxBinary`, `spawnCoana`, `spawn`, `execFile`, `exec`, `npx`, `npm exec`, `pnpm dlx`, `yarn dlx`, `bunx`, `pipx`, `uvx`, `python`, and dynamic executable resolution. For each result classify: (A) embedded runtime payload acquired and verified at build time, (B) Socket API or project-input data fetched at runtime, (C) user-requested package-manager execution, (D) test/build-only, (E) explicit external tool override, or (F) OS service/ambient project tool with a named availability contract. Any runtime executable/toolchain acquisition discovered is a plan defect and must be embedded or cause the affected feature/version to fail before launch. Add a test or documented rationale for each production runtime result. Search transitive helper behavior (especially cdxgen, Coana, uv, Python CLIs, and Maven/Gradle/sbt wrappers), not just Socket direct calls. Any binary/runtime download reachable from a supported Socket command is in scope and must become a build-time artifact input. + + +## Dependency removal and owned implementations + +This workstream is a first-class part of the standalone artifact, not a post-build cleanup. The goal is to stop depending on the Socket support library (`@socketsecurity/registry`, the root source dependency matching the described role) and `@socketregistry/packageurl-js` where the CLI uses only specific methods. Copy only the specific methods/types required into clearly owned Socket CLI modules, then remove the dependency references and prove the package still behaves identically. Do not copy whole packages, generated bundles, or unrelated utilities. + +### Confirmed package URL use + +Current direct usage is visible in: + +- `src/utils/purl.mts`: imports `PackageURL` and `PurlQualifiers`; constructs instances, parses with `PackageURL.fromString`, and exposes local create/get/normalize helpers. +- `src/utils/socket-url.mts`: uses `PackageURL` as a type through `getPurlObject`. +- `src/utils/spec.mts`: uses `PackageURL` as a type for version resolution. +- `package.json` directly lists `@socketregistry/packageurl-js` and package.json `pnpm.overrides` maps `packageurl-js` to that package. Remove both references if unused after migration; update lockfile and any workspace/importer catalog consistently. + +The root package directly depends on `@socketsecurity/registry` (currently `1.1.17`), imported through 395 production-source import declarations across its `lib/*` subpaths. The heaviest surfaces are `logger` (164 import lines), `debug` (55), `spawn` (34), `objects` (20), `spinner` (17), `arrays` (17), `fs` (15), `prompts` (14), `strings` (12), `packages` (9), and smaller path/env/bin/url/regex/sort/promise/agent/stream/glob/constants helpers. This is the concrete support-library dependency to audit for the requested method-by-method ownership migration; treat `@socketsecurity/registry` as the candidate intended library and confirm package identity during plan review before removal. Do not remove it wholesale without mapping all used symbols. Existing comments, coverage reports, or bundled output are not authoritative source inventories. + +### Method-by-method extraction process + +1. **Establish provenance and scope.** Confirm whether the intended library is `@socketsecurity/registry` and identify its authoritative repository/version; enumerate every imported symbol used by root `socket` source. For package URLs, inspect the exact locked `@socketregistry/packageurl-js` implementation/version. Record each call site, symbol, edge-case behavior, license/copyright, and relevant upstream test vectors. +2. **Create a minimal API inventory.** For `@socketsecurity/registry`, inventory direct imported functions/types, root exports such as `getManifestData`, dynamic requires, constant internals, and build-script/Rollup consumers; map each symbol to helper closure and data files. For package URLs, define the precise in-scope contract: `PackageURL` fields/constructor/parser/serializer behavior and the qualifier type/normalization actually consumed by CLI code. Use import/reference searches plus TypeScript/compiler dependency analysis; generated `dist` bundles are not source of truth. +3. **Copy narrowly into owned modules.** Add focused modules such as `src/utils/package-url.mts` (or another repo-consistent name) and focused owned modules grouped by concern (for example logging, spawn, filesystem, package helpers), without retaining registry namespace naming unless needed for clear provenance. Copy only the individual methods needed, adapt imports to repo-owned types/helpers, retain essential upstream attribution/license notices, and add comments naming upstream source/version/commit and any intentional deviations. Do not copy unrelated exports or entire package trees. Include the minimal transitive helper/type/data closure proven necessary for each copied method; enumerate every copied dependency with provenance and tests. +4. **Keep the API internal and minimal.** Preserve existing call-site semantics with compatibility wrappers where that reduces churn, but avoid re-exporting a general package URL or socket-lib library as a new public API. Normalize thrown/invalid-input behavior and `throws: false` behavior explicitly. Preserve object shape, optional fields, qualifiers, namespaces, subpaths, versions, and serialization contracts used by the CLI. +5. **Remove dependencies comprehensively.** Remove direct dependency entries, the `packageurl-js` pnpm override if unused, aliases that exist only for these packages, bundler externals, ambient typings, package-specific checks, and build-time imports after confirming no other root-source consumer needs them. Regenerate the pnpm lockfile canonically. Migrate build bootstrap/config imports before removing the package so `pnpm build` remains functional. Reproduce required registry-owned manifest/extension JSON data with a documented source, license, update process and parity tests. Do not change separately vendored projects unless they feed the product. +6. **Verify dependency graph and output.** Use package manager dependency graph tools and Rollup metadata to prove root Socket-owned source/build code no longer imports the removed libraries. Record independently required helper copies in the target manifest/SBOM; do not require unrelated helper dependency graphs to remove their own legitimate implementation. Check npm pack contents/import closure as appropriate. Account for other packages that independently depend on packageurl-js; the goal is to remove Socket CLI's own use, not blindly eliminate a legitimate transitive dependency from tools such as cdxgen unless separately replaced and validated. + +### Behavioral and legal guardrails + +- Use upstream tests/specification as a differential oracle before changing call sites. Cover PURL parsing/serialization, encoding and normalization, scoped npm names, Maven namespace separators, qualifiers/subpaths, Unicode and reserved bytes, malformed escapes, empty/absent versions, invalid types, and error classes/messages where callers depend on them. Include round-trip and adversarial cases; do not silently weaken validation. +- Preserve Socket's existing `normalizePurl`, `createPurlObject`, and `getPurlObject` public/internal semantics unless a separate behavior change is explicitly approved. Keep project-specific policy layered outside the copied standards implementation. +- Keep copyright and license notices for copied code; verify license permits copying/modification and retain required attribution. Prefer a small clean-room reimplementation from the spec when upstream license or code provenance makes copying unsuitable, but document that choice and retain parity tests. +- Add focused ownership tests that do not import the removed dependencies. During migration, differential tests may temporarily compare old and new implementations; remove the old package from final runtime/test imports when the migration is complete. +- Run source and built-output scans to prevent accidental imports reappearing. Update dependency documentation and bundle inventory to show the maintained local implementation and its upstream/spec reference. + +### Acceptance gates for dependency removal + +- Root Socket-owned source/build bootstrap has no import or runtime resolution of `@socketsecurity/registry` or `@socketregistry/packageurl-js` after migration; direct aliases/overrides and lockfile importer edges are removed where no longer needed. Independent helper graphs such as cdxgen may retain their own packageurl dependency; inventory those separately and do not claim global absence. +- Every copied method is enumerated with source provenance, license handling, owned module, call sites, and test coverage. No unrelated upstream files or exports were copied. +- CLI PURL behavior passes the differential/spec corpus and all existing tests; consumers no longer rely on `PackageURL` class identity from an external package. +- Rollup production graph and standalone payload prove the removed implementations are not included as hidden transitive code. Any independent helper dependency is explicitly documented and does not undermine the claimed `socket` package reduction. +- Standard npm package behavior and the new SEA artifact both use the same owned implementation. No SEA-only divergent PURL behavior is allowed. + +## Proposed architecture + +### Build and payload + +1. Build only the root `socket` application at the same source revision/version as the intended release. Explicitly exclude `@socketsecurity/cli` and `@socketsecurity/cli-with-sentry` from product naming, package resolution, metadata, and release claims. +2. Produce a dedicated standalone entry and Rollup bundle for production JS. Put JS modules and ordinary data into SEA VFS. Put executables, native addons, interpreter files, dynamic libraries, and assets requiring filesystem paths into a target-specific resource payload. +3. Treat the Node 27 SEA executable as the product entrypoint, not a general Node CLI runtime. Include separately pinned, signed plain Node child runtimes only where actual helper or explicitly selected package-manager behavior requires `node