Skip to content

Commit

Permalink
containertool: Use epoch date in image metadata (#38)
Browse files Browse the repository at this point in the history
Motivation
----------

The registry is a content-addressable store in which objects are
identified by their hashes. Many objects, such as image manifests,
contain timestamp fields. A difference in a timestamp field will cause
otherwise identical objects to have different hashes, causing a variety
of problems:

* an image cannot be verified by rebuilding it from the same original
parts and comparing the result
* the registry cannot completely deduplicate two images with almost
identical contents because their hashes do not match, wasting storage
and network bandwidth (some block-level deduplication may still be
possible, but clients which already have one image will have to pull the
other in its entirety)

These problems can be avoided by setting timestamp fields to fixed
values, often the Unix epoch:
https://reproducible-builds.org/docs/source-date-epoch/

Modifications
-------------

Set the overall image manifest timestamp and the timestamp used in the
image history log to the Unix epoch.

`containertool` already sets file modification times to the epoch when
creating image layers.

Result
------

An image packaging the same executable will have the same hash when
built at different times on the same machine or different machines.

Test Plan
---------

* All existing tests, including end to end tests, continue to pass.
* Manually verified that repeated builds produces images with identical
hashes.
  • Loading branch information
euanh authored Dec 6, 2024
1 parent bfdab0e commit 13702bc
Showing 1 changed file with 3 additions and 3 deletions.
6 changes: 3 additions & 3 deletions Sources/containertool/containertool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ enum AllowHTTP: String, ExpressibleByArgument, CaseIterable { case source, desti

// MARK: Create the application configuration

let now = Date.now.ISO8601Format()
let timestamp = Date(timeIntervalSince1970: 0).ISO8601Format()

// Inherit the configuration of the base image - UID, GID, environment etc -
// and override the entrypoint.
Expand All @@ -154,7 +154,7 @@ enum AllowHTTP: String, ExpressibleByArgument, CaseIterable { case source, desti
inherited_config.WorkingDir = "/"

let configuration = ImageConfiguration(
created: now,
created: timestamp,
architecture: architecture,
os: os,
config: inherited_config,
Expand All @@ -167,7 +167,7 @@ enum AllowHTTP: String, ExpressibleByArgument, CaseIterable { case source, desti
digest(of: tardiff)
] + baseimage_config.rootfs.diff_ids
),
history: [.init(created: now, created_by: "containertool")]
history: [.init(created: timestamp, created_by: "containertool")]
)

let config_blob = try await destination.putImageConfiguration(
Expand Down

0 comments on commit 13702bc

Please sign in to comment.