Skip to content

feat: fall back to OCI labels for base image detection when Dockerfile is unavailable#789

Draft
parker-snyk wants to merge 3 commits intomainfrom
CN-1041-oci-base-image-fallback-detection
Draft

feat: fall back to OCI labels for base image detection when Dockerfile is unavailable#789
parker-snyk wants to merge 3 commits intomainfrom
CN-1041-oci-base-image-fallback-detection

Conversation

@parker-snyk
Copy link
Copy Markdown
Contributor

@parker-snyk parker-snyk commented Apr 9, 2026

  • Ready for review
  • Follows CONTRIBUTING rules
  • Reviewed by Snyk internal team

What does this PR do?

When Snyk scans an image without a Dockerfile (or with a Dockerfile that has no FROM), the base image has historically been undetectable — causing Snyk to skip base image remediation advice entirely.

This PR adds a fallback: after Dockerfile analysis, if baseImage is still unset, analyzeStatically checks the image's OCI standard labels:

  1. org.opencontainers.image.base.name (preferred — human-readable tag, e.g. alpine:latest)
  2. org.opencontainers.image.base.digest (fallback — content-addressed digest)

If either label is present, its value is used as the base image. Dockerfile-derived values always take precedence — this only activates when no base image could be determined from the Dockerfile.

Where should the reviewer start?

lib/static.ts — the fallback logic is a small addition after the existing Dockerfile analysis block.

Then test/lib/static.spec.ts for the unit tests, and test/system/static.spec.ts for the end-to-end system test.

How should this be manually tested?

  1. Load the test fixture image into Docker:
    docker load < test/fixtures/docker-archives/docker-save/oci-labels.tar
  2. Run the plugin against the image using the empty Dockerfile fixture:
    npx ts-node -e "
    const plugin = require('./lib');
    plugin.scan({
      path: 'docker-archive:test/fixtures/docker-archives/docker-save/oci-labels.tar',
      file: 'test/fixtures/dockerfiles/empty-dockerfile',
    }).then(r => console.log(JSON.stringify(r.scanResults[0].facts.find(f => f.type === 'dockerfileAnalysis'), null, 2)));
    "
  3. Verify that dockerfileAnalysis.baseImage is "alpine:latest" in the output.

Without this change, baseImage would be undefined.

Any background context you want to provide?

Many modern third-party images (Chainguard, Bitnami, Red Hat UBI, distroless, official Docker Hub images) include OCI base image labels as part of their build process. The OCI Image Spec defines org.opencontainers.image.base.name and org.opencontainers.image.base.digest specifically for this purpose.

Without this fallback, users auditing pre-built images without access to the original Dockerfile receive no base image remediation advice — even when the image itself carries the necessary metadata.

What are the relevant tickets?

CN-1041

Screenshots

N/A

Additional questions

The snapshot updates in this PR are due to image layer hashes changing as the underlying test images were refreshed from their registries. The logic changes themselves are isolated to lib/static.ts.

@parker-snyk parker-snyk requested a review from a team as a code owner April 9, 2026 21:03
@parker-snyk parker-snyk requested a review from d3vco April 9, 2026 21:03
@parker-snyk parker-snyk marked this pull request as draft April 9, 2026 21:04
@snyk-pr-review-bot
Copy link
Copy Markdown

PR Reviewer Guide 🔍

🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Broken Fallback Logic 🔴 [critical]

The fallback logic for base image detection is gated by if (baseImageLabel && dockerfileAnalysis). However, the outer if condition explicitly allows for !dockerfileAnalysis (line 62). If no Dockerfile was provided, dockerfileAnalysis is undefined, causing the code to skip the assignment of baseImageLabel. This prevents the fallback from working in the primary scenario it was designed for: scans where a Dockerfile is entirely unavailable.

if (
  (!dockerfileAnalysis || !dockerfileAnalysis.baseImage) &&
  staticAnalysis.imageLabels
) {
  const baseImageLabel =
    staticAnalysis.imageLabels["org.opencontainers.image.base.name"] ||
    staticAnalysis.imageLabels["org.opencontainers.image.base.digest"];
  if (baseImageLabel && dockerfileAnalysis) {
    dockerfileAnalysis.baseImage = baseImageLabel;
  }
}
📚 Repository Context Analyzed

This review considered 6 relevant code sections from 5 files (average relevance: 0.92)

fix: fix snapshots

fix: restore snapshots and fix static.spec.ts corruption from containerd-on run

The previous LLM session regenerated snapshots with containerd enabled,
which produced incorrect/truncated dep graphs. This restores the
rpm-transitive-dependencies snapshot to match main (full transitive dep
graph), and removes the duplicate OCI label test block that was
accidentally injected inside the opensuse test in static.spec.ts,
causing a TypeScript parse error.
@parker-snyk parker-snyk force-pushed the CN-1041-oci-base-image-fallback-detection branch from 8fc29ec to c17f243 Compare April 9, 2026 21:18
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.

1 participant