Skip to content

test(lockfile): add invariant — LocationRole must be set when BlockLocation is valid#149

Merged
anderruiz merged 2 commits into
mainfrom
ander/location-role-invariant-test
May 13, 2026
Merged

test(lockfile): add invariant — LocationRole must be set when BlockLocation is valid#149
anderruiz merged 2 commits into
mainfrom
ander/location-role-invariant-test

Conversation

@anderruiz
Copy link
Copy Markdown
Contributor

Summary

  • Adds a cross-extractor invariant test that walks all fixtures under `pkg/lockfile/fixtures/`, runs the registered extractor for each file, and fails if any `PackageDetails` has a valid `BlockLocation` (file + line + column all set) but an empty `LocationRole`.

Motivation

Identified while reviewing PR #126 (`PackageJSONExtractor`): the extractor sets `BlockLocation` for every package but omits `LocationRole`, so the `role` field in the SBOM output is blank. Since `LocationRole` is a plain `string` field, the compiler cannot enforce it — a test is the right safety net.

How the test catches PR #126 as-is: when that PR merges, `PackageJSONExtractor` is registered and its `package.json` fixtures are picked up by this test. The extractor sets a valid `BlockLocation` but leaves `LocationRole` empty → the test fails. After adding `LocationRole: models.LocationRoleManifest` (the fix) the test passes again.

Test plan

  • Passes on `main` (all current extractors already set `LocationRole` correctly)
  • Lint passes

🤖 Generated with Claude Code

…n is set

Any extractor that populates a valid BlockLocation must also set
LocationRole. Without it, the reporter emits a blank role field in
the SBOM output even though the location is meaningful.

The test walks pkg/lockfile/fixtures/, runs the registered extractor
for each fixture file, and fails if any PackageDetails has a valid
BlockLocation (file + line/column all non-zero) but an empty
LocationRole. It is a no-op for files without a registered extractor
and silently skips fixtures that intentionally fail to parse.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@anderruiz anderruiz requested a review from a team as a code owner May 13, 2026 13:19
@datadog-prod-us1-5

This comment has been minimized.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c15246aca6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return err
}

extractor, _ := lockfile.FindExtractor(path, map[string]bool{})
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 Badge Enable parsers before using FindExtractor

In this test, FindExtractor only returns an extractor when enabledParsers[name] is true (see pkg/lockfile/extract.go), so passing an empty map disables every registered parser. As a result extractor is nil for every fixture and the new invariant test passes without exercising any extractor, including the future package.json case it is meant to catch. Populate the map from the registered extractor names before walking fixtures, or use a helper that matches all registered extractors.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 4be1fa3. The test now populates allParsers from lockfile.ListSupportedExtractors() before passing it to FindExtractor, so every registered extractor is exercised against its fixture files.

Pass allParsers populated from ListSupportedExtractors() to FindExtractor
instead of an empty map. An empty map causes FindExtractor to return nil
for every fixture, making the test pass vacuously without exercising any
extractor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4be1fa3a63

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
defer f.Close()

packages, err := extractor.Extract(f, context)
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 Badge Exercise matcher-enriched package locations

For extractors that add source-file locations via matchers, this check is bypassed because it calls extractor.Extract directly. Production extraction then runs any ExtractorWithMatcher matchers (see ExtractFromFileWithContext), and those matchers are exactly where several manifest BlockLocation/LocationRole fields are populated. If a matcher regresses and starts setting a valid BlockLocation without LocationRole, this invariant still passes, so use the same extraction path that applies matchers for each fixture.

Useful? React with 👍 / 👎.

@anderruiz anderruiz merged commit 153b51a into main May 13, 2026
11 checks passed
@anderruiz anderruiz deleted the ander/location-role-invariant-test branch May 13, 2026 14:19
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.

2 participants