# External Tools Socket CLI integrates with external security tools for scanning, analysis, and vulnerability detection. This document explains how tools are bundled and executed in different deployment modes. ## Deployment Modes | Mode | Description | Tool Source | | ----------- | -------------------------------------- | ------------------------------- | | **SEA** | Standalone executable with bundled VFS | Tools pre-bundled at build time | | **npm CLI** | Installed via npm/pnpm/yarn | Tools downloaded at runtime | ## Tool Matrix | Tool | Type | SEA Mode | npm CLI Mode | | ----------------- | -------------- | --------------------------- | ----------------- | | @coana-tech/cli | npm | VFS (node_modules) | dlx download | | @cyclonedx/cdxgen | npm | VFS (node_modules) | dlx download | | opengrep | github-release | VFS (/snapshot/) | GitHub download | | python | github-release | VFS (/snapshot/) | GitHub download | | socket-basics | github-source | VFS (pre-installed) | N/A (SEA only) | | socket-patch | github-release | VFS (/snapshot/) | GitHub download | | socketsecurity | pypi | VFS (pre-installed via pip) | pip install | | sfw | hybrid | VFS (GitHub binary) | dlx (npm package) | | synp | npm | VFS (node_modules) | dlx download | | trivy | github-release | VFS (/snapshot/) | GitHub download | | trufflehog | github-release | VFS (/snapshot/) | GitHub download | ## Configuration All tools are defined in `packages/cli/bundle-tools.json`: ```json { "tool-name": { "description": "Tool description", "type": "npm | github-release | pypi | github-source", "version": "1.0.0", "checksums": { ... } } } ``` --- ## SEA Mode (Standalone Executable) SEA binaries contain all tools pre-bundled in a Virtual File System (VFS). Tools are extracted to a temp directory on first use. ### VFS Structure ```text /snapshot/ ├── node_modules/ # npm packages with full dependency trees │ ├── @coana-tech/cli/ │ ├── @cyclonedx/cdxgen/ │ ├── @socketsecurity/sfw-bin/sfw │ └── synp/ ├── opengrep/ # Standalone binaries ├── python/ # Python runtime + pre-installed packages │ └── lib/python3.11/site-packages/ │ ├── socketsecurity/ │ └── socket_basics/ ├── socket-patch/ ├── trivy/ └── trufflehog/ ``` ### Python Package Pre-bundling Python packages (`socketsecurity`, `socket_basics`) are installed at **build time** into the bundled Python: 1. Build downloads `python-build-standalone` runtime 2. Build runs `pip install socketsecurity==X.X.X` into bundled Python 3. Build copies `socket-basics` source into site-packages 4. VFS contains complete Python with packages pre-installed 5. Runtime skips pip install (checks `import socketsecurity` first) ### VFS Extraction Tools are extracted on first use to `~/.socket/_vfs/`: ```typescript // Detection if (isSeaBinary() && areExternalToolsAvailable()) { // Use VFS-extracted tool return spawnToolVfs(args, options) } ``` --- ## npm CLI Mode When installed via npm, tools are downloaded at runtime. ### Download Locations | Source | Cache Location | | --------------- | ---------------------------------------------------------- | | npm dlx | `~/.socket/_dlx/{package}@{version}/` | | GitHub releases | `~/.socket/_dlx/github/{owner}/{repo}/{version}/` | | PyPI | `~/.socket/_dlx/pypi/{package}/{version}/` | | Python runtime | `~/.socket/_dlx/python/{version}-{tag}-{platform}-{arch}/` | ### Download Flow ```text 1. Check local path override (SOCKET_CLI_*_LOCAL_PATH env var) └── If set, use local binary directly 2. Check cache └── If cached and valid, use cached binary 3. Download ├── npm packages: dlxPackage() from npm registry ├── GitHub releases: downloadGitHubReleaseBinary() └── PyPI packages: downloadPyPIWheel() 4. Verify integrity ├── GitHub releases / PyPI: SHA-256 checksum validation (required in production) └── npm packages: registry integrity only; the bundle-tools.json SRI is enforced in the SEA build, not on this path (see "npm tool integrity") 5. Extract and cache └── Save to ~/.socket/_dlx/ ``` --- ## Security ### Checksum Verification GitHub-release and PyPI downloads are verified with SHA-256 checksums defined in `bundle-tools.json`: ```json { "trivy": { "checksums": { "trivy_0.69.2_macOS-ARM64.tar.gz": "320c0e6af90b5733...", "trivy_0.69.2_Linux-64bit.tar.gz": "affa59a1e37d86e4..." } } } ``` Checksums are **required** in production builds. Dev mode allows downloads without checksums for testing. ### npm tool integrity The three `packageManager: "npm"` tools - `@coana-tech/cli`, `@cyclonedx/cdxgen`, and `synp` - pin a `sha512-` SRI in `integrity` rather than a per-asset sha256. Two links have to hold for that pin to mean anything: 1. **Tarball bytes against the registry's advertised hash.** npm's installer (cacache/pacote, driven by Arborist) does this and records the result in `node_modules/.package-lock.json`. 2. **That recorded hash against our pin.** `scripts/sea-build-utils/npm-integrity.mts` does this, and throws on a mismatch, a missing pin, or a missing record. Link 2 is what stops a registry-side substitution from passing as a pinned build; link 1 alone only proves the registry served what it said it would. > [!WARNING] > The **runtime dlx path does not enforce these pins.** `spawnDlx` > (`src/util/dlx/spawn.mts`) passes no `hash` to `dlxPackage`, the SRI values are > never inlined into the CLI bundle, and `@socketsecurity/lib` 6.4.0's > `ensurePackageInstalled` accepts a `hash` option and ignores it. A coana > download performed by the installed CLI is therefore checked by npm against the > registry, but not against `bundle-tools.json`. Closing this needs an upstream > lib change; do not describe the runtime coana pin as integrity-enforced until > it lands. ### Archive Extraction Safety - Path traversal validation (no `../` escapes) - Symlink target validation (no escapes via symlinks) - Lock file protection against concurrent downloads ### Local Path Overrides Environment variables for development/testing: | Variable | Tool | | ------------------------------------ | -------------- | | `SOCKET_CLI_CDXGEN_LOCAL_PATH` | cdxgen | | `SOCKET_CLI_COANA_LOCAL_PATH` | coana | | `SOCKET_CLI_PYCLI_LOCAL_PATH` | socketsecurity | | `SOCKET_CLI_SFW_LOCAL_PATH` | sfw | | `SOCKET_CLI_SOCKET_PATCH_LOCAL_PATH` | socket-patch | --- ## Implementation Files | File | Purpose | | --------------------------------- | ------------------------------------- | | `bundle-tools.json` | Tool definitions, versions, checksums | | `src/util/dlx/resolve-binary.mts` | Binary resolution logic | | `src/util/dlx/spawn.mts` | Tool spawning (VFS + dlx) | | `src/util/dlx/vfs-extract.mts` | VFS extraction utilities | | `src/util/basics/spawn.mts` | Python-based tools (basics) | | `src/util/basics/vfs-extract.mts` | Basics tools VFS extraction | | `src/env/*-version.mts` | Version getters (esbuild inlined) | | `src/env/*-checksums.mts` | Checksum getters (esbuild inlined) | --- ## Adding a New Tool 1. Add entry to `bundle-tools.json` with version and checksums 2. Create `src/env/{tool}-version.mts` version getter 3. Create `src/env/{tool}-checksums.mts` checksum getter (if applicable) 4. Add resolve function in `src/util/dlx/resolve-binary.mts` 5. Add spawn functions in `src/util/dlx/spawn.mts`: - `spawn{Tool}Vfs()` - VFS extraction path - `spawn{Tool}Dlx()` - Download path - `spawn{Tool}()` - Auto-detect wrapper 6. Update build scripts to bundle tool in VFS (for SEA)