Skip to content

Run CI dependency installs behind Socket Firewall (SFW)#1814

Open
nebasuke wants to merge 21 commits into
mainfrom
ci/socket-firewall-poc
Open

Run CI dependency installs behind Socket Firewall (SFW)#1814
nebasuke wants to merge 21 commits into
mainfrom
ci/socket-firewall-poc

Conversation

@nebasuke

@nebasuke nebasuke commented Jun 1, 2026

Copy link
Copy Markdown
Member

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-sfw action installs sfw and exports SFW_PREFIX; steps that
install 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_PREFIX unset, so the step runs unprotected rather than failing the
job (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 changesets and publish jobs carry a Require SFW guard that
fails when SFW_PREFIX is empty, so a release never installs dependencies with
the firewall off.

SFW_PREFIX is a wrapper, not bare sfw: inside a wrap sfw narrows the CA vars
(SSL_CERT_FILE, CARGO_HTTP_CAINFO, …) to its own MITM root and hijacks
SSL_CERT_DIR, breaking TLS to hosts it passes through (github.com for the
hermit 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.

  • ci: infra setup/check, cargo cooldown check, both renovate npx steps
    (infra test/lint don't fetch dependencies, so they're left unwrapped).
  • benchmark_*: infra setup* (the perf build/run + bencher upload steps
    left unwrapped).
  • publish: infra setup only — infra publish steps upload with auth and
    must not go through the MITM. The changesets and publish jobs add a
    Require SFW guard (the build-and-validate dry-run stays best-effort).
  • sourcify: the cargo build (the test run hits chain RPCs / Sourcify API,
    not registries).
  • excluded: validate-devcontainer (in-container; the bare-metal
    socketdev/action proxy doesn't apply).

@changeset-bot

changeset-bot Bot commented Jun 1, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 3769f85

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@nebasuke nebasuke changed the title PoC: Socket Firewall (SFW) in audit mode on the ci workflow PoC: Socket Firewall (SFW) on the ci workflow Jun 1, 2026
@nebasuke nebasuke force-pushed the ci/socket-firewall-poc branch from 47023bd to fdad0d9 Compare June 2, 2026 08:44
@nebasuke nebasuke changed the title PoC: Socket Firewall (SFW) on the ci workflow Run CI dependency installs behind Socket Firewall (SFW) Jun 2, 2026
@nebasuke nebasuke force-pushed the ci/socket-firewall-poc branch from 980ea1f to 4c95e30 Compare June 2, 2026 12:10
@nebasuke nebasuke requested a review from Copilot June 2, 2026 12:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-sfw composite action that installs SFW and builds a CA-merge wrapper, exporting SFW_PREFIX via GITHUB_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}.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread .github/actions/setup-sfw/action.yml
Comment thread .github/actions/setup-sfw/action.yml
@nebasuke nebasuke marked this pull request as ready for review June 2, 2026 20:32
@nebasuke nebasuke requested review from a team as code owners June 2, 2026 20:32
@nebasuke nebasuke added ci:perf Runs performance test dry-runs in a PR (rather than the smoke-tests) and removed ci:perf Runs performance test dry-runs in a PR (rather than the smoke-tests) labels Jun 2, 2026
@nebasuke nebasuke force-pushed the ci/socket-firewall-poc branch from f96de0e to c0b4d12 Compare June 2, 2026 20:39
@nebasuke nebasuke added the ci:perf Runs performance test dry-runs in a PR (rather than the smoke-tests) label Jun 2, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchci/socket-firewall-poc
Testbedci

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchci/socket-firewall-poc
Testbedci

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchci/socket-firewall-poc
Testbedci

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchci/socket-firewall-poc
Testbedci

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

🐰 View full continuous benchmarking report in Bencher

nebasuke added 7 commits June 3, 2026 09:02
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.
nebasuke added 14 commits June 3, 2026 09:02
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.
- 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.
@nebasuke nebasuke force-pushed the ci/socket-firewall-poc branch from c0b4d12 to 3769f85 Compare June 3, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:perf Runs performance test dry-runs in a PR (rather than the smoke-tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants