Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 +96,34 @@ jobs:
id: scan-ref
run: echo "ref=ghcr.io/aureliolo/ai-company-backend:sha-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"

- name: Trivy scan
- name: Trivy scan (critical — hard fail)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
with:
image-ref: ${{ steps.scan-ref.outputs.ref }}
format: table
exit-code: "1"
severity: CRITICAL,HIGH
severity: CRITICAL
trivyignores: .trivyignore.yaml

- name: Trivy scan (high — warn only)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
continue-on-error: true
with:
image-ref: ${{ steps.scan-ref.outputs.ref }}
format: table
exit-code: "0"
severity: HIGH
trivyignores: .trivyignore.yaml
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment on lines +108 to +116
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

continue-on-error: true masks scan infrastructure failures

exit-code: "0" already instructs Trivy to exit with code 0 when vulnerabilities are found, making continue-on-error: true redundant for the intended use case. However, the combination is subtly problematic: if Trivy encounters a genuine infrastructure error (DB download failure, image pull error, malformed config), it still exits non-zero — but continue-on-error: true will swallow that failure and mark the step as passed.

The CRITICAL step (no continue-on-error) running first provides a partial mitigation — if the infrastructure is broken, the critical scan would fail first. However, there's a narrow window where the critical step succeeds and the high step then encounters a transient error (flaky network on DB re-download, ephemeral runner issues), resulting in the HIGH scan being silently skipped rather than visibly errored.

Using exit-code: "0" alone is sufficient to make findings non-blocking, while still correctly surfacing scan infrastructure failures in the step output. Consider removing continue-on-error: true from both the build-backend (line 110) and build-web (line 221) jobs:

Suggested change
- name: Trivy scan (high — warn only)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
continue-on-error: true
with:
image-ref: ${{ steps.scan-ref.outputs.ref }}
format: table
exit-code: "0"
severity: HIGH
trivyignores: .trivyignore.yaml
- name: Trivy scan (high — warn only)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
with:
image-ref: ${{ steps.scan-ref.outputs.ref }}
format: table
exit-code: "0"
severity: HIGH
trivyignores: .trivyignore.yaml
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/docker.yml
Line: 108-116

Comment:
**`continue-on-error: true` masks scan infrastructure failures**

`exit-code: "0"` already instructs Trivy to exit with code 0 when vulnerabilities are found, making `continue-on-error: true` redundant for the intended use case. However, the combination is subtly problematic: if Trivy encounters a genuine infrastructure error (DB download failure, image pull error, malformed config), it still exits non-zero — but `continue-on-error: true` will swallow that failure and mark the step as passed.

The CRITICAL step (no `continue-on-error`) running first provides a partial mitigation — if the infrastructure is broken, the critical scan would fail first. However, there's a narrow window where the critical step succeeds and the high step then encounters a transient error (flaky network on DB re-download, ephemeral runner issues), resulting in the HIGH scan being silently skipped rather than visibly errored.

Using `exit-code: "0"` alone is sufficient to make findings non-blocking, while still correctly surfacing scan infrastructure failures in the step output. Consider removing `continue-on-error: true` from both the `build-backend` (line 110) and `build-web` (line 221) jobs:

```suggestion
      - name: Trivy scan (high — warn only)
        uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
        with:
          image-ref: ${{ steps.scan-ref.outputs.ref }}
          format: table
          exit-code: "0"
          severity: HIGH
          trivyignores: .trivyignore.yaml
```

How can I resolve this? If you propose a fix, please make it concise.


- name: Grype scan
uses: anchore/scan-action@1638637db639e0ade3258b51db49a9a137574c3e # v6
with:
image: ${{ steps.scan-ref.outputs.ref }}
fail-build: true
severity-cutoff: high
severity-cutoff: critical
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

.grype.yaml is added in this PR, but the Grype scan step doesn’t explicitly reference it (no config/args pointing to .grype.yaml). If anchore/scan-action doesn’t automatically discover repo-local config in its execution environment, the CVE ignore won’t apply and the job can still fail on CVE-2026-22184. Consider passing the config explicitly (or adding a note/assertion in the workflow logs) so it’s unambiguous that Grype is using the intended ignore list.

Suggested change
severity-cutoff: critical
severity-cutoff: critical
grype-config: .grype.yaml

Copilot uses AI. Check for mistakes.
config: .grype.yaml

# Push only after both scans pass — prevents publishing vulnerable images.
# Push only after scans pass — prevents publishing vulnerable images.
# NOTE: This is a separate build invocation from the scan step. GHA cache
# ensures deterministic layer content, but the manifest digest differs due
# to SBOM + provenance attestation layers added only on push.
Expand Down Expand Up @@ -195,22 +207,34 @@ jobs:
id: scan-ref
run: echo "ref=ghcr.io/aureliolo/ai-company-web:sha-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"

- name: Trivy scan
- name: Trivy scan (critical — hard fail)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
with:
image-ref: ${{ steps.scan-ref.outputs.ref }}
format: table
exit-code: "1"
severity: CRITICAL,HIGH
severity: CRITICAL
trivyignores: .trivyignore.yaml

- name: Trivy scan (high — warn only)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
continue-on-error: true
with:
image-ref: ${{ steps.scan-ref.outputs.ref }}
format: table
exit-code: "0"
severity: HIGH
trivyignores: .trivyignore.yaml

- name: Grype scan
uses: anchore/scan-action@1638637db639e0ade3258b51db49a9a137574c3e # v6
with:
image: ${{ steps.scan-ref.outputs.ref }}
fail-build: true
severity-cutoff: high
severity-cutoff: critical
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

.grype.yaml is added in this PR, but the Grype scan step doesn’t explicitly reference it (no config/args pointing to .grype.yaml). If anchore/scan-action doesn’t automatically discover repo-local config in its execution environment, the CVE ignore won’t apply and the job can still fail on CVE-2026-22184. Consider passing the config explicitly (or adding a note/assertion in the workflow logs) so it’s unambiguous that Grype is using the intended ignore list.

Suggested change
severity-cutoff: critical
severity-cutoff: critical
grype-config: .grype.yaml

Copilot uses AI. Check for mistakes.
config: .grype.yaml

# Push only after both scans pass — prevents publishing vulnerable images.
# Push only after scans pass — prevents publishing vulnerable images.
# NOTE: Separate build invocation; GHA cache ensures deterministic layers,
# but manifest digest differs due to SBOM + provenance attestation layers.
- name: Push image
Expand Down
8 changes: 8 additions & 0 deletions .grype.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Grype configuration — CVE ignore list
# Kept in sync with .trivyignore.yaml.

ignore:
- vulnerability: CVE-2026-22184
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.

critical

There appears to be a typo in the CVE identifier. Based on the context and the links provided in the PR description, the correct identifier should be CVE-2022-37434, not CVE-2026-22184. With the current typo, Grype will not ignore the intended vulnerability, and the build may continue to fail.

  - vulnerability: CVE-2022-37434

reason: >-
Disputed zlib vulnerability affecting only the untgz demo utility
in contrib/, not core zlib. Upstream disputes CVE validity.
11 changes: 11 additions & 0 deletions .trivyignore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Trivy CVE ignore list — structured YAML format

vulnerabilities:
- id: CVE-2026-22184
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.

critical

There seems to be a typo in the CVE identifier. The correct identifier for the disputed zlib vulnerability is CVE-2022-37434, not CVE-2026-22184. This typo will prevent Trivy from ignoring the vulnerability as intended.

  - id: CVE-2022-37434

statement: >-
Disputed zlib vulnerability affecting only the untgz demo utility
in contrib/, not core zlib compression. Our images do not ship or
invoke untgz. Upstream disputes CVE validity:
https://github.com/madler/zlib/issues/1148
nginx-unprivileged maintainer closed as not-zlib:
https://github.com/nginx/docker-nginx-unprivileged/issues/381
Comment on lines +4 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No expiry date on CVE suppression

Trivy's structured YAML ignore format supports an expiry-date field. Without it, this entry will silently suppress CVE-2026-22184 indefinitely — even after Alpine rebuilds its base image with a patched zlib. If the patch lands before the ignore entry is manually reviewed, future scans would still mask it with no alert.

Consider adding an expiry date (e.g. 90 days out) so the entry automatically becomes actionable if the upstream situation hasn't resolved by then:

Suggested change
- id: CVE-2026-22184
statement: >-
Disputed zlib vulnerability affecting only the untgz demo utility
in contrib/, not core zlib compression. Our images do not ship or
invoke untgz. Upstream disputes CVE validity:
https://github.com/madler/zlib/issues/1148
nginx-unprivileged maintainer closed as not-zlib:
https://github.com/nginx/docker-nginx-unprivileged/issues/381
vulnerabilities:
- id: CVE-2026-22184
expiry-date: "2026-06-10"
statement: >-
Disputed zlib vulnerability affecting only the untgz demo utility
in contrib/, not core zlib compression. Our images do not ship or
invoke untgz. Upstream disputes CVE validity:
https://github.com/madler/zlib/issues/1148
nginx-unprivileged maintainer closed as not-zlib:
https://github.com/nginx/docker-nginx-unprivileged/issues/381
Prompt To Fix With AI
This is a comment left during a code review.
Path: .trivyignore.yaml
Line: 4-11

Comment:
**No expiry date on CVE suppression**

Trivy's structured YAML ignore format supports an `expiry-date` field. Without it, this entry will silently suppress CVE-2026-22184 **indefinitely** — even after Alpine rebuilds its base image with a patched zlib. If the patch lands before the ignore entry is manually reviewed, future scans would still mask it with no alert.

Consider adding an expiry date (e.g. 90 days out) so the entry automatically becomes actionable if the upstream situation hasn't resolved by then:

```suggestion
vulnerabilities:
  - id: CVE-2026-22184
    expiry-date: "2026-06-10"
    statement: >-
      Disputed zlib vulnerability affecting only the untgz demo utility
      in contrib/, not core zlib compression. Our images do not ship or
      invoke untgz. Upstream disputes CVE validity:
      https://github.com/madler/zlib/issues/1148
      nginx-unprivileged maintainer closed as not-zlib:
      https://github.com/nginx/docker-nginx-unprivileged/issues/381
```

How can I resolve this? If you propose a fix, please make it concise.

2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ src/ai_company/
## CI

- **Jobs**: lint (ruff) + type-check (mypy src/ tests/) + test (pytest + coverage) run in parallel → ci-pass (gate)
- **Docker**: `.github/workflows/docker.yml` — builds backend + web images, pushes to GHCR, runs Trivy + Grype scans, signs with cosign. Triggers on push to main and version tags (`v*`).
- **Docker**: `.github/workflows/docker.yml` — builds backend + web images, pushes to GHCR, signs with cosign. Scans: Trivy (CRITICAL = hard fail, HIGH = warn-only) + Grype (critical cutoff). CVE triage via `.trivyignore.yaml` and `.grype.yaml`. Images only pushed after scans pass. Triggers on push to main and version tags (`v*`).
- **Matrix**: Python 3.14
- **Dependabot**: daily uv + github-actions + docker updates, grouped minor/patch, no auto-merge
- **Secret scanning**: gitleaks workflow on push/PR + weekly schedule
Expand Down
2 changes: 2 additions & 0 deletions DESIGN_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -3231,6 +3231,8 @@ ai-company/
│ ├── CONTRIBUTING.md
│ └── SECURITY.md
├── .dockerignore # Consolidated Docker build context exclusions
├── .grype.yaml # Grype CVE ignore list (synced with .trivyignore.yaml)
├── .trivyignore.yaml # Trivy CVE ignore list (structured YAML format)
├── DESIGN_SPEC.md # This document
├── README.md
├── pyproject.toml
Expand Down
Loading