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
17 changes: 17 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ jobs:
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-checksums: dist/checksums.txt
id: attest
- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
with:
cosign-release: v3.1.3
# Attach a keyless signature of checksums.txt and the SLSA provenance bundle
# to the GitHub release so both can be verified from the release page alone.
- name: Sign checksums and attach signature and provenance
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
BUNDLE: ${{ steps.attest.outputs.bundle-path }}
run: |
cosign sign-blob --yes --bundle dist/checksums.txt.sigstore.json dist/checksums.txt
cp "$BUNDLE" "dist/notation-aws-verifier_${TAG#v}.intoto.jsonl"
gh release upload "$TAG" --repo "$GITHUB_REPOSITORY" --clobber \
dist/checksums.txt.sigstore.json \
"dist/notation-aws-verifier_${TAG#v}.intoto.jsonl"

image:
name: image
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Security

- Base images are pinned by digest directly in `FROM`, so Dependabot keeps tag and digest current.
- Releases attach a keyless cosign signature of `checksums.txt` and the SLSA provenance bundle.
- Added a fuzz test for `/checkimages` request parsing.
- Added `osv-scanner.toml` documenting advisories that do not affect this service.

## [1.0.0] - 2026-09-24

First release of `notation-aws-verifier`, forked from
Expand Down
10 changes: 4 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# syntax=docker/dockerfile:1
ARG BUILDER_IMAGE="golang:1.26.8-alpine3.24"
# gcr.io/distroless/static:nonroot, pinned by digest (multi-arch index).
ARG BASE_IMAGE="gcr.io/distroless/static:nonroot@sha256:e2e927ec666bae08560abb3c55d0659eceabb657f56b6782ab500a9fc7f555e3"

FROM --platform=$BUILDPLATFORM $BUILDER_IMAGE AS builder
# Base images are pinned by multi-arch index digest directly in FROM so that
# Dependabot can bump tag and digest together.
FROM --platform=$BUILDPLATFORM golang:1.26.8-alpine3.24@sha256:8ac98ca534ac3f51e1f420a1dd2c15e74c75cfa0f23f3ad27eb5d7236c349a0c AS builder

ARG TARGETOS
ARG TARGETARCH
Expand Down Expand Up @@ -37,7 +35,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \
-ldflags="-s -w -X main.version=${VERSION}" \
-o /out/notation-aws-verifier .

FROM $BASE_IMAGE
FROM gcr.io/distroless/static:nonroot@sha256:e2e927ec666bae08560abb3c55d0659eceabb657f56b6782ab500a9fc7f555e3

ARG VERSION=dev
LABEL org.opencontainers.image.title="notation-aws-verifier" \
Expand Down
12 changes: 12 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,15 @@ Verify a downloaded release binary archive:
gh attestation verify notation-aws-verifier_1.0.0_linux_amd64.tar.gz \
--repo krax1337/notation-aws-verifier
```

Each release attaches `notation-aws-verifier_<version>.intoto.jsonl` (the SLSA
provenance bundle, usable with `gh attestation verify --bundle`). Releases after
v1.0.0 also attach `checksums.txt.sigstore.json`, a keyless cosign signature of
`checksums.txt`, so archives can be verified offline from the release page:

```sh
cosign verify-blob checksums.txt --bundle checksums.txt.sigstore.json \
--certificate-identity-regexp '^https://github.com/krax1337/notation-aws-verifier/.github/workflows/release.yaml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum --ignore-missing -c checksums.txt
```
48 changes: 48 additions & 0 deletions internal/verifier/request_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package verifier

import (
"encoding/json"
"testing"

"github.com/krax1337/notation-aws-verifier/internal/types"
)

// FuzzProcessRequestData feeds arbitrary /checkimages request bodies through the
// same decode and validation path as the HTTP handler. The body is supplied by
// the caller (a Kyverno policy), so malformed input must be rejected with an
// error, never a panic, and an accepted request must carry at least one image.
func FuzzProcessRequestData(f *testing.F) {
seeds := []string{
`{}`,
`{"images":{}}`,
`{"images":{"containers":{"app":{"registry":"123456789012.dkr.ecr.us-west-2.amazonaws.com","path":"demo","name":"demo","tag":"v1","jsonPointer":"/spec/containers/0/image"}}}}`,
`{"images":{"initContainers":{"init":{"registry":"public.ecr.aws","path":"a/b","name":"b","digest":"sha256:00"}}},"trustPolicy":"tp-default"}`,
`{"images":{"containers":{"a":{}}},"attestations":[{"imageReference":"*","type":[{"name":"sbom/cyclone-dx","conditions":{"all":[{"key":"{{a}}","operator":"Equals","value":"1"}]}}]}]}`,
`{"images":{"containers":{"a":{}}},"attestations":[{"imageReference":"","type":[]}]}`,
`{"images":{"containers":{"a":{}}},"attestations":[{"imageReference":"*","type":[{"name":"x","conditions":{"any":[{"operator":"Equals"}]}}]}]}`,
`{"images":null,"attestations":null,"imageReferences":["*"],"insecure":true}`,
}
for _, s := range seeds {
f.Add([]byte(s))
}

f.Fuzz(func(t *testing.T, body []byte) {
var req types.RequestData
if err := json.Unmarshal(body, &req); err != nil {
return
}
got, err := processRequestData(&req)
if err != nil {
if got != nil {
t.Fatalf("non-nil request returned with error %v", err)
}
return
}
if got == nil {
t.Fatal("nil request returned without error")
}
if len(got.Images.Containers)+len(got.Images.InitContainers)+len(got.Images.EphemeralContainers) == 0 {
t.Fatal("request without images was accepted")
}
})
}
40 changes: 40 additions & 0 deletions osv-scanner.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Advisories reported by OSV-based scanners (osv-scanner, OpenSSF Scorecard) that
# do not affect this service. govulncheck, which checks reachability, reports none
# of them as called; see .govulncheck-ignore and .trivyignore.yaml for the same
# decisions in CI. Review on every dependency bump; remove entries once fixed.

# github.com/kyverno/kyverno: module-wide advisories without a fixed version.
# They concern the Kyverno admission controller (apiCall, service calls, policy
# context loading). This service only imports condition evaluation, JMESPath and
# image helpers and never makes Kyverno service or API calls.
[[IgnoredVulns]]
id = "GO-2025-3615"
reason = "Kyverno SSRF via service calls; not used, no fixed version"

[[IgnoredVulns]]
id = "GO-2026-5337"
reason = "Kyverno cross-namespace read in policy context; not used, no fixed version"

[[IgnoredVulns]]
id = "GO-2026-5594"
reason = "Kyverno apiCall SSRF; apiCall not used, no fixed version"

# Pulled in transitively by Kyverno's API package (via cosign CLI options).
# The ACR credential helper is linked but never invoked: registry credentials come
# from the ECR helper and image pull secrets only. No fixed version exists.
[[IgnoredVulns]]
id = "GO-2026-6225"
reason = "docker-credential-acr-env credential leakage; ACR helper never invoked, no fixed version"

# Advisory against the deprecated golang.org/x/crypto/openpgp package as a whole.
# Only x/crypto/cryptobyte and other packages are used; openpgp is not imported.
[[IgnoredVulns]]
id = "GO-2026-5932"
reason = "x/crypto/openpgp unmaintained; openpgp is not imported"

# gRPC-Go server panic on missing :authority/Host. grpc is indirect and this
# binary runs no gRPC server. Fixed only in a 1.85.0 development build.
[[IgnoredVulns]]
id = "GO-2026-6443"
ignoreUntil = 2026-12-31
reason = "grpc server panic; no gRPC server runs; fix only in 1.85.0-dev"
Loading