Repository navigation
controls: socket-firewall-ci — are committed workflow installs behind Socket Firewall? (47 to 48) - #70
Merged
Conversation
…he Socket question (47 to 48) `socket-firewall` asks whether `sfw` is on the developer's PATH. That is a fact about a machine, and nobody cloning the repository can check it -- it is one of the class-C controls a public scan has to leave `unverified`. This additive control asks a different question with different evidence and leaves that one untouched: do this repository's COMMITTED workflows put their package-manager installs behind Socket Firewall? Every subject is read through `git show HEAD:<path>`, so an index-only `git add` and a working-tree edit are both excluded, and the verdict is a property of the repository. Only Socket Firewall Free's ecosystems can fail it -- npm, yarn, pnpm, pip (including `python -m pip`), uv, cargo. Go, Maven, Gradle, Bundler, gem, dotnet and NuGet are Enterprise-only; bun, composer, apt, brew and rustup are proxied at no tier. Both are reported as information, because failing a maintainer for an ecosystem the free tool cannot protect is a false positive by construction, and a repository whose only installs are Enterprise-tier verifies INFO rather than PASS or FAIL. The unit of judgement is (job, ecosystem), with a local composite action (`uses: ./...`) spliced into the calling job at the step that uses it, and the FIRST acquisition of each pair must carry the `sfw` prefix. So `sfw cargo fetch --locked` followed by a bare `cargo build --locked` is a PASS -- the crates came through the firewall and the build reads the filtered cache -- which makes the remedy one step per job instead of a prefix on every matrix `cargo test`. Acquiring subcommands are an ALLOWLIST and an unrecognised one is not an acquisition, so `cargo fmt`, `npm run` and `npm test` are silent and detection fails open: a missed install is a gap disclosed in the docs, an invented one sends a maintainer to fix nothing. Recognition reuses `workflows`'s shell tokeniser rather than string matching, so an install inside a heredoc, a comment or a quoted string is text, while `sudo`, `env`, `time` and `FOO=1` hide neither the manager nor the firewall. `workflows`'s operator gates are deliberately NOT imported: `sfw npm ci || true` still ran the install through the firewall, which is the whole question, so importing them would be a bug rather than an omission. DEGRADED carries `no-inventory` when workflows parsed and nothing of any tier was acquired -- nothing verified is not a pass -- and `scan-error` when HEAD cannot be read. A `workflow_dispatch`-only workflow, one GitHub would refuse to run, a constant-false job or step, a non-POSIX `run:` body, a `uses: ./...` that is not a committed composite, and the second level of a composite chain are each named as NOT EXAMINED rather than counted as clean. `evidence` is deliberately left empty -- `machine` asserts every row's `artifacts` equals `workflows::artifacts_for(id)`, which is empty here -- so the proving files are named in the messages. Four disclosed misses, in docs/phase-2.md and the changelog: `SocketDev/action`'s unreleased `shims: true` PATH-shimming will protect an unprefixed install that this control still reads as unprotected; indirect acquisition (an `npm run build` whose script installs, a Makefile target) is not followed; composites are spliced one level deep; and a PASS proves the workflow SAYS installs go through the firewall, not that it ran or that `sfw` resolved on PATH. It ships off by default, which also keeps the directory's `in_scope` unchanged so no other repository's grade can move. sscsb's own repository FAILS it today with six findings -- bare `cargo clippy`, `cargo build --release`, `cargo llvm-cov` and `cargo build --release --locked --target`, plus `python3 -m pip install` reached twice through the `setup-sscsb-tools` composite -- and is deliberately not enabled here, so the gap is visible and fixable as its own change. Also corrects two now-false statements found while in these files: docs/phase-2.md said socket-firewall "needs a Socket account" and the bundled skill filed it under "a paid or unreleased tool". Socket Firewall Free needs neither an account nor an API key; both controls are off for the real reason instead -- putting a filtering proxy in front of every install is a decision about how builds fetch. Tests: 26 in the new module, written red-first against a stub that returned Pass (19 of 21 then-existing cases failed). The bare first acquisition, the prefix licensing the rest of the job, no-inventory, scan-error, Enterprise and unsupported tiers across fifteen spellings, heredoc/comment/quote silence, wrapper prefixes both ways, the operator gates deliberately not applied, unrecognised subcommands, alternate pip and uv spellings, workflow_dispatch-only, an unrunnable workflow, constant-false job and step, a non-POSIX shell, HEAD-not-worktree, composite splicing and its depth-1 boundary, per-job and per-ecosystem units, the continue-on-error note, message abbreviation, and a source scan proving this control never reads PATH. `workflows.rs` changes are visibility only: sixteen items promoted to `pub(crate)` with no behaviour change, the way `Finding::new` was promoted for `pinning.rs`.
p4gs
force-pushed
the
feat/socket-firewall-ci
branch
from
September 11, 2026 16:56
9d06021 to
4c604bd
Compare
4 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
socket-firewall-ci(phase 2, off by default) — control 48. It is additive:socket-firewallis untouched.socket-firewallasks whethersfwis on the developer's PATH. That is a fact about a machine, and nobody cloning the repository can check it. This control asks the repository-observable question with different evidence: do this repository's COMMITTED workflows put their package-manager installs behind Socket Firewall? Every subject is read throughgit show HEAD:<path>, so an index-onlygit addand a working-tree edit are both excluded. No tool runs; no network call is made.The site repo must register the
socket-firewall-ciid before this merges — every directory scan throws otherwise. Held for that; do not merge until the site side lands.The design
Manager tiers are the false-positive defence. Socket Firewall Free proxies exactly npm, yarn, pnpm, pip (incl.
python -m pip), uv, cargo. Go/Maven/Gradle/Bundler/gem/dotnet/NuGet are Enterprise-only; bun/composer/apt/brew/rustup are proxied at no tier. Only the free tier can produce aFail— failing a maintainer for an ecosystem the free tool cannot protect is a false positive by construction. A repository whose only installs are Enterprise-tier verifiesINFO, neverPASSand neverFAIL.The first-acquisition rule. The unit is (job, ecosystem), with a local composite action (
uses: ./…) spliced into the calling job at the step that uses it. The first acquisition of each pair must carry thesfwprefix:One-step remedy per job, instead of a prefix on every matrix
cargo test.Acquiring subcommands are an allowlist. An unrecognised subcommand is not an acquisition —
cargo fmt,npm run,npm testare silent. Detection fails open on purpose: a missed install is a disclosed gap, an invented one sends a maintainer to fix nothing.Recognition reuses
workflows's shell tokeniser, not string matching, so an install inside a heredoc, a comment or a quoted string is text, andsudo/env/time/FOO=1hide neither the manager (sudo npm cifails) nor the firewall (sudo sfw npm cipasses).workflows's operator gates are deliberately NOT imported.sfw npm ci || truestill ran the install through the firewall, which is the whole question — importing the!/set +e/||/|/&gates would be a bug here rather than an omission. Stated in the module docs and covered by a test.Verdicts.
Pass/Failas above;Degraded+no-inventorywhen workflows parsed but nothing of any tier was acquired (nothing verified is not a pass);Degraded+scan-errorwhen HEAD cannot be read;Infowhen an inventory exists with no free-tier acquisition. Aworkflow_dispatch-only workflow, one GitHub would refuse to run, a constant-false job or step, a non-POSIXrun:body, an unresolvableuses: ./…, and the second level of a composite chain are each named not examined rather than counted as clean.No
evidence.machine.rsasserts every row'sartifacts == workflows::artifacts_for(id), which is empty for this control, so the proving files are named inmessagesinstead.Four disclosed misses
Written into
docs/phase-2.mdand the changelog:SocketDev/action'sshims: truePATH-shimming is unreleased upstream; when it ships, an unprefixed install under it will be protected and this control will read it as unprotected.npm run buildwhose script installs, a Makefile target) is not followed.sfwresolved on PATH.Dogfood: this repo FAILS, and ships the control off
ci.ymljoblint— barecargo clippy --all-targets -- -D warningsci.ymljobtest→setup-sscsb-tools/action.yml—python3 -m pip install --quiet semgrep==…ci.ymljobtest—cargo build --release --lockedci.ymljobcoverage→setup-sscsb-tools/action.yml— the same pip install, reached againci.ymljobcoverage—cargo llvm-cov --locked …release.ymljobbuild—cargo build --release --locked --target "$TARGET"Plus one
[info](rustup target add— unsupported at any tier) and one latercargo test --lockedcorrectly not judged.Deliberately NOT enabled in
.sscsb/config.tomlhere — the gap is visible and fixable as its own change. Default-off also means the directory'sin_scopeexcludes it, so adding this control cannot move any other repository's grade.Two corrections while in these files
docs/phase-2.mdsaidsocket-firewall"needs a Socket account" and the bundled skill filed it under "a paid or unreleased tool". Socket Firewall Free needs neither an account nor an API key. Both controls are now off for the real reason: putting a filtering proxy in front of every install is a decision about how builds fetch, not a binary you drop in.Tests
26 in the new module, written red-first against a stub that returned
Pass— 19 of the 21 cases that existed at that point failed against it (log kept). Coverage ofsrc/socket_firewall.rs: 95.89% lines / 100% functions; crate total (lib) 96.52% lines / 96.24% functions, above the 95/94 gate.cargo fmt --checkclean,cargo clippy --all-targets --locked -- -D warningsclean.src/workflows.rschanges are visibility only — sixteen items promoted topub(crate)with no behaviour change, the wayFinding::newwas promoted forpinning.rs.Lock-step files touched
src/socket_firewall.rs(new),src/lib.rs,src/controls.rs(entry + dispatch + default-off assertion),src/workflows.rs(visibility),templates/compliance/map.json,tests/tool_orchestration.rs(both lists),.claude/skills/sscsb/SKILL.md+templates/skills/sscsb/SKILL.md(byte-identical: 47→48, 32 on / 16 off, phase-2 row 9→10, taxonomy),README.md,docs/phase-2.md,CHANGELOG.md.🤖 Generated with Claude Code