Skip to content

ci: enforce scoped production dependency audits - #339

Open
coleleavitt wants to merge 4 commits into
cortexkit:masterfrom
coleleavitt:chore/dependency-audit-254
Open

ci: enforce scoped production dependency audits#339
coleleavitt wants to merge 4 commits into
cortexkit:masterfrom
coleleavitt:chore/dependency-audit-254

Conversation

@coleleavitt

@coleleavitt coleleavitt commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • audit each published package as an isolated registry consumer without monorepo overrides
  • fail on unaccepted HIGH/CRITICAL findings and scope temporary exceptions by advisory, package, artifact, severity, and exact resolved path
  • validate waiver ownership, rationale, reachability, upstream HTTPS links, and expiry
  • gate both PR CI and tag publishing on policy tests plus the live audit using pinned Bun scanner semantics

Addresses #254 (enforces fail-closed production auditing; the two upstream vulnerabilities remain time-boxed exceptions)

Current accepted upstream blockers

  • @huggingface/transformers@4.2.0 > onnxruntime-node@1.24.3 > adm-zip@0.5.18
  • @huggingface/transformers@4.2.0 > sharp@0.34.5

Both expire 2026-11-17 and link their open upstream issues/PRs. No consumer-ineffective override is added.

Verification

  • 14 policy/parser/path tests pass
  • live audit accepts exactly the two documented paths for plugin and Pi; CLI is clean
  • synthetic wrong artifact/path, new HIGH, optional/required-peer, malformed date, and malformed URL cases fail closed
  • Biome and git diff --check pass

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Enforces scoped production dependency audits in CI and release, failing on any unaccepted HIGH/CRITICAL advisory. Previously we didn’t audit published packages in isolation; now each package is audited as an isolated consumer with only time‑boxed, path‑scoped exceptions allowed. Satisfies Linear #254.

  • Adds an audit-production job to PR and release workflows; all npm publish jobs depend on it. Bun is pinned to 1.3.10 for audit jobs only to keep scanner semantics stable.
  • Exceptions live in .github/production-audit-policy.json and must match advisory ID, package, affected artifact, and exact resolved path; ownership, rationale, reachability, HTTPS upstream links, and expiry are required and validated by tests.
  • Current accepted upstream blockers (expire 2026-11-17): @huggingface/transformers@4.2.0 > onnxruntime-node@1.24.3 > adm-zip@0.5.18 and @huggingface/transformers@4.2.0 > sharp@0.34.5.
  • Stabilizes TUI test imports by warming @opentui/core to prevent Bun TDZ exposure.
  • Required action: if a new production dependency surfaces a HIGH/CRITICAL advisory, upgrade to a fixed version or add a temporary, fully scoped exception to the policy; otherwise CI and releases will fail.

Written for commit 6223f7d. Summary will update on new commits.

Review in cubic

Greptile Summary

The PR adds isolated production-dependency auditing and makes that audit a prerequisite for CI and npm publication.

  • Builds temporary consumer manifests for the three published packages.
  • Rejects unaccepted HIGH and CRITICAL advisories using artifact- and dependency-path-scoped exceptions.
  • Validates exception metadata, expiry dates, and upstream URLs.
  • Adds policy tests and pins Bun 1.3.10 for consistent audit behavior.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the available follow-up review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
scripts/audit-production.ts Orchestrates isolated installs, live audits, dependency-path resolution, rejection reporting, and temporary-directory cleanup.
scripts/audit-production-policy.ts Parses Bun dependency output and requires advisory exceptions to match ID, package, severity, artifact, and exact resolved path.
scripts/audit-production-input.ts Validates policy metadata and constructs isolated manifests containing all production dependency groups.
scripts/audit-production.test.ts Exercises policy matching, malformed metadata rejection, production manifest construction, and representative dependency-path parsing.
.github/workflows/release.yml Adds the production audit job as a prerequisite for all three npm publication jobs.
.github/workflows/ci.yml Runs policy tests and the live production audit for pull requests and master updates.
.github/production-audit-policy.json Defines two artifact- and path-scoped temporary exceptions with ownership, reachability, expiry, and upstream tracking.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  CI[PR or release workflow] --> Tests[Policy tests]
  Tests --> Manifests[Create isolated consumer manifests]
  Manifests --> Install[Bun lockfile-only install]
  Install --> Audit[Bun production audit]
  Audit --> Paths[Resolve dependency paths]
  Paths --> Policy{Exact policy exception?}
  Policy -->|Yes| Accept[Accept documented advisory path]
  Policy -->|No| Fail[Fail CI or publication]
  Accept --> Publish[Allow downstream release gates]
Loading

Reviews (4): Last reviewed commit: "ci: scope production audit Bun pin" | Re-trigger Greptile

Context used:

@cubic-dev-ai cubic-dev-ai Bot 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.

3 issues found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/audit-production.sh">

<violation number="1" location="scripts/audit-production.sh:1">
P3: The new shell script carries a `#!/usr/bin/env bash` shebang but is committed non-executable (mode 100644); every other script under scripts/ is 100755. It works today because package.json.js invokes it as `bash scripts/audit-production.sh`, but direct execution (`./scripts/audit-production.sh`) fails with permission denied. Mark it executable to match the repo convention: `chmod +x scripts/audit-production.sh` and commit the mode change.</violation>
</file>

<file name="scripts/audit-production-policy.ts">

<violation number="1" location="scripts/audit-production-policy.ts:46">
P2: The hand-rolled `bun pm why` parser assumes a fixed 3-column-per-level indentation and rejects any non-integer depth or unrecognized line by throwing `AuditInputError`, which aborts the entire multi-package audit. Multi-branch trees that render `│` continuation characters break the `(indentation + 1) / 3` invariant, and any bun formatting change fails the whole gate even though the affected package is otherwise fine. Make the parser tolerant (skip or warn on an unrecognized line; fall back to a conservative unresolved path) instead of throwing, so a single transitive package's rendering cannot take down the audit for every published package.</violation>

<violation number="2" location="scripts/audit-production-policy.ts:118">
P2: When a valid waiver uses a lowercase GHSA/CVE ID, `parsePolicy` accepts it but this comparison rejects the waiver because the audit URL preserves different casing. Normalize both IDs before comparing, or require canonical uppercase IDs during policy parsing.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

if (finding === undefined) continue;
const exception = policy.acceptedAdvisories.find(
(candidate) =>
candidate.id === finding.id &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When a valid waiver uses a lowercase GHSA/CVE ID, parsePolicy accepts it but this comparison rejects the waiver because the audit URL preserves different casing. Normalize both IDs before comparing, or require canonical uppercase IDs during policy parsing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/audit-production-policy.ts, line 118:

<comment>When a valid waiver uses a lowercase GHSA/CVE ID, `parsePolicy` accepts it but this comparison rejects the waiver because the audit URL preserves different casing. Normalize both IDs before comparing, or require canonical uppercase IDs during policy parsing.</comment>

<file context>
@@ -0,0 +1,130 @@
+				if (finding === undefined) continue;
+				const exception = policy.acceptedAdvisories.find(
+					(candidate) =>
+						candidate.id === finding.id &&
+						candidate.package === finding.package &&
+						candidate.severity === finding.severity &&
</file context>

const node = match[2];
if (node === undefined)
throw new AuditInputError(`missing package in bun pm why line: ${line}`);
const depth = indentation === 0 ? 0 : (indentation + 1) / 3;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The hand-rolled bun pm why parser assumes a fixed 3-column-per-level indentation and rejects any non-integer depth or unrecognized line by throwing AuditInputError, which aborts the entire multi-package audit. Multi-branch trees that render continuation characters break the (indentation + 1) / 3 invariant, and any bun formatting change fails the whole gate even though the affected package is otherwise fine. Make the parser tolerant (skip or warn on an unrecognized line; fall back to a conservative unresolved path) instead of throwing, so a single transitive package's rendering cannot take down the audit for every published package.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/audit-production-policy.ts, line 46:

<comment>The hand-rolled `bun pm why` parser assumes a fixed 3-column-per-level indentation and rejects any non-integer depth or unrecognized line by throwing `AuditInputError`, which aborts the entire multi-package audit. Multi-branch trees that render `│` continuation characters break the `(indentation + 1) / 3` invariant, and any bun formatting change fails the whole gate even though the affected package is otherwise fine. Make the parser tolerant (skip or warn on an unrecognized line; fall back to a conservative unresolved path) instead of throwing, so a single transitive package's rendering cannot take down the audit for every published package.</comment>

<file context>
@@ -0,0 +1,130 @@
+		const node = match[2];
+		if (node === undefined)
+			throw new AuditInputError(`missing package in bun pm why line: ${line}`);
+		const depth = indentation === 0 ? 0 : (indentation + 1) / 3;
+		if (!Number.isInteger(depth))
+			throw new AuditInputError(`unrecognized bun pm why indentation: ${line}`);
</file context>

@@ -0,0 +1,5 @@
#!/usr/bin/env bash

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The new shell script carries a #!/usr/bin/env bash shebang but is committed non-executable (mode 100644); every other script under scripts/ is 100755. It works today because package.json.js invokes it as bash scripts/audit-production.sh, but direct execution (./scripts/audit-production.sh) fails with permission denied. Mark it executable to match the repo convention: chmod +x scripts/audit-production.sh and commit the mode change.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/audit-production.sh, line 1:

<comment>The new shell script carries a `#!/usr/bin/env bash` shebang but is committed non-executable (mode 100644); every other script under scripts/ is 100755. It works today because package.json.js invokes it as `bash scripts/audit-production.sh`, but direct execution (`./scripts/audit-production.sh`) fails with permission denied. Mark it executable to match the repo convention: `chmod +x scripts/audit-production.sh` and commit the mode change.</comment>

<file context>
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
</file context>

@coleleavitt

Copy link
Copy Markdown
Contributor Author

Retriggering the unchanged commit because the plugin job failed only in unrelated TUI runtime import probes; changed audit tests and live audit passed.

@coleleavitt coleleavitt reopened this Aug 19, 2026
@coleleavitt

Copy link
Copy Markdown
Contributor Author

The production audit itself is green. The plugin job failed twice in the unrelated @opentui/core/testing / TreeSitterClient initialization-order race. That race is now fixed and stress-tested (20/20) in test-reliability PR #338. Merge #338 first, then rerun this PR; I deliberately did not duplicate that unrelated test fix into this security-policy branch.

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