Conversation
… is enumerated Both SBOMs are generated from the installed tree (npm ci, then npm sbom --omit dev) so they describe what a consumer's `npm install` receives. The validator that gates the upload, however, only required the SPDX document to list at least one package, which a document produced from an uninstalled checkout satisfies with a single self-describing entry and zero dependencies. Extend scripts/supply-chain/validate-sbom.mjs: take the `dependencies` keys of package.json as the declared runtime set (never a hardcoded number), require a versioned SPDX entry for the package itself and for every declared name (missing/empty/NOASSERTION versionInfo does not count), require a matching CycloneDX component for every declared name (by `name` or npm purl, scoped and percent-encoded names included), and refuse a manifest that declares no runtime dependencies at all. Failures name the missing packages. Tests: fixtures now carry the versionInfo npm sbom actually emits; new cases cover the uninstalled shape, NOASSERTION entries, a missing CycloneDX component, a missing root entry, the zero-floor refusal, and the purl parser. vitest (repo-pinned 4.1.11): 38 passed. Local npm sbom receipt on 2.1.3: installed tree -> exit 0; stripped document -> exit 1 (missing eventemitter3). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
ⓘ Qodo reviews are paused because your workspace is out of credits. Ask your workspace admin to add credits to resume reviews. Manage billing |
There was a problem hiding this comment.
Sorry @yakimoto, this account has used its review budget of 2,500,000 diff characters for the last 7 days.
You can request another review in 52 minutes by commenting @sourcery-ai review.
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_af8b68bf-a650-4983-81f1-12718b7c695d) |
|
Warning Review limit reachedNext included review available in 54 minutes. View limit detailsLimit details: You’ve used the included review currently available. Your 72 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Team Run ID: 📒 Files selected for processing (2)
Comment |
Reviewer's GuideThe PR adds a manifest-driven second gate for SBOM completeness, requiring every declared runtime dependency to appear with usable identity data in both SPDX and CycloneDX documents while preserving existing format and release-version checks. It also adds focused pure helpers, actionable failures, success reporting, and regression tests for uninstalled-tree and npm purl edge cases. Flow diagram for manifest-driven SBOM validationflowchart TD
Manifest[package.json dependencies] --> Declared[declaredDependencies]
SPDX[SPDX document] --> SPDXNames[spdxVersionedNames]
CycloneDX[CycloneDX document] --> CDXNames[cyclonedxComponentNames]
Declared --> Gate{Every declared dependency present?}
SPDXNames --> Gate
CDXNames --> Gate
Gate -->|No runtime dependencies| RejectFloor[Reject zero dependency floor]
Gate -->|Missing versioned SPDX entry| RejectSPDX[Fail with missing package names]
Gate -->|Missing CycloneDX component| RejectCDX[Fail with missing package names]
Gate -->|All checks pass| Summary[Report dependencies enumerated in both SBOMs]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Note Automatic reviews are paused because your team has used its included automatic processing for this billing period (headroom scales with your seat count). You can still comment "Gitar review" to run one anytime, and automatic reviews resume on their own by October 1. Add seats for more headroom. Code Review ✅ ApprovedStrengthens pre-upload SBOM validation to require every declared runtime dependency in both SPDX and CycloneDX documents, closing the regression where an uninstalled tree would ship with only the root package. Exports three helpers for unit-testable parsing and includes comprehensive test coverage for missing versions, scoped names, and edge cases. No issues found. OptionsDisplay: compact → Counting what did not apply, without listing it. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This focused change hardens the release SBOM validator and can block SBOM publication when declared dependencies are not fully represented. Because it modifies a security-sensitive supply-chain control in the release process, human review is warranted. Not approved because:
Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
2 issues found across 2 files
Confidence score: 3/5
- In
scripts/supply-chain/validate-sbom.mjs, whitespace-onlyversionInfocan bypass the fail-closed dependency validation, allowing malformed SPDX entries through; trim the value before checking it against empty orNOASSERTION. - In
scripts/supply-chain/validate-sbom.mjs, a missing usablepackage.jsonname can skip the required root SPDX validation, weakening release-manifest checks; reject nameless manifests first and make the root check unconditional.
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/supply-chain/validate-sbom.mjs">
<violation number="1" location="scripts/supply-chain/validate-sbom.mjs:50">
P2: A whitespace-only `versionInfo` is accepted as versioned, allowing a malformed SPDX entry to pass the fail-closed dependency check. Trim `versionInfo` before testing it against the empty and `NOASSERTION` values.</violation>
<violation number="2" location="scripts/supply-chain/validate-sbom.mjs:107">
P2: When `package.json` has no usable `name`, this condition skips the required root SPDX check entirely. Reject a nameless release manifest before checking the root entry, then make the root check unconditional.</violation>
</file>
Architecture diagram
sequenceDiagram
participant CI as Release CI
participant NPM as npm CLI
participant FS as Installed Tree (node_modules)
participant SBOM as SBOM Generator
participant VAL as validateSbom.mjs
participant PKG as package.json
participant SPDX as SPDX Doc
participant CDX as CycloneDX Doc
Note over CI,CDX: Release SBOM Validation Flow
CI->>NPM: npm ci
NPM->>FS: Install dependencies
FS-->>NPM: Installed tree ready
CI->>SBOM: npm sbom --omit dev (SPDX)
SBOM->>FS: Read installed packages
FS-->>SBOM: Package inventory
SBOM-->>CI: SPDX document
CI->>SBOM: npm sbom --omit dev (CycloneDX)
SBOM->>FS: Read installed packages
FS-->>SBOM: Package inventory
SBOM-->>CI: CycloneDX document
CI->>VAL: validateSboms(tag, pkg, cyclonedx, spdx)
VAL->>PKG: Extract dependencies keys
PKG-->>VAL: Declared runtime deps
alt No runtime dependencies declared
VAL-->>CI: Error: refuses floor of 0
else Dependencies declared
VAL->>SPDX: Check versioned entries for each dep
SPDX-->>VAL: Package names with versionInfo
alt SPDX missing deps or weak versionInfo
VAL-->>CI: Error: names missing packages
else SPDX passes
VAL->>SPDX: Check root package entry
SPDX-->>VAL: Root package with version
alt No versioned root entry
VAL-->>CI: Error: package itself missing
else Root entry valid
VAL->>CDX: Check components for each dep
CDX-->>VAL: Component names and purls
alt CDX missing components
VAL-->>CI: Error: names missing packages
else All checks pass
VAL-->>CI: declaredDependencyCount + success summary
end
end
end
end
Note over VAL,CDX: Validation ensures SBOMs reflect installed tree, not pre-install state
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| export function spdxVersionedNames(spdx) { | ||
| const names = new Set(); | ||
| for (const p of Array.isArray(spdx?.packages) ? spdx.packages : []) { | ||
| const version = typeof p?.versionInfo === 'string' ? p.versionInfo : ''; |
There was a problem hiding this comment.
P2: A whitespace-only versionInfo is accepted as versioned, allowing a malformed SPDX entry to pass the fail-closed dependency check. Trim versionInfo before testing it against the empty and NOASSERTION values.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/supply-chain/validate-sbom.mjs, line 50:
<comment>A whitespace-only `versionInfo` is accepted as versioned, allowing a malformed SPDX entry to pass the fail-closed dependency check. Trim `versionInfo` before testing it against the empty and `NOASSERTION` values.</comment>
<file context>
@@ -27,10 +35,42 @@ export function versionFromTag(tag) {
+export function spdxVersionedNames(spdx) {
+ const names = new Set();
+ for (const p of Array.isArray(spdx?.packages) ? spdx.packages : []) {
+ const version = typeof p?.versionInfo === 'string' ? p.versionInfo : '';
+ if (typeof p?.name === 'string' && p.name && !NO_VERSION.has(version)) names.add(p.name);
+ }
</file context>
| const version = typeof p?.versionInfo === 'string' ? p.versionInfo : ''; | |
| const version = typeof p?.versionInfo === 'string' ? p.versionInfo.trim() : ''; |
| ); | ||
| } | ||
| const spdxNames = spdxVersionedNames(spdx); | ||
| if (typeof pkg?.name === 'string' && pkg.name && !spdxNames.has(pkg.name)) { |
There was a problem hiding this comment.
P2: When package.json has no usable name, this condition skips the required root SPDX check entirely. Reject a nameless release manifest before checking the root entry, then make the root check unconditional.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/supply-chain/validate-sbom.mjs, line 107:
<comment>When `package.json` has no usable `name`, this condition skips the required root SPDX check entirely. Reject a nameless release manifest before checking the root entry, then make the root check unconditional.</comment>
<file context>
@@ -54,11 +94,41 @@ export function validateSboms({ tag, pkg, cyclonedx, spdx }) {
+ );
+ }
+ const spdxNames = spdxVersionedNames(spdx);
+ if (typeof pkg?.name === 'string' && pkg.name && !spdxNames.has(pkg.name)) {
+ throw new Error(`spdx: no versioned package entry for the package itself, ${pkg.name}@${version}`);
+ }
</file context>
User description
What
sbom.ymlalready generates both SBOMs from the installed tree (npm ci, thennpm sbom --omit devfor CycloneDX and SPDX), so they describe what a consumer ofnpm install @wave-av/sdkactually receives. The validator that gates the upload,scripts/supply-chain/validate-sbom.mjs, only required the SPDX document to list at least one package. A document produced from an uninstalled checkout satisfies that with a single self-describing entry and zero dependencies, so a regression to scanning before install would have shipped silently.This PR extends
validateSboms()with a per-name check and keeps every existing check intact:dependencieskeys ofpackage.jsonas the declared runtime set, so the floor tracks the manifest and is never a hardcoded number;packages[]entry for the package itself and for every declared name (entries with a missing, empty, orNOASSERTIONversionInfodo not count);nameor by npm purl (scoped, percent-encoded names such aspkg:npm/%40wave-av/sdk@2.1.3decode correctly);Three small pure helpers are exported (
declaredDependencies,spdxVersionedNames,cyclonedxComponentNames) so the parsing is unit-testable on its own. No workflow YAML changes; the step insbom.ymlthat calls the script is unchanged.Tests
scripts/supply-chain/__tests__/validate-sbom.test.ts: fixtures now carry theversionInfothatnpm sbomactually emits and apackage.jsonwith the real single runtime dependency. New cases cover the uninstalled shape (root only), NOASSERTION / missing versionInfo, a missing CycloneDX component, a missing root SPDX entry, the zero-floor refusal, the success summary, and the purl name parser.Local receipts (GitHub Actions is billing-locked, so nothing ran in CI)
./node_modules/.bin/vitest run scripts/supply-chain(repo-pinned vitest 4.1.11): 2 files, 38 tests passed.npm sbom --omit devon the installed 2.1.3 tree: SPDX 2 packages, CycloneDX 1 component; validator exit 0 withall 1 declared runtime dependencies enumerated in both.no versioned package entry for declared runtime dependency(ies): eventemitter3.npm sbomon a tree with nonode_modulesrefuses outright (ESBOMPROBLEMS), which is the property the workflow comment already relies on; the validator is the second, independent gate.actionlint .github/workflows/*.yml: only a pre-existing info-level SC2016 ingovernance-enforce.yml, untouched here.no-undef processfindings onmainand on this branch (CI lintssrc/only), so no new lint debt.Why it matters
An SBOM that enumerates only the top-level package is a claim, not an inventory. Checking every declared dependency by name in both documents makes the release job fail loudly if the installed tree ever stops being what
npm sbomreads.🤖 Generated with Claude Code
Note
Low Risk
Supply-chain release gating only: stricter validation with broad test coverage and clearer failure messages, with no changes to runtime SDK behavior or auth/data paths.
Overview
Tightens pre-upload SBOM validation so a non-empty SPDX document alone can’t pass when dependencies are missing—closing the “scan before
npm ci” regression where only the root package appears.validateSboms()now derives the required set frompackage.jsondependenciesand insists each name shows up in both SBOMs: SPDX entries must have realversionInfo(not missing, empty, orNOASSERTION), including the released package itself; CycloneDX matches bynameor decoded npmpurl. Manifests with zero runtime dependencies are rejected outright. Success output includesdeclaredDependencyCount.Three exported helpers (
declaredDependencies,spdxVersionedNames,cyclonedxComponentNames) support the checks and unit tests. Fixtures and new Vitest cases cover the uninstalled shape, weak SPDX entries, missing CycloneDX components, missing root SPDX entry, and purl parsing. No workflow YAML changes—the existingsbom.ymlstep still calls the same script.Reviewed by Cursor Bugbot for commit 0686f0d. Bugbot is set up for automated code reviews on this repo. Configure here.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.CodeAnt-AI Description
Require release SBOMs to include every runtime dependency
What Changed
Impact
✅ Prevents incomplete dependency inventories from shipping✅ Catches SBOMs generated before dependencies are installed✅ Clearer release failures for missing packages💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.