Skip to content

Add repository-level grype ignore policy for no-fix libc6 CVEs - #52924

Merged
pelikhan merged 6 commits into
mainfrom
copilot/container-image-scan-fix-issues
Aug 15, 2026
Merged

Add repository-level grype ignore policy for no-fix libc6 CVEs#52924
pelikhan merged 6 commits into
mainfrom
copilot/container-image-scan-fix-issues

Conversation

Copilot AI commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

The daily container scan flags Critical/High findings in ghcr.io/github/github-mcp-server:v1.9.0 that have no available remediation: v1.9.0 is the latest upstream release and its tag digest is unchanged, and the glibc CVEs (CVE-2026-5450, CVE-2026-5928, CVE-2026-5435) have no fixed version published by Debian. Since the scan workflow gates on [Critical], this adds the risk-acceptance mechanism the issue recommends.

Findings triage

Finding Status
libc6 CVE-2026-5450 / 5928 / 5435 No Debian fix — risk-accepted here
golang.org/x/text GO-2026-5970 Inside upstream Go binary; gh-aw's own go.mod is already on v0.41.0. Needs an upstream rebuild
6 Grant license violations Already covered by the Debian base-OS ignore-packages block in .grant.yaml (#52912)

Changes

  • pkg/cli/grype.go--grype now picks up an optional repo-root .grype.yaml, mounts it read-only into the scanner container, and passes --config, mirroring how --grant consumes .grant.yaml. Docker arg construction moved into a testable grypeDockerArgs; behaviour is unchanged when the file is absent (including outside a git checkout).
  • .grype.yaml (new) — per-CVE ignore rules scoped to libc6/deb with a reason each, so newly disclosed libc6 vulnerabilities are still reported and rules can be deleted once Debian ships a patch.
  • Tests — arg construction with/without config, missing config file, repo config resolution.
  • Docssetup/cli.md and a "Container Vulnerability Exceptions" section in CONTRIBUTING.md describing when a rule is acceptable and when to remove it.
# .grype.yaml
ignore:
  - vulnerability: CVE-2026-5450
    reason: "Debian lists no fixed libc6 version; risk-accepted until a patched base image ships."
    package:
      name: libc6
      type: deb

Grype moves matched rules into ignoredMatches, so they drop out of the matches array the compiler renders and no longer trip the Critical gate. Scoping by CVE ID rather than package keeps future libc6 findings visible.


Run context: https://github.com/github/gh-aw/actions/runs/31896433106> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 9.01 AIC · ⌖ 5.84 AIC · ⊞ 8.7K ·

Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix container vulnerabilities and license violations Add repository-level grype ignore policy for no-fix libc6 CVEs Aug 15, 2026
Copilot AI requested a review from pelikhan August 15, 2026 16:32
@pelikhan
pelikhan marked this pull request as ready for review August 15, 2026 16:35
Copilot AI balanced review requested due to automatic review settings August 15, 2026 16:35
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Reviewed PR #52924 and found no actionable changed-line issues requiring GitHub write comments; submitting no-op for required safe output.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Ponytail review: no over-engineering found. The change mirrors the existing .grant.yaml pattern (grantPolicyFile/buildDockerReadonlyFileMount), reuses existing mount-validation helpers, and the config data (.grype.yaml) is intentionally scoped per-CVE rather than duplicated logic. Lean already. Ship.

Generated by Ponytail Reviewer for #52924

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-15T00:00:00Z
review_event: COMMENT
top_themes:
  - no actionable blocking issues found in changed lines
  - tests cover new grype config argument construction and repo config lookup
files_reviewed:
  - .grype.yaml
  - CONTRIBUTING.md
  - docs/src/content/docs/setup/cli.md
  - pkg/cli/grype.go
  - pkg/cli/grype_test.go
comment_count: 0

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 3.37 AIC · ⌖ 5.3 AIC · ⊞ 6.9K ·
Comment /review to run again

@github-actions github-actions 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.

Overall the changes are well-structured and follow the established grant pattern. The .grype.yaml config, documentation, and tests are all consistent.

One non-blocking concern was flagged inline: the scan-result cache keys only on imageRef while the result now also depends on configFile. This is safe in the current single-config-per-run flow, but it is a latent bug if the cache is ever reused across different config contexts.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 28.7 AIC · ⌖ 8 AIC · ⊞ 5.6K

Comment thread pkg/cli/grype.go Outdated
// and passed to grype via --config.
func grypeRunOnImage(imageRef, configFile string, verbose bool) (*grypeOutput, error) {
// Check cache first.
if result, err, ok := grypeScanResultCache.get(imageRef); ok {

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.

The cache in grypeRunOnImage keys on imageRef alone, but the scan result now also depends on configFile. If two calls in the same process use different configs for the same image reference, the second call returns the first call's cached result, silently ignoring the different config.

In the current wiring this is safe (config is resolved once per compile run), but it is a latent bug worth guarding against.

Suggested fix: include the config path in the cache key, e.g. cacheKey := imageRef + "|" + configFile.

@copilot please address this.

@github-actions github-actions Bot mentioned this pull request Aug 15, 2026
…CVEs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (126 new lines in pkg/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/52924-grype-repository-config-for-risk-accepted-cves.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI couldn't infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-52924: Repository-Level Grype Config for Risk-Accepted CVEs

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 52924-title.md for PR #52924).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · sonnet46 · 64.4 AIC · ⌖ 25 AIC · ⊞ 9K ·
Comment /review to run again

@github-actions github-actions 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.

Skills-Based Review 🧠

Applied /codebase-design and /tdd — requesting changes on a correctness issue with the result cache and a fragile environment-coupled test.

📋 Key Themes & Highlights

Key Themes

  • Cache correctness: The scan result cache key is imageRef alone, but results now vary by configFile. This is low-risk today (config is resolved once per run and passed identically to all grypeRunOnImage calls), but is a latent correctness bug for tests and future callers.
  • Environment-coupled test: TestGrypeConfigFileResolvesRepositoryPolicy assumes the test is executed from within the gh-aw git checkout. It should skip gracefully when that assumption doesn't hold.
  • Unnecessary runtime validation of a constant: validateContainerMountPath(grypeContainerConfigPath) is called on a fixed constant on every invocation; the error branch is unreachable.

Positive Highlights

  • ✅ Excellent refactor: grypeDockerArgs is cleanly testable and mirrors the pattern in grant.go.
  • ✅ Risk-acceptance rules are tightly scoped (specific CVE ID + package type) so new vulnerabilities aren't silently suppressed.
  • ✅ Documentation in CONTRIBUTING.md is actionable — it explains when to add and when to remove a rule.
  • ✅ Read-only volume mount reuses the existing validated buildDockerReadonlyFileMount helper.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 45.8 AIC · ⌖ 8.78 AIC · ⊞ 7.7K
Comment /matt to run again

Comment thread pkg/cli/grype.go Outdated
// and passed to grype via --config.
func grypeRunOnImage(imageRef, configFile string, verbose bool) (*grypeOutput, error) {
// Check cache first.
if result, err, ok := grypeScanResultCache.get(imageRef); ok {

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.

[/codebase-design] Cache key is imageRef alone, but scan results now vary by configFile too. A result cached without a config will be returned for a subsequent call with a config (or vice-versa) in the same process.

💡 Suggested fix

Include the config path in the cache key:

cacheKey := imageRef
if configFile != "" {
    cacheKey = imageRef + "\x00" + configFile
}
if result, err, ok := grypeScanResultCache.get(cacheKey); ok {
    ...
}
// and store with the same key
grypeScanResultCache.set(cacheKey, &output)

This is low-risk in production (config is resolved once per compile run), but it is a correctness issue for tests and future callers.

@copilot please address this.

Comment thread pkg/cli/grype.go
info, err := os.Stat(configFile)
if err != nil || !info.Mode().IsRegular() {
grypeLog.Printf("No grype config found at %s", configFile)
return ""

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.

[/codebase-design] validateContainerMountPath is called on grypeContainerConfigPath (a compile-time constant) on every invocation. This validation can never fail and adds dead-error-path noise. Consider validating it once (e.g., in a TestMain or init guard) or asserting it at compile time with a constant-fold check.

💡 Detail

grypeContainerConfigPath = "/tmp/gh-aw-grype-config.yaml" is a fixed constant that cannot change at runtime. validateContainerMountPath will always succeed for it, so the error branch at line 262 can never be reached. Either remove the runtime call and use the constant directly (trusting the existing test TestGrypeDockerArgs_WithConfig), or add a package-level init() assertion:

func init() {
    if _, err := validateContainerMountPath(grypeContainerConfigPath); err != nil {
        panic("invalid grypeContainerConfigPath constant: " + err.Error())
    }
}

@copilot please address this.

Comment thread pkg/cli/grype_test.go Outdated
func TestGrypeConfigFileResolvesRepositoryPolicy(t *testing.T) {
configFile := grypeConfigFile()
if configFile == "" {
t.Fatal("Expected repository grype config to be found")

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.

[/tdd] TestGrypeConfigFileResolvesRepositoryPolicy is an environment-coupled test: it passes only when the test is run from inside the gh-aw git checkout. In a different working directory (e.g., a temp dir or a CI runner that checks out to an unusual path) grypeConfigFile() may return "" and the test fails with a misleading message.

💡 Suggestion

Either skip the test when not in a git checkout, or use a table-driven approach with a synthetic git root:

func TestGrypeConfigFileResolvesRepositoryPolicy(t *testing.T) {
    if _, err := gitutil.FindGitRoot(); err != nil {
        t.Skip("not inside a git checkout")
    }
    configFile := grypeConfigFile()
    if configFile == "" {
        t.Fatal("Expected repository grype config to be found")
    }
    ...
}

This makes the test self-documenting about its environmental requirement and avoids false failures.

@copilot please address this.

Copilot AI 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.

Pull request overview

Adds repository-level Grype risk-acceptance rules for unpatched libc6 CVEs.

Changes:

  • Loads optional .grype.yaml policies during container scans.
  • Adds targeted CVE exceptions and documentation.
  • Adds argument/config-resolution tests.
Show a summary per file
File Description
.grype.yaml Defines vulnerability exceptions.
pkg/cli/grype.go Loads and mounts Grype configuration.
pkg/cli/grype_test.go Tests configuration and Docker arguments.
docs/src/content/docs/setup/cli.md Documents --grype configuration behavior.
CONTRIBUTING.md Documents exception governance.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 6/6 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread .grype.yaml
Comment on lines +14 to +28
- vulnerability: CVE-2026-5450
reason: "Debian lists no fixed libc6 version; risk-accepted until a patched base image ships."
package:
name: libc6
type: deb
- vulnerability: CVE-2026-5928
reason: "Debian lists no fixed libc6 version; risk-accepted until a patched base image ships."
package:
name: libc6
type: deb
- vulnerability: CVE-2026-5435
reason: "Debian lists no fixed libc6 version; risk-accepted until a patched base image ships."
package:
name: libc6
type: deb
Comment thread pkg/cli/grype.go
func grypeRunOnImage(imageRef string, verbose bool) (*grypeOutput, error) {
// When configFile is non-empty it is mounted read-only into the scanner container
// and passed to grype via --config.
func grypeRunOnImage(imageRef, configFile string, verbose bool) (*grypeOutput, error) {
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage for maintainer-ready follow-up:

Please refresh the branch if GitHub allows it, address the remaining reviewer feedback, and run the pr-finisher skill before handing this PR back to maintainers.

Outstanding review items (newest first):

  • github-actions requested changes on cache correctness: scan results currently key only on imageRef, but the result now also depends on configFile.
  • github-actions requested changes on test robustness: TestGrypeConfigFileResolvesRepositoryPolicy should skip gracefully when the repo checkout assumption does not hold.
  • github-actions requested linking the generated ADR in the PR body so the gate can clear.

Failed checks from the compact candidate set:

  • None listed.

Branch update was requested automatically for this run when GitHub allows it.
Run context: https://github.com/github/gh-aw/actions/runs/31896433106

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 9.01 AIC · ⌖ 5.84 AIC · ⊞ 8.7K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Quick triage for maintainer-ready follow-up:

Please refresh the branch if GitHub allows it, address the remaining reviewer feedback, and run the pr-finisher skill before handing this PR ba...

Addressed the cache and portable-test feedback in 558f715. Final local validation, review, and secret scanning passed; the generated ADR is linked in the PR handoff.

Copilot AI requested a review from gh-aw-bot August 15, 2026 17:08
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage for maintainer-ready follow-up:

Please refresh the branch if GitHub allows it, resolve the remaining open review threads, and run the pr-finisher skill before handing this PR back to maintainers.

Outstanding review items (newest first):

Failed checks from the compact candidate set:

  • None listed.

Branch update was requested automatically for this run when GitHub allows it.
Run context: https://github.com/github/gh-aw/actions/runs/31897747771

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 29.8 AIC · ⌖ 7.03 AIC · ⊞ 8.7K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Quick triage for maintainer-ready follow-up:

Please refresh the branch if GitHub allows it, resolve the remaining open review threads, and run the pr-finisher skill before handing this PR ...

Addressed the outstanding review points in a56d53b: each exception is now scoped to libc6 2.36-9+deb12u14; the content-digest cache isolation and skippable checkout test remain in place. Final validation, review, and secret scan passed.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage for maintainer-ready follow-up:

Please refresh the branch if GitHub allows it and run the pr-finisher skill before handing this PR back to maintainers.

The latest author reply says the previously listed review points were addressed, and GraphQL returned no unresolved review threads.

Outstanding maintainer-facing follow-up:

  • re-run or refresh the current review/check state on the latest head so maintainers can verify the updated cache/config changes.
  • if any stale blocking review remains after that refresh, summarize why it is obsolete and close the loop in the PR conversation.

Failed checks from the compact candidate set:

  • None listed.

Run context: https://github.com/github/gh-aw/actions/runs/31899148351

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 17.1 AIC · ⌖ 6.96 AIC · ⊞ 6.3K ·
Comment /souschef to run again

@pelikhan
pelikhan merged commit 3d913bd into main Aug 15, 2026
1 check failed
@pelikhan
pelikhan deleted the copilot/container-image-scan-fix-issues branch August 15, 2026 17:52
Copilot stopped work on behalf of gh-aw-bot due to an error August 15, 2026 17:53
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.87.0

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.

[container-image-scan] Container findings for ghcr.io/github/github-mcp-server:v1.9.0

4 participants