feat: surface .npmrc and pip configuration on the host#69
Open
swarit-stepsecurity wants to merge 6 commits intostep-security:mainfrom
Open
feat: surface .npmrc and pip configuration on the host#69swarit-stepsecurity wants to merge 6 commits intostep-security:mainfrom
swarit-stepsecurity wants to merge 6 commits intostep-security:mainfrom
Conversation
Adds a read-only audit that enumerates each .npmrc across all four npm
config scopes (built-in, global, user, project), parses every key/value
(redacting auth values to ***last4, preserving ${VAR} env-refs), and
captures the merged effective view npm itself would resolve via
`npm config ls -l --json` plus source attribution from `npm config ls -l`.
Surfaces in:
- standard scan: compact summary section in --pretty + JSON via
ScanResult.NPMRCAudit / Payload.NPMRCAudit
- new --npmrc flag: focused, verbose pretty view (or JSON via
--npmrc --json) for deep inspection without running the rest of the
scan; ~1s runtime
- HTML / enterprise telemetry payloads pick up the audit object
automatically through the model wiring
Drift detection (snapshot/diff across runs), per-project effective
overrides, and severity scoring are intentionally out of scope here.
The model carries SHA256 / ValueSHA256 fingerprints today specifically
so a future drift layer can land cheaply on top of the surface
inventory. See .plans/0005-npmrc-audit.md for extension notes.
…ation Adds a read-only audit that mirrors the npmrc one but covers pip: discovery via `pip config debug` (with OS-specific path-enumeration fallback when pip isn't installed), parsing of every pip.conf / pip.ini across all four scopes (global / user / user-legacy / site / PIP_CONFIG_FILE), the merged effective view from `pip config list -v` with per-key source attribution, a snapshot of PIP_* environment variables, and a `~/.netrc` presence/permissions probe. Where the pip audit goes further than npmrc: it ships a fixed catalog of finding IDs (pip-001 .. pip-024) per the spec — embedded creds in URLs, http:// schemes, extra-index-url presence (dependency-confusion), trusted-host, no-build-isolation, file mode escalations, legacy paths, PIP_CONFIG_FILE redirection, etc. Each finding carries severity, category, source attribution, redacted value, detail, and a remediation hint. Auth tokens and proxy credentials are always rendered as `user:****@host` and the raw value never leaves the detector. Surfaces in: - standard scan: compact summary section in --pretty (severity bucket counts) plus the full audit object in JSON / enterprise telemetry - new --pipconfig flag: focused, verbose pretty view (or JSON via --pipconfig --json) — findings first, then files, then effective view, then env vars + ~/.netrc End-to-end validated on Fedora EC2 with seeded fixtures across all four scopes (PIP_CONFIG_FILE redirect, http:// scheme on index-url, extra-index-url with embedded creds, no-build-isolation, etc.). See .plans/0006-pip-config-audit.md for the full design.
…figaudit Moves the 15 npmrc + pipconfig files out of internal/detector/ and into a dedicated sub-package internal/detector/configaudit/. Pure rename + a package-decl change in each file (`package detector` → `package configaudit`) plus updated imports in the three callsites: - internal/scan/scanner.go - internal/telemetry/telemetry.go - cmd/stepsecurity-dev-machine-guard/main.go `detector.NewNPMRCDetector(...)` becomes `configaudit.NewNPMRCDetector(...)` and likewise for `NewPipConfigDetector`. No public-API changes beyond the package qualifier. Why: internal/detector/ had grown to 55 files and the rc/config-file audits are a self-contained subset (15 files, no cross-references with sibling detector files). Splitting them off drops detector/ to 40 files and clarifies the architecture: detector/ owns inventory-style detectors (IDEs, AI tools, package managers, etc.); configaudit/ owns config-file audits with their own discovery + parsing + finding semantics. Future sibling audits — .yarnrc.yml, .gemrc, .cargo/config.toml — fit naturally under configaudit/. Verified: full test suite green (configaudit tests run as a separate package now), cross-compile clean for darwin/linux/windows.
9 tasks
…ffix Two bugs surfaced by end-to-end testing on Fedora EC2 with a 69-scenario harness: 1. Plaintext credential leak in `effective.config`. `pip config list -v` emits URL values verbatim, including any embedded `user:pass@host` userinfo. We were copying the value into `effective.config[<key>]` without redaction — so a hardcoded token in `extra-index-url` would show up in the JSON output even though the per-file `entries` view already redacted it. Fix: run `redactCredsInValue` over the value before storing in the merged map. 2. `pip-019` (legacy `~/.pip/pip.conf`) only fired when the discovery layer was tagged `user-legacy`. But when `pip` is installed, our discovery uses `pip config debug`, which reports the legacy path under the `user` layer (pip itself doesn't expose the "legacy" concept) — so the rule silently never fired in practice. Fix: detect by path suffix (`isLegacyPipConfigPath`) instead of the layer label. The Windows discriminator carefully excludes both `%APPDATA%\...` (current user) and `%PROGRAMDATA%\...` (global) so only the `%HOME%\pip\pip.ini` form trips the rule. Also: `PipKeyValue.Values` is now `json:"-"`. It holds the raw, un-redacted parsed values for the findings engine to inspect (URL.User parsing, http-scheme detection, etc.) — it must never be serialized, because for keys like `extra-index-url` it can hold a literal `user:pass@host` URL. The `Display` field is the canonical user-facing rendering and it stays in JSON. Three new unit tests lock all of this in: - `TestParseEffective_RedactsEmbeddedCreds` - `TestIsLegacyPipConfigPath` (10 cases incl. all three Windows variants) - `TestEvaluateFileLevel_Pip019_FiresOnLegacyPathRegardlessOfLayer` Validated on Fedora EC2: 69/69 scenarios pass.
Reusable shell harness covering ~65 scenarios for the npmrc + pip config audits — discovery across all four scopes for each tool, credential redaction, env-var interactions (NPM_CONFIG_USERCONFIG, PIP_CONFIG_FILE incl. /dev/null disable, VIRTUAL_ENV), every pip-001..pip-024 finding rule, file-mode escalations, severity ordering, and edge cases (missing files, unreadable files, garbage content, symlinks). Usage: tests/test_rc_audit.sh # uses ./stepsecurity-dev-machine-guard BINARY=/path/to/binary tests/test_rc_audit.sh # explicit binary Conventions match tests/test_smoke_go.sh (pass/fail/section helpers, PASS/FAIL/SKIP counts, color-coded output, exits non-zero on any FAIL). Safety: backs up any pre-existing user config (~/.npmrc, ~/.netrc, ~/.config/pip/pip.conf, ~/.pip/pip.conf) on entry and restores via trap on EXIT/INT/TERM, so a developer running this against their own machine never loses config. Sudo-required scenarios (writing /etc/pip.conf for the global-scope test) are skipped automatically when passwordless sudo is unavailable; git scenarios skip if git is absent. No secrets, no hardcoded paths to credential stores, no remote-machine assumptions. Verified on: - macOS (BINARY=/tmp/dmg-rc-mac): PASS=64 FAIL=0 SKIP=1 (no sudo) - Fedora 42 EC2 (BINARY=~/dmg-rc): PASS=65 FAIL=0 SKIP=0
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.
Summary
Adds two read-only audits that enumerate package-manager configuration on the host. Surface-only — no drift detection, no auto-remediation, no traffic, no plaintext credentials in any output.
Two commits, intentionally split for review:
feat(npmrc)(41e17d7) — every.npmrcacross all four npm scopes (built-in / global / user / project), parsed (with auth values redacted to***last4and${VAR}env-refs preserved verbatim), plus the merged effective view npm itself would resolve vianpm config ls -l --jsonwith per-key source attribution.feat(pipconfig)(18e6959) — everypip.conf/pip.iniacross all four pip scopes (global / user / user-legacy / site /PIP_CONFIG_FILEoverride), parsed, plus the merged effective view frompip config list -vwith per-key source attribution. Adds a fixed catalog of finding IDs (pip-001..pip-024) covering embedded creds,http://schemes,extra-index-url(dependency-confusion),trusted-host,no-build-isolation, file-mode escalations, legacy paths, andPIP_CONFIG_FILEredirection.Both audits run as part of the standard scan and surface in:
npmrc_audit/pip_auditfields onScanResultandPayload--pretty— compact summary block for each--npmrc— verbose pretty view of just the npm audit (also--npmrc --json)--pipconfig— verbose pretty view of just the pip audit, findings first (also--pipconfig --json)What's intentionally out of scope (documented for follow-up)
The npmrc audit is inventory-only. Drift / change tracking (snapshot to disk, diff next run, attribute writers) and per-project effective overrides ("if I cd into this cloned repo and run npm install, what flips?") are deliberately deferred. The model already carries
SHA256andValueSHA256fingerprints so a future drift layer can land cheaply on top of what's here. See `.plans/0005-npmrc-audit.md` (worktree-local) for extension notes.Test plan
go test ./...— full suite green on darwin (no cache, fresh run)linux/amd64andwindows/amd64--npmrcsmoke run on macOS — discovers global / user / project files, redaction works on real auth tokens,${VAR}env-refs preserved--pipconfigsmoke run on macOS — finds all 5 pip scope candidates, surfaces~/.netrcpermissions findingpip-001CRITICAL embedded creds,pip-005HIGH extra-index-url,pip-007HIGH trusted-host,pip-022HIGH file-perms-with-creds,pip-011MEDIUM no-build-isolation,pip-020MEDIUM PIP_CONFIG_FILE redirect,pip-023/pip-024INFO defensive controls) all fire as expected against seeded fixtures across/etc/pip.conf,~/.config/pip/pip.conf,~/test-venv/pip.conf, andPIP_CONFIG_FILE=/tmp/...