Skip to content

Acquire: persist mirror history to skip re-synchronizing already-mirrored (and promoted) digests #157

Description

@toddysm

Problem

The mirror action (mirror-image / _mirror-image.yml) decides idempotency by comparing the source manifest digest with the destination (quarantine/<image>:<tag>) digest. It copies whenever they differ or the destination is absent.

This is stateless. Once an image is promoted out of quarantine, the promotion workflow deletes the tag from quarantine — and because GHCR deletes the whole package when the last tagged version is removed, the quarantine/<image> repo disappears. On the next scheduled mirror run the destination is absent, so the digest comparison mismatches and the already-processed, already-promoted digest is re-synchronized into quarantine. The image then loops back through the pipeline.

Goal

Give the mirror a durable memory of what it has already synchronized so a digest that was mirrored once is not mirrored again, even after it has been promoted and deleted from quarantine.

Proposed approach

Store a mirror-history OCI artifact in each synchronized repo (ghcr.io/<owner>/quarantine/<image>), under a reserved tag mirror-history. It is a small, append-only JSON log (one entry per synchronized source digest, keyed by source tag) wrapped as an OCI artifact. Because it is a separate tag, it survives image-tag deletion during promotion — and, as a bonus, keeps the quarantine package alive so promotion no longer hits the "cannot delete the last tagged version" edge case.

The mirror flow gains a step: before copying, read the history artifact; if the resolved source digest for that source tag is already recorded, skip the copy (unless force). After a successful copy (or a force run), append the digest to the history and push the updated artifact.

Decisions (agreed)

  • Location: colocated in quarantine/<image>, reserved tag mirror-history.
  • History key: source manifest digest, scoped per source tag.
  • force: bypasses the history check and still records the digest.
  • Retention: append-only, unbounded.

Scope

Design first. A design doc will be added under docs/architecture/acquire/, reviewed, then broken into child work items before implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    acquireRelated to the Acquire stagefeatureNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions