Skip to content

fix(scanners): uv-first bandit[sarif] install + pip-audit pyproject.toml support#166

Merged
theagenticguy merged 1 commit into
mainfrom
fix/scanners-uv-bandit-pyproject-pipaudit
May 29, 2026
Merged

fix(scanners): uv-first bandit[sarif] install + pip-audit pyproject.toml support#166
theagenticguy merged 1 commit into
mainfrom
fix/scanners-uv-bandit-pyproject-pipaudit

Conversation

@theagenticguy
Copy link
Copy Markdown
Owner

Summary

Two customer-facing scanner fixes, both surfaced by a real codehub analyze run on a uv-managed Python project (pyproject.toml + uv.lock, no requirements.txt):

codehub scan: bandit: rejected '-f sarif' (exit 2). The SARIF formatter is not installed — install the extra: pip install 'bandit[sarif]==1.9.4'.
codehub scan: pip-audit: stdout was not valid JSON (stderr: invalid requirements input: requirements.txt); emitting empty SARIF.

1. bandit install command → uv-first, with the [sarif] extra

BANDIT_SPEC.installCmd was pip install 'bandit[sarif]==1.9.4'. Now uv tool install 'bandit[sarif]==1.9.4':

  • Matches the repo's uv-first convention and the existing doctor.ts hint.
  • An isolated uv tool venv won't be shadowed by (or shadow) a project's bare bandit that lacks the [sarif] extra — the exact trap, since a PATH bandit without bandit-sarif-formatter argparse-rejects -f sarif with exit 2.

PIP_AUDIT_SPEC.installCmd likewise moved to uv tool install.

2. pip-audit now audits pyproject.toml projects

The wrapper hardcoded -r requirements.txt. On a project without that file, pip-audit emitted invalid requirements input → empty SARIF (silent miss). The wrapper now resolves what to audit, first hit wins:

  1. An existing requirements.txt (or explicit requirementsPath) → audited directly. Unchanged path.
  2. No requirements file but a pyproject.toml → bridge via uv export --quiet --format requirements-txt --no-emit-project -o <.codehub>/.pip-audit-requirements.txt, then audit the export with the same -r … --disable-pip invocation. uv emits hashes by default, which --disable-pip requires. Findings are labelled against pyproject.toml (the file the user maintains) via the converter's requirementsPath option, not the transient export.
  3. Neither file → actionable advisory + empty SARIF. Missing-uv and failed-uv export also degrade to an advisory.

scan.ts points exportDir at the gitignored .codehub/ meta dir and lets the wrapper auto-detect instead of hardcoding requirements.txt. Adds an optional fileExists to WrapperDeps (DI seam; real access() default, so existing wrappers/tests are unaffected).

Test plan

  • End-to-end: codehub scan <uv-project> --scanners pip-audit now reports PYSEC-2026-161 (starlette@1.0.0) @ pyproject.toml (was: empty SARIF). Temp export lands in .codehub/ and is gitignored.
  • 6 new pip-audit wrapper tests: requirements.txt path, custom path, pyproject bridge (asserts uv export → audit chain + pyproject.toml SARIF URI), missing-uv advisory, failed-export advisory, no-input advisory.
  • @opencodehub/scanners: 92/92 pass
  • @opencodehub/cli: 263/263 pass
  • tsc --noEmit workspace: clean
  • biome check: clean

…oml support

Two customer-facing scanner fixes surfaced by a real `codehub analyze` run on
a uv-managed Python project (pyproject.toml + uv.lock, no requirements.txt).

bandit installCmd:
- Was `pip install 'bandit[sarif]==1.9.4'`. Changed to
  `uv tool install 'bandit[sarif]==1.9.4'` — matches the uv-first convention
  (and the existing doctor.ts hint), and an isolated tool venv won't be
  shadowed by a project's bare `bandit` that lacks the [sarif] extra (the
  exact trap: a PATH bandit without the formatter argparse-rejects -f sarif).
- pip-audit installCmd likewise moved to `uv tool install`.

pip-audit pyproject.toml support:
- Previously hardcoded `-r requirements.txt`; on a project without that file
  pip-audit emitted `invalid requirements input` and an empty SARIF.
- The wrapper now resolves what to audit (first hit wins): an existing
  requirements.txt is audited directly (unchanged path); otherwise, if a
  pyproject.toml exists, it bridges via `uv export --quiet --format
  requirements-txt --no-emit-project -o <.codehub>/.pip-audit-requirements.txt`
  (uv emits hashes by default, which --disable-pip requires) and audits the
  export. Findings are labelled against pyproject.toml via the converter's
  requirementsPath option, not the transient export. Missing-uv and
  failed-export both degrade to an actionable advisory + empty SARIF.
- scan.ts points exportDir at the gitignored .codehub/ meta dir and lets the
  wrapper auto-detect instead of hardcoding requirements.txt.
- Adds an optional fileExists to WrapperDeps (DI seam; real access() default).

Verified end-to-end: `codehub scan ngs-research-agent --scanners pip-audit`
now reports PYSEC-2026-161 (starlette@1.0.0) @ pyproject.toml; the temp
export lands in .codehub/ and is gitignored. Scanners 92/92, cli 263/263,
tsc clean, biome clean.
@theagenticguy theagenticguy enabled auto-merge (squash) May 29, 2026 17:00
@theagenticguy theagenticguy merged commit 5ad02d8 into main May 29, 2026
43 of 45 checks passed
@theagenticguy theagenticguy deleted the fix/scanners-uv-bandit-pyproject-pipaudit branch May 29, 2026 17:02
@github-actions github-actions Bot mentioned this pull request May 29, 2026
theagenticguy pushed a commit that referenced this pull request May 29, 2026
🤖 Automated release via release-please
---


<details><summary>cli: 0.5.5</summary>

##
[0.5.5](cli-v0.5.4...cli-v0.5.5)
(2026-05-29)


### Bug Fixes

* **cli:** doctor resolves @opencodehub/sarif as installed pkg, not
monorepo path
([#164](#164))
([2b2b389](2b2b389))
* **scanners:** uv-first bandit[sarif] install + pip-audit
pyproject.toml support
([#166](#166))
([5ad02d8](5ad02d8))


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @opencodehub/mcp bumped to 0.4.4
    * @opencodehub/scanners bumped to 0.2.2
</details>

<details><summary>mcp: 0.4.4</summary>

##
[0.4.4](mcp-v0.4.3...mcp-v0.4.4)
(2026-05-29)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @opencodehub/scanners bumped to 0.2.2
</details>

<details><summary>scanners: 0.2.2</summary>

##
[0.2.2](scanners-v0.2.1...scanners-v0.2.2)
(2026-05-29)


### Bug Fixes

* **scanners:** uv-first bandit[sarif] install + pip-audit
pyproject.toml support
([#166](#166))
([5ad02d8](5ad02d8))
</details>

<details><summary>root: 0.6.6</summary>

##
[0.6.6](root-v0.6.5...root-v0.6.6)
(2026-05-29)


### Bug Fixes

* **cli:** doctor resolves @opencodehub/sarif as installed pkg, not
monorepo path
([#164](#164))
([2b2b389](2b2b389))
* **scanners:** uv-first bandit[sarif] install + pip-audit
pyproject.toml support
([#166](#166))
([5ad02d8](5ad02d8))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
theagenticguy added a commit that referenced this pull request May 29, 2026
…inary (#171)

## Summary

`doctor` reported **bandit OK** from `bandit --version` exit 0 — while
`codehub scan` was silently broken. Without the `[sarif]` extra
(`bandit-sarif-formatter`), `bandit -f sarif` is argparse-rejected (exit
2 + a `usage: bandit` banner) and the scan contributes **0 findings**.
The check was a false positive (field-report Issue 6).

## Fix

- **`banditSarifCheck`** replaces the bandit `binaryOnPathCheck`. It
probes `bandit --version` (missing → `warn`), then runs `bandit -f sarif
--quiet -r <empty tmp dir>`. argparse validates the `--format` choice
**before** walking any target, so a missing formatter fails fast (~0.1s)
without scanning the repo. The fail branch gates on the **structural**
signature (exit 2 + `usage: bandit` banner) — not advisory prose — so it
can't silently regress if the message is reworded. Row name stays
`"bandit binary"` (preserves `--strict` exit accounting and table
order).
- **`runCommand` DI seam** added to `DoctorOptions`, threaded into the
spawning checks (pnpm, scip indexers, `binaryOnPathCheck`,
`banditSarifCheck`). This makes doctor tests hermetic and de-flakes the
pre-existing strict-exit test, which previously depended on whatever
scanner binaries the host happened to have installed.

## Test plan

- [x] **On this host:** doctor reports **FAIL** for the PATH bandit
lacking the extra (`mise pipx-bandit`), and **OK** for the uv-tool
`bandit[sarif]`.
- [x] 3 new tests via the DI seam: formatter-missing (exit 2 + usage) →
`fail` with a `bandit[sarif]` hint; formatter-present → `ok`;
binary-absent → `warn`.
- [x] `@opencodehub/cli` 266/266; `tsc` + `biome` clean.

Companion to #166 (which fixed the `installCmd` the hint points at).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant