1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
name: Mirror distroless images
# Keeps https://img.dieschoenewolke.de in step with gcr.io/distroless.
#
# The copying is done by zot's sync extension on the VPS, not by this job: the
# registry diffs digests itself, pulls only what changed, and can do so while
# the home Forgejo instance (and this runner) is down. This workflow is the
# auditor — it compares upstream and mirror digests, pull-verifies anything new,
# and only then writes a `synced-<repo>-<tag>-<digest12>` marker tag.
#
# That is the same "marker last" discipline as the Pureblog release pipeline:
# a marker exists only for a ref that was proven pullable by digest. A run that
# dies before the push leaves no marker, so the next run retries.
#
# gcr.io load: one anonymous token request per repo plus one manifest request
# per ref = 8 requests per run, every 6 hours. No per-request storm, no docker
# login, nothing that could hit an anonymous rate limit.
on:
schedule:
- cron: "17 */6 * * *"
workflow_dispatch:
inputs:
verify_all:
description: "Pull-verify every ref, not just new digests (1/0)"
required: false
default: "0"
type: string
concurrency:
group: distroless-mirror-sync
# Never cancel a run half way: a cancelled run could leave a tag pushed
# without the verification it claims. Runs are minutes apart anyway.
cancel-in-progress: false
jobs:
verify:
runs-on: docker-cli
timeout-minutes: 30
container:
image: docker:29-cli
env:
# shared by the verify and publish steps; a step-level env would not be
# visible to the next step
MARKERS_FILE: ${{ runner.temp }}/mirror-markers
steps:
- name: Install workflow tools
# nodejs is required by actions/checkout inside this image
run: apk add --no-cache bash curl git jq nodejs
- name: Check out the marker tags
uses: https://github.com/actions/checkout@v4
with:
fetch-depth: 0
- name: Compare upstream and mirror, verify, mark
env:
# docker:cli keeps the CLI in /usr/local/bin; the runner's DOCKER_HOST
# points at the daemon, so the pull goes over the public hostname and
# the real TLS/edge path.
VERIFY_PULL: ${{ inputs.verify_all == '1' && 'always' || 'new' }}
run: ./scripts/verify-mirror.sh
- name: Publish marker tags
run: |
set -eu
file="$MARKERS_FILE"
[ -s "$file" ] || { echo "no new markers"; exit 0; }
while read -r marker; do
[ -n "$marker" ] || continue
git push origin "refs/tags/$marker"
echo "marked $marker"
done <"$file"
|