Skip to content

Fix DiffID computation to use uncompressed layer digest#587

Open
cluster2600 wants to merge 4 commits intoapple:mainfrom
cluster2600:fix/diffid-computation
Open

Fix DiffID computation to use uncompressed layer digest#587
cluster2600 wants to merge 4 commits intoapple:mainfrom
cluster2600:fix/diffid-computation

Conversation

@cluster2600
Copy link
Contributor

@cluster2600 cluster2600 commented Mar 17, 2026

Summary

  • Fix InitImage.create() to compute DiffIDs from the uncompressed layer content per the OCI Image Specification
  • Add ContentWriter.diffID(of:) which decompresses gzip data and computes SHA256 of the raw content
  • The previous implementation incorrectly used the digest of the compressed gzip layer as the DiffID

Changes

  • ContentWriter.swift: Add diffID(of:) static method with gzip header parsing and streaming decompression via Apple's Compression framework
  • InitImage.swift: Replace compressed digest with uncompressed digest for Rootfs.diffIDs
  • DiffIDTests.swift: 6 tests covering correctness, determinism, error handling, large layers, and output format

Context

Resolves the TODO at InitImage.swift:56:

// TODO: compute and fill in the correct diffID for the above layer
// We currently put in the sha of the fully compressed layer, this needs to be replaced with
// the sha of the uncompressed layer.

Test plan

  • All 6 new DiffID tests pass
  • Full test suite passes (392 tests, 0 failures)
  • Verified DiffID output matches SHA256 of known uncompressed content
  • Verified error handling for non-gzip, empty, and truncated inputs

cluster2600 and others added 4 commits March 5, 2026 09:11
Resolves apple#467.

Previously, any arbitrary string could be passed as a nameserver in
DNS configuration, which would silently result in an invalid
/etc/resolv.conf inside the container.

This change adds a DNS.validate() method that ensures every nameserver
string is a valid IPv4 or IPv6 address (using the existing
ContainerizationExtras parsers). The method is called from
Vminitd.configureDNS() before applying the configuration.

Tests added to DNSTests.swift covering valid IPv4, IPv6, mixed, empty
nameserver lists, and invalid hostname/address rejection.

Signed-off-by: Maxime Grenu <maxime.grenu@gmail.com>
The validate() method uses ContainerizationError which lives in its own
module and must be explicitly imported.

Signed-off-by: Maxime Grenu <maxime.grenu@gmail.com>
The OCI Image Specification requires DiffIDs to be the SHA256 digest
of the uncompressed layer content. InitImage.create() was incorrectly
using the digest of the compressed gzip layer.

Add ContentWriter.diffID(of:) which decompresses the gzip stream and
computes SHA256 of the raw content. The implementation parses the gzip
header (handling FEXTRA, FNAME, FCOMMENT, FHCRC flags) and feeds the
raw deflate stream to Apple's Compression framework.

Signed-off-by: Maxime Grenu <maxime@cluster2600.com>
Signed-off-by: Maxime Grenu <maxime.grenu@gmail.com>
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