Skip to content

Add native Go fuzzing coverage#227

Merged
bomly-guy merged 2 commits into
mainfrom
codex/add-native-go-fuzzing
Jul 3, 2026
Merged

Add native Go fuzzing coverage#227
bomly-guy merged 2 commits into
mainfrom
codex/add-native-go-fuzzing

Conversation

@bomly-guy

@bomly-guy bomly-guy commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add native Go fuzz targets for lockfile parsers, SBOM JSON, SDK transport/PURL handling, and plugin path/archive sanitizers
  • add make fuzz and an explicit fuzz target runner with configurable FUZZTIME
  • add a nightly/manual GitHub Actions fuzz workflow and contributor/CI documentation
  • harden plugin relative-path validation after fuzzing found ".\\" cleaned to "." and was accepted

Validation

  • go test ./internal/detectors/node/npm ./internal/detectors/node/pnpm ./internal/detectors/node/yarn ./internal/sbom ./sdk ./internal/plugin
  • make fuzz FUZZTIME=5s
  • go test ./internal/detectors/gradle ./internal/detectors/maven ./internal/detectors/sbt after transient Java readiness timeouts
  • make test
  • git diff --check
  • make fmt-check

Note: the first full make test run hit transient Java readiness timeouts in Gradle/Maven/sbt detector tests; those packages passed on immediate rerun, and the subsequent full make test passed.

Summary by CodeRabbit

  • New Features

    • Added a scheduled and manually runnable fuzzing workflow to improve ongoing resilience checks.
    • Introduced a project-wide fuzzing command for local and CI use.
  • Bug Fixes

    • Tightened path validation to reject an additional invalid relative-path case.
  • Tests

    • Added fuzz coverage for dependency lockfiles, SBOM JSON handling, plugin paths, package URLs, graph data, and registry data.
  • Documentation

    • Expanded contributor and CI docs with fuzzing guidance and recovery steps for minimized failures.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@bomly-guy, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 844baae0-a7d8-4a06-a60a-569be19c9ca8

📥 Commits

Reviewing files that changed from the base of the PR and between 106cde5 and b01fb44.

📒 Files selected for processing (5)
  • internal/detectors/node/nodetest/fuzz.go
  • internal/detectors/node/npm/npm_lockfile_fuzz_test.go
  • internal/detectors/node/pnpm/pnpm_lockfile_fuzz_test.go
  • internal/detectors/node/yarn/yarn_lockfile_fuzz_test.go
  • sdk/fuzz_test.go
📝 Walkthrough

Walkthrough

This PR adds native Go fuzz testing across the repository: a scheduled CI workflow, a Makefile target and shell script to run fuzz targets, documentation updates, fuzz tests for npm/pnpm/yarn lockfile parsers, SBOM codec, plugin path sanitizers, and SDK JSON handling, plus a small plugin path validation fix.

Changes

Native Go Fuzzing Infrastructure

Layer / File(s) Summary
CI workflow, Make target, and fuzz runner script
.github/workflows/fuzz.yml, Makefile, scripts/run-fuzz.sh, CONTRIBUTING.md, dev-docs/CI.md
Adds a nightly/manual Fuzz CI workflow, a fuzz Make target with FUZZTIME variable, a runner script iterating fuzz targets via go test -fuzz, and documents fuzzing usage for contributors.
Lockfile parser fuzz tests
internal/detectors/node/npm/npm_lockfile_fuzz_test.go, internal/detectors/node/pnpm/pnpm_lockfile_fuzz_test.go, internal/detectors/node/yarn/yarn_lockfile_fuzz_test.go
Adds seeded fuzz tests writing fuzzed lockfile content to temp projects and validating the parsed dependency graph structure for npm, pnpm, and yarn.
SBOM codec fuzz test
internal/sbom/codec_fuzz_test.go
Adds FuzzUnmarshalAutoJSON, validating unmarshal/marshal round-trip behavior on SPDX/CycloneDX JSON inputs.
Plugin path sanitization fix and fuzz test
internal/plugin/types.go, internal/plugin/path_fuzz_test.go
Fixes cleanRelativePluginPath to reject a cleaned path of ".", and adds a fuzz test covering archive name sanitization and path traversal safety.
SDK fuzz tests
sdk/fuzz_test.go
Adds fuzz tests for CanonicalizePackageURL, Graph JSON round-trips, and PackageRegistry JSON round-trips with a shared graph validation helper.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Cron as Scheduled Trigger
  participant Workflow as Fuzz Workflow
  participant Make as make fuzz
  participant Script as run-fuzz.sh
  participant GoTest as go test -fuzz

  Cron->>Workflow: nightly trigger / manual dispatch
  Workflow->>Make: make fuzz FUZZTIME=2m
  Make->>Script: scripts/run-fuzz.sh
  Script->>GoTest: run each fuzz target (npm, pnpm, yarn, sbom, plugin, sdk)
  GoTest-->>Workflow: pass/fail results
  Workflow->>Workflow: upload testdata/fuzz artifacts on failure
Loading

Sequence diagram(s) (compact metadata)

  • Related issues: None referenced
  • Related PRs: None referenced
  • Suggested labels: testing, ci, security
  • Suggested reviewers: None specified

🐰 A rabbit hops through fuzzed terrain,
Seeding chaos, checking again,
Lockfiles, SBOMs, paths made tight,
Every corner tested right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding native Go fuzz targets and fuzzing infrastructure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/add-native-go-fuzzing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@bomly-guy bomly-guy marked this pull request as ready for review July 3, 2026 10:38
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Bomly Diff Summary

Compared 92fc08bba5301494759a01ba959969b8c95b6f74 to b01fb4400362f2090da2383718d903df7fc7a23f.

Overview

Status Manifests Dependencies Findings Duration
⚠️ Warnings +1 / ~0 / -0 +4 / ~0 / -0 1 introduced / 0 persisted / 0 resolved 1m 4s

Dependency Changes

Summary: 4 added, 0 changed, 0 removed.

Added Dependencies

Change Package Version Direct? Scope Licenses
added .github/workflows/fuzz.yml@local local No runtime -
added actions:checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 Yes runtime -
added actions:setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 924ae3a1cded613372ab5595356fb5720e22ba16 Yes runtime -
added actions:upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 ea165f8d65b6e75b540449e92b4886f43607fa02 Yes runtime -

Vulnerabilities

✅ No vulnerability changes.

License Changes

✅ No license changes.

Project Posture

✅ No project posture changes (--matchers +scorecard was not selected).

Policy Findings

Summary: 1 introduced, 0 persisted, 0 resolved.

Introduced Findings

Status Category Severity ID Package Fixed In Title
⚠️ introduced license WARNING UNKNOWN-zh7e-g3ge-2da2 .github/workflows/fuzz.yml@local - Package license is unknown

Legend: ✅ resolved · ❌ failing · ⚠️ warning

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
internal/detectors/node/npm/npm_lockfile_fuzz_test.go (1)

11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared fuzz-validation helper instead of copy-pasting across packages.

maxFuzzInputSize and requireFuzzGraphValid are duplicated verbatim in the npm, pnpm, and yarn fuzz test files. Since the codebase already favors shared test helpers (e.g. testutil.BuildGoBinary()), consider moving this graph-invariant validation into a small shared test helper package (e.g. internal/detectors/node/nodetest or similar) so all three ecosystems share one implementation and future changes to the invariant only need to happen once.

♻️ Suggested consolidation
// internal/detectors/node/nodetest/fuzz.go
package nodetest

const MaxFuzzInputSize = 1 << 20

func RequireFuzzGraphValid(t *testing.T, graph *sdk.Graph) {
	t.Helper()
	// ... same body ...
}

Then in each fuzz test file:

-const maxFuzzInputSize = 1 << 20
-
 func FuzzDepGraphFromNPMLockfile(f *testing.F) {
   ...
-  requireFuzzGraphValid(t, graph)
+  nodetest.RequireFuzzGraphValid(t, graph)
 }
-
-func requireFuzzGraphValid(t *testing.T, graph *sdk.Graph) { ... }

Also applies to: 39-62

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/detectors/node/npm/npm_lockfile_fuzz_test.go` at line 11, The
fuzz-test validation logic is duplicated across the npm, pnpm, and yarn node
detector tests, including the max input size constant and requireFuzzGraphValid
helper. Move this shared invariant-checking code into a small common test helper
package such as nodetest, and have npm_lockfile_fuzz_test and the sibling fuzz
tests call that shared helper instead of keeping local copies. Keep the shared
symbols named clearly, like MaxFuzzInputSize and RequireFuzzGraphValid, so
future invariant changes happen in one place.
sdk/fuzz_test.go (1)

46-64: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Round-trip fuzz tests don't verify data fidelity, only that re-marshal/unmarshal succeeds.

Both FuzzGraphJSON and FuzzPackageRegistryJSON marshal the decoded value and unmarshal it again, but never compare the round-tripped value against the original decoded value. This means these targets can't catch a class of bug fuzzing is specifically good at finding: silent data loss/corruption during marshal/unmarshal (e.g., a dropped edge, altered PURL, or mutated field) that doesn't produce an error.

Consider asserting structural/value equality between the original and round-tripped graph/registry (e.g., compare node/edge counts and IDs, or use reflect.DeepEqual if the types support it deterministically).

♻️ Example addition for FuzzGraphJSON
 		var roundTrip Graph
 		if err := json.Unmarshal(encoded, &roundTrip); err != nil {
 			t.Fatalf("round-trip graph JSON does not unmarshal: %v", err)
 		}
+		requireFuzzGraphValid(t, &roundTrip)
+		if roundTrip.Size() != graph.Size() {
+			t.Fatalf("round-trip graph size mismatch: got %d want %d", roundTrip.Size(), graph.Size())
+		}

Also applies to: 75-100

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/fuzz_test.go` around lines 46 - 64, The fuzz targets in FuzzGraphJSON and
FuzzPackageRegistryJSON only verify that marshal/unmarshal succeeds, so they
miss silent data corruption. After the round-trip in these functions, compare
the decoded value against the original decoded value using a deterministic
structural/value check (for example, DeepEqual or explicit comparisons of
counts/IDs/fields for Graph and the registry type). Keep the existing
unmarshal/marshal error checks, but add an assertion that the round-tripped
object matches the pre-মarshal object so fuzzing can catch data loss.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/detectors/node/npm/npm_lockfile_fuzz_test.go`:
- Line 11: The fuzz-test validation logic is duplicated across the npm, pnpm,
and yarn node detector tests, including the max input size constant and
requireFuzzGraphValid helper. Move this shared invariant-checking code into a
small common test helper package such as nodetest, and have
npm_lockfile_fuzz_test and the sibling fuzz tests call that shared helper
instead of keeping local copies. Keep the shared symbols named clearly, like
MaxFuzzInputSize and RequireFuzzGraphValid, so future invariant changes happen
in one place.

In `@sdk/fuzz_test.go`:
- Around line 46-64: The fuzz targets in FuzzGraphJSON and
FuzzPackageRegistryJSON only verify that marshal/unmarshal succeeds, so they
miss silent data corruption. After the round-trip in these functions, compare
the decoded value against the original decoded value using a deterministic
structural/value check (for example, DeepEqual or explicit comparisons of
counts/IDs/fields for Graph and the registry type). Keep the existing
unmarshal/marshal error checks, but add an assertion that the round-tripped
object matches the pre-মarshal object so fuzzing can catch data loss.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ad009a0-ab1e-45b8-b383-e9309a3830a4

📥 Commits

Reviewing files that changed from the base of the PR and between 92fc08b and 106cde5.

📒 Files selected for processing (12)
  • .github/workflows/fuzz.yml
  • CONTRIBUTING.md
  • Makefile
  • dev-docs/CI.md
  • internal/detectors/node/npm/npm_lockfile_fuzz_test.go
  • internal/detectors/node/pnpm/pnpm_lockfile_fuzz_test.go
  • internal/detectors/node/yarn/yarn_lockfile_fuzz_test.go
  • internal/plugin/path_fuzz_test.go
  • internal/plugin/types.go
  • internal/sbom/codec_fuzz_test.go
  • scripts/run-fuzz.sh
  • sdk/fuzz_test.go

@bomly-guy bomly-guy merged commit 7562491 into main Jul 3, 2026
13 checks passed
@bomly-guy bomly-guy deleted the codex/add-native-go-fuzzing branch July 3, 2026 21:42
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