Run CI dependency installs behind Socket Firewall (SFW)#1814
Conversation
|
47023bd to
fdad0d9
Compare
980ea1f to
4c95e30
Compare
There was a problem hiding this comment.
Pull request overview
Introduces a GitHub composite action that installs Socket Firewall (SFW Free) and exposes an SFW_PREFIX wrapper, then updates CI-related workflows to prefix dependency/downloading steps with ${SFW_PREFIX} so installs run behind the firewall and fail closed if SFW can’t be installed.
Changes:
- Added
.github/actions/setup-sfwcomposite action that installs SFW and builds a CA-merge wrapper, exportingSFW_PREFIXviaGITHUB_ENV. - Updated CI, publish, benchmark, and Sourcify workflows to run selected dependency-fetching/build steps behind SFW by prefixing commands with
${SFW_PREFIX}. - Kept auth-sensitive publish/upload/test-execution steps unwrapped (where applicable), limiting MITM exposure to dependency acquisition paths.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| .github/actions/setup-sfw/action.yml | New composite action to install SFW and export SFW_PREFIX wrapper with CA handling adjustments. |
| .github/workflows/ci.yml | Wraps infra setup/check/test/lint, cargo cooldown, and renovate npx steps with ${SFW_PREFIX}. |
| .github/workflows/publish.yml | Wraps infra setup in relevant jobs with ${SFW_PREFIX} while leaving publish steps unwrapped. |
| .github/workflows/benchmark_npm.yml | Wraps dependency-oriented setup/check steps with ${SFW_PREFIX}. |
| .github/workflows/benchmark_cargo_slang.yml | Wraps infra setup cargo pipenv with ${SFW_PREFIX}. |
| .github/workflows/benchmark_cargo_slang_v2.yml | Wraps infra setup cargo pipenv with ${SFW_PREFIX}. |
| .github/workflows/benchmark_cargo_cmp.yml | Wraps infra setup cargo pipenv with ${SFW_PREFIX}. |
| .github/workflows/benchmark_archive.yml | Wraps infra setup cargo with ${SFW_PREFIX}. |
| .github/workflows/sourcify_single_chain.yml | Adds SFW setup and wraps the cargo build of the Sourcify test binary with ${SFW_PREFIX}. |
b0a0b1c to
f96de0e
Compare
f96de0e to
c0b4d12
Compare
|
| Branch | ci/socket-firewall-poc |
| Testbed | ci |
🐰 View full continuous benchmarking report in Bencher
⚠️ WARNING: Truncated view!The full continuous benchmarking report exceeds the maximum length allowed on this platform.
|
| Branch | ci/socket-firewall-poc |
| Testbed | ci |
⚠️ WARNING: Truncated view!The full continuous benchmarking report exceeds the maximum length allowed on this platform.
🐰 View full continuous benchmarking report in Bencher
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
|
| Branch | ci/socket-firewall-poc |
| Testbed | ci |
⚠️ WARNING: Truncated view!The full continuous benchmarking report exceeds the maximum length allowed on this platform.
🐰 View full continuous benchmarking report in Bencher
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
|
| Branch | ci/socket-firewall-poc |
| Testbed | ci |
⚠️ WARNING: Truncated view!The full continuous benchmarking report exceeds the maximum length allowed on this platform.
🐰 View full continuous benchmarking report in Bencher
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
Adapts solx's setup-sfw composite action (github.com/NomicFoundation/solx, PRs #250/#357/#397), slimmed to the bare-metal Linux path since slang CI is all GitHub-hosted ubuntu (drops the container npm path + platform skips). Wires it into ci.yml in AUDIT mode and wraps 'infra setup' (where the cargo + pnpm fetches happen) with ${SFW_PREFIX:-}. Audit-first so it can't break CI; the goal of the first run is to learn whether the MITM proxy is compatible with slang's fetchers — notably hermit/rustup downloads, which 'infra setup' currently routes through SFW too.
The first run failed: socketdev/action rejects mode=audit (supports firewall/patch/cli), and Socket Firewall Free has no warn-only mode at all — that's Enterprise-only. Free blocks confirmed-malicious packages and only warns on AI-flagged-unconfirmed ones. Switch to mode=firewall (the real, only proxy mode). slang's tree is known-clean, so it shouldn't block anything; the run now validates MITM compatibility (hermit/rustup/cargo/pnpm fetches). Also correct the action's mode description, which inherited solx's inaccurate audit claim.
The first firewall run silently no-op'd: the CA-discovery step (ported from solx's container-path fix, PR #357) found no NODE_EXTRA_CA_CERTS on slang's bare-metal runner and disabled SFW, so 'infra setup' ran unwrapped despite green CI. sfw-free is documented as zero-config and natively wraps cargo (+ npm/ pnpm/pip), so it should set up its own proxy + TLS trust for the wrapped process — no manual CARGO_HTTP_CAINFO bridging. Strip the CA dance to just install + export SFW_PREFIX, and let a real TLS failure surface loudly instead of silently disabling. The next run answers two things: (1) does zero-config trust cover cargo/pnpm, and (2) does wrapping the 'infra' parent propagate the proxy to its child package managers.
Pulls forward the scheduled Renovate cargo minor/patch group. Doubles as the SFW PoC validation fixture: these new versions aren't in any cache, so the next run's 'cargo fetch' downloads them through 'sfw' — the real interception test the warm-cache run couldn't exercise. Cooldown-check passes locally (all three are >7 days old).
Revert before merge. The restore-keys prefix fallback defeats key bumping, so skipping the restore is the only way to make hermit/pnpm/cargo download cold and actually exercise the firewall MITM path.
The dropped-CA run failed at the hermit bootstrap: a raw curl rejects the MITM cert because sfw only injects its CA into the package managers it wraps, not the system trust store. Re-add minimal, docs-aligned CA handling — locate socketFirewallCa.crt and install it via /usr/local/share/ca-certificates + update-ca-certificates — which covers curl/git/cargo. No per-tool env bridging. The find pipeline is guarded with '|| true' because composite-action steps run under 'bash -e -o pipefail', where find's nonzero exit on unreadable dirs would otherwise abort the step before the result is checked.
find / turned up no socketFirewallCa.crt — that name is from Socket's enterprise OpenSSL examples, not what the free binary emits. The free proxy advertises its CA only through NODE_EXTRA_CA_CERTS on wrapped processes. Read that path from a wrapped shell and install the file system-wide (same documented method). Diagnostics (injected env + candidate cert files) now run only on the failure branch, so the success path skips the ~4-min full-fs find.
Diagnostics showed sfw has no persistent CA file: inside each wrap it points SSL_CERT_FILE/CARGO_HTTP_CAINFO/etc. at a per-invocation /tmp/sfw-XXX bundle holding ONLY its MITM root, and hijacks SSL_CERT_DIR. That breaks raw TLS to hosts sfw passes through (github.com for hermit, static.rust-lang.org for rustup): 'unable to get local issuer certificate' for lack of public roots. Replace the (unworkable) system-trust install with a wrapper run as 'sfw <wrapper> <cmd>': inside the wrap it merges sfw's root with the system bundle, re-points the CA vars at the union, clears SSL_CERT_DIR, then exec's the command. SFW_PREFIX points at it, so ci.yml is unchanged.
Extend the firewall beyond ci's 'infra setup' to every dependency-fetching /
build step, each via the CA-merge wrapper (${SFW_PREFIX:-}):
- ci: also wrap check/test/lint (build.rs/npx can fetch); wrap the cargo
cooldown check and both renovate 'npx --yes' steps (npm fetches).
- benchmark_*: wrap the 'infra setup*' steps (perf steps build+upload to
bencher, left unwrapped).
- publish: wrap only 'infra setup'; the 'infra publish' upload steps must not
go through the MITM (auth + registry writes).
- sourcify: wrap the cargo build; the test run hits chain RPCs / Sourcify API,
not registries, so it stays unwrapped.
Excluded: validate-devcontainer (bare-metal socketdev/action doesn't work in
the container; would need the npm-install sfw path this action dropped).
Drop the repeated 'wrap setup' comments on the Setup SFW steps; instead put a
one-line marker on each intentionally-unwrapped call (benchmark perf, publish
upload steps, sourcify test run) so the missing ${SFW_PREFIX:-} reads as
deliberate, not an oversight.
Also tighten the ci.yml anchor comment to one line and cut the action's
description down to what it does (the CA-merge rationale lives on the wrapper
step, not the description).
slang CI is all ubuntu-24.04, so the 'runner.os == Linux' guards and the 'unset on non-Linux → run unwrapped' fallback never fired. Remove them and the matching description clause; if a non-Linux runner is ever added the action will fail loudly (socketdev/action + the bash/openssl wrapper are Linux-only).
Every call site passed mode: "firewall" — the action's default. Remove the input, hardcode "firewall" on the socketdev/action step, and drop the 'with: mode' block from all 12 call sites.
The unwrapped-step rationale lives in the PR description; the scattered inline markers were redundant noise.
…ough SFW" This reverts commit fd79cf5.
… fixture" This reverts commit 47855a6.
- Add REQUESTS_CA_BUNDLE to the merged-CA exports: pip/requests can ignore CURL_CA_BUNDLE inside a venv (pipenv), psf/requests#6660. Cheap insurance — the cold green run already exercised a wrapped pipenv install successfully. - Comment the load-bearing word-splitting contract: SFW_PREFIX is consumed unquoted so the shell splits it into 'sfw' + wrapper path; quoting breaks it.
- Rename the step from 'Setup SFW (firewall)' to 'Setup SFW' at all call sites (there's only one mode now; the composite action keeps its full name). - Add a Require SFW guard to the publish job so it hard-fails if sfw didn't install, rather than silently publishing deps installed unprotected. The soft-fail default stays everywhere else (PR/benchmark flows tolerate flakes).
SFW now soft-fails: the install step is continue-on-error and the action
warns (not errors) when sfw is absent, leaving SFW_PREFIX unset so callers
run unprotected. A socket.dev outage no longer reddens every PR.
The release path stays strict: a Require SFW guard fails the job when
SFW_PREFIX is empty, added to both the changesets and publish jobs (each
sets up SFW on its own runner, so the needs-chain alone isn't enough).
Callers use ${SFW_PREFIX:-} since unset is now a valid state. test/lint
are unwrapped — they don't fetch dependencies.
c0b4d12 to
3769f85
Compare
Implement a wrapper for Socket Firewall using https://github.com/SocketDev/sfw-free, preventing malicious downloads in CI.
I've made the wrapper optional on sfw installation failure as it's another layer of defense on top of the already implemented cargo-cooldown-check, cooldowns, and locked installs, and I've seen the occasional flake for sfw installs in solx/edr repos. It is strictly required for the publish flow (not dry-run), to avoid installing any malicious packages.
Tested by temporarily disabling the deps cache.
Claude Summary
Runs CI dependency installs behind Socket Firewall (SFW) Free as a supply-chain
guard. The
setup-sfwaction installs sfw and exportsSFW_PREFIX; steps thatinstall dependencies are prefixed with
${SFW_PREFIX:-}to run behind it.SFW is best-effort by default: if sfw can't be installed the action warns and
leaves
SFW_PREFIXunset, so the step runs unprotected rather than failing thejob (it's a layer on top of cargo-cooldown-check, cooldowns, and locked
installs, and sfw installs occasionally flake). The release path is the
exception — the
changesetsandpublishjobs carry aRequire SFWguard thatfails when
SFW_PREFIXis empty, so a release never installs dependencies withthe firewall off.
SFW_PREFIXis a wrapper, not baresfw: inside a wrap sfw narrows the CA vars(
SSL_CERT_FILE,CARGO_HTTP_CAINFO, …) to its own MITM root and hijacksSSL_CERT_DIR, breaking TLS to hosts it passes through (github.com for thehermit bootstrap, static.rust-lang.org for rustup). The wrapper merges sfw's
root with the system CA bundle and re-points the CA vars at the union before
running the command.
Wrapping
Only dependency-installing steps are wrapped; steps that build/run, upload, or
execute tests are left unwrapped on purpose.
infra setup/check, cargo cooldown check, both renovatenpxsteps(
infra test/lintdon't fetch dependencies, so they're left unwrapped).infra setup*(theperfbuild/run + bencher upload stepsleft unwrapped).
infra setuponly —infra publishsteps upload with auth andmust not go through the MITM. The
changesetsandpublishjobs add aRequire SFWguard (thebuild-and-validatedry-run stays best-effort).not registries).
validate-devcontainer(in-container; the bare-metalsocketdev/actionproxy doesn't apply).