Sitelet https://github.com/git-pkgs/git-pkgs/pull/332
Skip to content

Attach manifest occurrences to SBOM components - #332

Merged
andrew merged 4 commits into
git-pkgs:mainfrom
abhinavgautam01:feature/sbom-occurrence-properties-307
Aug 28, 2026
Merged

andrew merged 4 commits into
git-pkgs:mainfrom
abhinavgautam01:feature/sbom-occurrence-properties-307

Conversation

@abhinavgautam01

Copy link
Copy Markdown
Contributor

Closes #307

Summary

  • Retain every manifest and lockfile occurrence represented by a deduplicated SBOM component.
  • Emit indexed occurrence properties containing:
    • manifest_path
    • requirement
    • dependency_type
  • Preserve the existing preference for resolved versions as component primaries.
  • Associate manifest ranges with compatible resolved components, preferring direct lockfile entries when available.
  • Preserve deterministic component and occurrence ordering.
  • Update github.com/git-pkgs/sbom to the merged commit from Preserve package properties in CycloneDX output sbom#14 so properties are encoded in CycloneDX JSON and XML.

Dependency version

github.com/git-pkgs/sbom is currently pinned to the immutable pseudo-version for the merged git-pkgs/sbom#14 commit because v0.1.6 has not yet been tagged.

The dependency can be changed to v0.1.6 if that tag is published before this PR merges.

Testing

Added regression coverage for:

  • Indexed occurrence property generation.
  • CycloneDX JSON and XML property encoding.
  • Multiple declarations of one component across workspace manifests.
  • Manifest range association when multiple resolved versions exist.
  • Existing resolved-version preference and dependencies without PURLs.

Verification

  • gofmt
  • go test ./... -count=1
  • go tool golangci-lint run ./...
  • go mod tidy -diff
  • git diff --check

@andrew andrew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • cmd/sbom.go:210-240: Resolution matching requires the manifest and lockfile to share a directory. A root package-lock.json cannot resolve packages/web/package.json. A real npm workspace produces two lodash components, with the nested declaration absent from the resolved component. Match shared root or ancestor lockfiles and add a regression through the public sbom command.

  • cmd/sbom.go:292-304: When a valid constraint matches no candidate, the code retains every original candidate. A ^5.0.0 declaration is attached to lockfile version 4.17.21. Preserve this as an unresolved occurrence, and reserve fallback matching for unsupported constraint syntax.

  • cmd/sbom.go:151-157: sbom --type spdx drops every occurrence property because git-pkgs/sbom has no SPDX property encoding. Fix and release that module before bumping it here, or explicitly limit occurrence metadata to CycloneDX.

  • go.mod:17: v0.1.6 now contains the pinned commit, so the temporary pseudo-version should be removed. That tag requires Go 1.26.7 while this project pins 1.26.6, so either bump the project toolchain or publish a compatible sbom release.

@abhinavgautam01
abhinavgautam01 force-pushed the feature/sbom-occurrence-properties-307 branch from 7a27913 to ed63645 Compare August 27, 2026 15:39
@abhinavgautam01

Copy link
Copy Markdown
Contributor Author

Addressed all four points. Workspace declarations now match the nearest ancestor lockfile, valid constraints with no matching resolved version remain unresolved, and occurrence properties are explicitly limited to CycloneDX and documented. I also switched to sbom v0.1.6, bumped Go to 1.26.7, added command-level regression coverage and rebased onto current main. Full tests and lint pass.

@andrew andrew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • cmd/sbom.go:335-362: Prefer direct candidates before constraint matching. Given foo@^5.0.0, a direct lockfile entry at 4.0.0, and a transitive entry at 5.1.0, sbom attaches the manifest occurrence to transitive foo@5.1.0. The nested entry cannot resolve the root declaration. Filter to direct entries first, leave the declaration unresolved when none satisfy its constraint, and add a command-level regression.

@abhinavgautam01

Copy link
Copy Markdown
Contributor Author

Thanks, Fixed. SBOM resolution now prefers direct lockfile candidates before evaluating constraints, so a compatible transitive entry cannot claim a direct manifest declaration. Added a command-level regression covering the mismatched direct and compatible transitive versions.

@andrew andrew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • cmd/sbom.go:335-343: Scope direct-candidate preference to manifests beside the lockfile. npm marks only root declarations as direct. When root and workspace manifests require different versions of the same package, the root candidate displaces the compatible workspace resolution before constraint matching. Add command-level coverage for that case.

@abhinavgautam01
abhinavgautam01 force-pushed the feature/sbom-occurrence-properties-307 branch from 0c3c3e8 to 087de4a Compare August 28, 2026 16:43
@abhinavgautam01

Copy link
Copy Markdown
Contributor Author

Thanks, Fixed. Direct-candidate preference is now limited to manifests beside the lockfile. Workspace manifests using an ancestor lockfile select the compatible resolved version using their own constraint.

I added command-level regression coverage for root and workspace manifests requiring different versions, rebased onto current main.

@andrew
andrew merged commit 39de458 into git-pkgs:main Aug 28, 2026
4 checks passed
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.

sbom: attach manifest occurrence to each component via properties

2 participants