Skip to content

fix: adds support for OCI images with embedded attestations#760

Draft
pecodez wants to merge 1 commit intomainfrom
fix/oci-attestation-support
Draft

fix: adds support for OCI images with embedded attestations#760
pecodez wants to merge 1 commit intomainfrom
fix/oci-attestation-support

Conversation

@pecodez
Copy link
Copy Markdown
Contributor

@pecodez pecodez commented Feb 25, 2026

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

What does this PR do?

Adds fix for OCI archive extraction deadlock on images with attestation blobs

Problem

OCI archives produced by Docker Desktop with the containerd snapshotter (Docker Engine 25+) can include in-toto attestation blobs (SPDX SBOMs, SLSA provenance) alongside standard image content. These blobs are large JSON files stored in blobs/sha256/ that are not image layers, manifests, or configs.

The OCI archive extractor pipes each blob to two consumers in parallel via PassThrough streams: streamToJson (for JSON classification) and extractImageLayer (for layer extraction). When extractImageLayer rejects on a non-layer blob (e.g., "Invalid tar header"), the PassThrough stream is left unconsumed. For blobs exceeding the PassThrough's 16KB internal buffer, the unconsumed stream applies backpressure to the source, which pauses data flow to the jsonStream consumer. streamToJson stalls waiting for data that will never arrive. The Promise.all never resolves, and the process hangs silently.

Changes

lib/extractor/oci-archive/layer.ts

Added .destroy() calls on PassThrough streams when their consumer rejects. Destroying the PassThrough unpipes it from the source stream, releasing backpressure and allowing the other consumer to complete.

lib/extractor/decompress-maybe.ts

  • Wrapped gzipStream.write() calls in try-catch blocks to propagate synchronous errors via the transform callback instead of crashing.
  • Added gzipStream.once("error", ...) handler in the flush method alongside the existing "end" handler, preventing the transform from hanging if gzip errors during finalization.
  • Removed async from flush (not needed, was masking the callback pattern).

test/fixtures/oci-archives/oci-with-attestations.tar (new)

OCI archive fixture containing attestation blobs. The SPDX blob is deliberately sized above the threshold that triggers the deadlock without the fix.

test/lib/extractor/oci-with-attestations.spec.ts (new)

Five tests covering OCI extraction with attestation blobs present: layer extraction, fallback path, platform detection, rootfs diff IDs, and layer content extraction via extract actions.

How should this be manually tested?

Detected issue in eclipse-temurin:17-jdk-alpine, run

snyk container test eclipse-temurin:17-jdk-alpine --debug

You should see the scanner exit, no report and the logs should state no layers were detected.

Run the same test against this branch and the results are returned as expected.

@pecodez pecodez force-pushed the fix/oci-attestation-support branch from 987ebfb to c3ae26e Compare February 25, 2026 18:58
@pecodez pecodez force-pushed the fix/oci-attestation-support branch from c3ae26e to 09097f4 Compare February 25, 2026 19:16
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