Skip to content

STAC-25019 Preserve repository_url qualifier on OCI PURLs#16

Merged
LouisLotter merged 3 commits into
mainfrom
fix-reports
Jun 18, 2026
Merged

STAC-25019 Preserve repository_url qualifier on OCI PURLs#16
LouisLotter merged 3 commits into
mainfrom
fix-reports

Conversation

@rb3ckers

Copy link
Copy Markdown
Contributor

Per the VEX Repository Specification, the repository_url qualifier must be retained in the id of OCI entries so Trivy can match them against the image PURL it generates at scan time. Without it, the index resolved but no statements matched and the listed CVEs kept showing as affected.

  • tools/build_index.py: keep the repository_url qualifier for pkg:oci/* PURLs while still stripping version and other qualifiers; fail fast if an OCI VEX file is missing the qualifier so the bug can't reappear silently.
  • pkg/oci/quay.io/stackstate/stackstate-k8s-agent/scan.openvex.json: add ?repository_url=quay.io/stackstate/stackstate-k8s-agent to all product @id fields (the target-allocator file already had it).
  • index.json: regenerated.

@rb3ckers rb3ckers requested a review from a team as a code owner June 18, 2026 10:19
Comment thread index.json
Comment thread tools/build_index.py Outdated
LouisLotter
LouisLotter previously approved these changes Jun 18, 2026
rb3ckers added 3 commits June 18, 2026 15:01
Per the VEX Repository Specification, the `repository_url` qualifier
must be retained in the `id` of OCI entries so Trivy can match them
against the image PURL it generates at scan time. Without it, the
index resolved but no statements matched and the listed CVEs kept
showing as affected.

- tools/build_index.py: keep the `repository_url` qualifier for
  pkg:oci/* PURLs while still stripping version and other qualifiers;
  fail fast if an OCI VEX file is missing the qualifier so the bug
  can't reappear silently.
- pkg/oci/quay.io/stackstate/stackstate-k8s-agent/scan.openvex.json:
  add `?repository_url=quay.io/stackstate/stackstate-k8s-agent` to all
  product @id fields (the target-allocator file already had it).
- The repository_url part must be URL encoded, otherwise trivy will not
  match it in the index.
- index.json: regenerated.
Reviewer pointed out that the previous guard preserved repository_url
but still accepted unencoded values (repository_url=quay.io/ns/foo) and
left #subpath attached to qualifier strings, contrary to the docstring.

Replace the ad-hoc string splits with a small PURL parser that:

- Strips subpath (#...) before qualifiers and version, per the PURL
  grammar (pkg:type/namespace/name@version?qualifiers#subpath).
- Splits qualifiers into a key/value map, requiring lowercase ASCII
  qualifier keys and rejecting malformed key=value pairs.
- Rejects qualifier values that are not fully percent-encoded per RFC
  3986 (decoded-then-re-encoded with safe="" must match the input,
  case insensitively). For OCI repository_url this forces '/' to %2F
  and ':' on non-default ports to %3A so Trivy gets a single canonical
  match key.
- Continues to require repository_url on pkg:oci/* and now also fails
  fast on an empty value.

Smoke-tested the parser against encoded/unencoded/missing/empty/
malformed-key/subpath inputs; all six rejection paths fire and the
two pass paths produce the expected canonical id.

Regenerated index.json (no functional change — both OCI entries were
already percent-encoded in their VEX files).
The existing Lane 2 statements only carry the quay.io/stackstate
product identity, so scans of the Rancher-distribution copies under
registry.rancher.com/suse-observability/* still miss them. Per
CONTRIBUTING.md, Lane 2 must list one product entry per distribution
registry — typically both Quay and the Rancher-registry copy.

For each statement in both Lane 2 files, add a sibling product entry
with @id pkg:oci/<image>?repository_url=registry.rancher.com%2F\
suse-observability%2F<image> and the same subcomponent. Done in the
existing quay-keyed file using the CONTRIBUTING-endorsed "single
file listing both in products" pattern, so the reasoning stays in
one place.

- opentelemetry-target-allocator: 5 statements x +1 product (Docker
  Engine docker/docker server-side CVEs, not in execute path).
- stackstate-k8s-agent: 13 statements x +1 product (embedded
  CPython 3.13.13 stdlib CVEs).

Regenerated index.json: now 5 entries (Maven plus both registry
copies of each OCI image). The two Rancher entries reuse the
quay-keyed file path, which build_index.py already supports.
@LouisLotter LouisLotter merged commit d5e9707 into main Jun 18, 2026
1 check passed
@LouisLotter LouisLotter deleted the fix-reports branch June 18, 2026 13:33
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.

3 participants