Skip to content

Commit 9352ee9

Browse files
committed
c: set up CI pipeline
1 parent 5cabfc0 commit 9352ee9

5 files changed

Lines changed: 192 additions & 22 deletions

File tree

.github/workflows/docker.yml

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,45 @@ on:
55
branches: [main]
66
pull_request: {}
77

8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
812
jobs:
913
build:
10-
runs-on: ubuntu-24.04
14+
name: build (${{ matrix.platform }})
15+
runs-on: ubuntu-24.04${{ matrix.platform == 'linux/arm64' && '-arm' || ''}}
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
platform:
20+
- linux/amd64
21+
- linux/arm64
1122
permissions:
1223
id-token: write
1324
packages: write
1425
contents: read
1526
attestations: write
1627
env:
17-
REGISTRY: ghcr.io
18-
IMAGE_NAME: ${{ github.repository }}
28+
PLATFORM: ${{ matrix.platform }}
1929

2030
steps:
2131
- name: Checkout
2232
uses: actions/checkout@v5
23-
- name: Set up QEMU
24-
id: qemu
25-
uses: docker/setup-qemu-action@v3
33+
- name: Build time variables
34+
run: |-
35+
echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >>"$GITHUB_ENV"
36+
echo "TOR_VERSION=$(tr -d '\n' <VERSION)" >>"$GITHUB_ENV"
37+
- name: Skip if already published
38+
env:
39+
FULL_DOCKER_IMAGE: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TOR_VERSION }}"
40+
run: |-
41+
echo "Checking if $FULL_DOCKER_IMAGE exists ..."
42+
if docker manifest inspect "$FULL_DOCKER_IMAGE" &>/dev/null; then
43+
echo "$FULL_DOCKER_IMAGE already exists, skipping build"
44+
gh run cancel "$GITHUB_RUN_ID"
45+
exit 0
46+
fi
2647
- name: Set up Docker Buildx
2748
uses: docker/setup-buildx-action@v3
2849
- name: Login to GitHub Container Registry
@@ -31,27 +52,85 @@ jobs:
3152
registry: ${{ env.REGISTRY }}
3253
username: ${{ github.actor }}
3354
password: ${{ secrets.GITHUB_TOKEN }}
34-
- run: echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >>"$GITHUB_ENV"
35-
- run: echo "TOR_VERSION=$(tr -d '\n' <VERSION) >>"$GITHUB_ENV"
55+
- name: Download Gentoo
56+
run: ./scripts/fetch-gentoo.sh "${PLATFORM##*/}"
57+
- name: Docker meta
58+
id: meta
59+
uses: docker/metadata-action@v5
60+
with:
61+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
3662
- name: Build and push image
3763
uses: docker/build-push-action@v6
38-
id: push
64+
id: build
3965
env:
4066
SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
4167
with:
4268
context: .
43-
outputs: type=registry,rewrite-timestamp=true
4469
sbom: true
45-
push: ${{ github.event_name != 'pull_request' }}
46-
provenance: "max"
70+
provenance: mode=max
71+
labels: ${{ steps.meta.outputs.labels }}
4772
build-args: TOR_VERSION=${{ env.TOR_VERSION }}
48-
platforms: "linux/amd64,linux/arm64"
49-
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TOR_VERSION }}
73+
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
74+
outputs: type=image,rewrite-timestamp=true,push-by-digest=true,name-canonical=true,push=${{ github.event_name == 'push' }}
75+
- name: Export digest
76+
run: |-
77+
mkdir -p "${{ runner.temp }}/digests"
78+
digest="${{ steps.build.outputs.digest }}"
79+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
80+
- name: Escape platform (/ -> -)
81+
id: platform
82+
run: echo "escaped=${PLATFORM//\//-}" >"$GITHUB_OUTPUT"
83+
- name: Upload digest
84+
uses: actions/upload-artifact@v4
85+
with:
86+
name: digests-${{ steps.platform.outputs.escaped }}
87+
path: ${{ runner.temp }}/digests/*
88+
if-no-files-found: error
89+
retention-days: 1
90+
- name: Attest
91+
uses: actions/attest-build-provenance@v3
92+
id: attest
93+
if: ${{ github.event_name == 'push' }}
94+
with:
95+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
96+
subject-digest: ${{ steps.build.outputs.digest }}
97+
push-to-registry: true
98+
99+
merge:
100+
if: ${{ github.event_name == 'push' }}
101+
runs-on: ubuntu-24.04
102+
needs:
103+
- build
104+
steps:
105+
- name: Checkout
106+
uses: actions/checkout@v5
107+
- name: Build time variables
108+
run: |-
109+
echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >>"$GITHUB_ENV"
110+
echo "TOR_VERSION=$(tr -d '\n' <VERSION)" >>"$GITHUB_ENV"
111+
- name: Download digests
112+
uses: actions/download-artifact@v4
113+
with:
114+
path: ${{ runner.temp }}/digests
115+
pattern: digests-*
116+
merge-multiple: true
117+
- name: Set up Docker Buildx
118+
uses: docker/setup-buildx-action@v3
119+
- name: Create manifest
120+
id: manifest
121+
env:
122+
FULL_DOCKER_IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TOR_VERSION }}
123+
DOCKER_IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
124+
run: |-
125+
readarray -t digests < <(printf "$DOCKER_IMAGE@sha256:%s\n" *)
126+
docker buildx imagetools create -t "$FULL_DOCKER_IMAGE" "${digests[@]}"
127+
docker buildx imagetools inspect "$FULL_DOCKER_IMAGE"
128+
echo "digest=$(docker buildx imagetools inspect "$FULL_DOCKER_IMAGE" | grep "Digest:" | awk '{ print $2 }')" >"$GITHUB_OUTPUT"
50129
- name: Attest
51-
uses: actions/attest-build-provenance@v2
130+
uses: actions/attest-build-provenance@v3
52131
id: attest
53132
if: ${{ github.event_name == 'push' }}
54133
with:
55134
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
56-
subject-digest: ${{ steps.push.outputs.digest }}
135+
subject-digest: ${{ steps.manifest.outputs.digest }}
57136
push-to-registry: true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.gentoo-sources

Dockerfile

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
# syntax=docker/dockerfile:1
2-
FROM gentoo/portage:latest AS portage
3-
FROM gentoo/stage3:latest AS builder
2+
FROM scratch AS builder
3+
4+
# Automatically supplied by Docker
5+
ARG TARGETARCH
6+
7+
# Comes from ./scripts/fetch-gentoo.sh
8+
ADD ./.gentoo-sources/$TARGETARCH.tar /
49

510
# https://gitlab.torproject.org/tpo/core/tor/-/tags
611
ARG TOR_VERSION
712

8-
COPY --from=portage /var/db/repos/gentoo /var/db/repos/gentoo
13+
SHELL ["/usr/bin/bash", "-euo", "pipefail", "-c"]
914

15+
# Download latest portage sources
1016
RUN <<EOF
11-
set -euo pipefail
12-
17+
mkdir -p /var/db/repos/gentoo
18+
emerge-webrsync
19+
EOF
20+
21+
RUN <<EOF
1322
export MAKEOPTS="-j$(nproc)"
1423
export EMERGE_DEFAULT_OPTS="--jobs 2"
1524
export USE="${USE:-""} hardened zstd static-libs"
@@ -31,6 +40,6 @@ RUN <<EOF
3140
strip /usr/bin/tor
3241
EOF
3342

34-
FROM gcr.io/distroless/static-debian12:nonroot
43+
FROM scratch
3544
COPY --from=builder /usr/bin/tor /usr/bin/tor
3645
ENTRYPOINT ["/usr/bin/tor"]

renovate.json5

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11
{
2+
// Validate with:
3+
// npx --yes --package renovate -- renovate-config-validator --strict
24
$schema: "https://docs.renovatebot.com/renovate-schema.json",
35
extends: ["config:recommended"],
6+
customManagers: [
7+
{
8+
customType: "regex",
9+
managerFilePatterns: ["/^VERSION$/"],
10+
matchStrings: ["^(?<currentValue>.+)$"],
11+
datasourceTemplate: "gitlab-releases",
12+
depNameTemplate: "tpo/core/tor",
13+
registryUrlTemplate: "https://gitlab.torproject.org",
14+
extractVersionTemplate: "^tor-(?<version>.+)$",
15+
},
16+
],
417
}

scripts/fetch-gentoo.sh

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env bash
2+
# Downloads a Gentoo stage3 tarball and makes it available for a FROM
3+
# scratch Docker image to use.
4+
#
5+
# Usage: fetch-gentoo.sh <ARCH>
6+
#
7+
# ARCH: amd64, arm64
8+
9+
set -euo pipefail
10+
11+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12+
# curl https://qa-reports.gentoo.org/output/service-keys.gpg | sha512sum | awk '{ print $1 }'
13+
SIGNATURE_FILE_HASH="21d1c6ccd5c3e82ce4ec2fe4509e072bc1e47d4f16628274d2b508e2d6e111ed0b3b5f7f542ad29d4f58fc0ff475b0d423322de3cad54c0056bf774fed3dffb0"
14+
15+
info() {
16+
echo -e "\033[1;34m[INFO]\033[0m" "$@"
17+
}
18+
19+
20+
ARCH="${1:-}"
21+
if [[ -z "$ARCH" ]] || ! [[ "$ARCH" =~ ^(arm64|amd64)$ ]]; then
22+
echo "Usage: $(basename "$0") <ARCH>"
23+
echo
24+
echo " ARCH: amd64, arm64"
25+
exit
26+
fi
27+
28+
# Download the Gentoo signing keys, comparing them to the time of this
29+
# script's writing (avoids us having to vendor them).
30+
gentooKeys="$(mktemp)"
31+
wget -O "$gentooKeys" https://qa-reports.gentoo.org/output/service-keys.gpg
32+
if [[ "$(sha512sum "$gentooKeys" | awk '{ print $1 }')" != "$SIGNATURE_FILE_HASH" ]]; then
33+
echo "Gentoo signing keys did not match expected hash" >&2
34+
exit 1
35+
fi
36+
37+
export GNUPGHOME=$(mktemp -d)
38+
gpg --import "$gentooKeys"
39+
info "Imported Gentoo signing keys successfully"
40+
41+
DOWNLOAD_DIR=$(mktemp -d)
42+
43+
wget -q -O "$DOWNLOAD_DIR/latest-version.txt" \
44+
"https://distfiles.gentoo.org/releases/$ARCH/autobuilds/latest-stage3-$ARCH-openrc.txt"
45+
gpg --verify "$DOWNLOAD_DIR/latest-version.txt"
46+
47+
GENTOO_VERSION=$(grep "stage3-$ARCH-openrc" "$DOWNLOAD_DIR/latest-version.txt" | awk -F '/' '{ print $1 }')
48+
info "Using Gentoo stage3 snapshot: $GENTOO_VERSION"
49+
50+
TAR_PATH="$DOWNLOAD_DIR/gentoo-$ARCH.tar.xz"
51+
52+
info "Fetching gentoo archive (ARCH: $ARCH)"
53+
wget --progress=bar --show-progress -O "$TAR_PATH" \
54+
"https://distfiles.gentoo.org/releases/$ARCH/autobuilds/$GENTOO_VERSION/stage3-$ARCH-openrc-$GENTOO_VERSION.tar.xz"
55+
wget --progress=bar --show-progress -O "$TAR_PATH.asc" \
56+
"https://distfiles.gentoo.org/releases/$ARCH/autobuilds/$GENTOO_VERSION/stage3-$ARCH-openrc-$GENTOO_VERSION.tar.xz.asc"
57+
info "Download successfully"
58+
59+
gpg --verify "$TAR_PATH.asc"
60+
info "Successfully validated downloaded archive"
61+
62+
DECOMPRESSED_PATH="$SCRIPT_DIR/../.gentoo-sources/$ARCH.tar"
63+
mkdir -p "$(dirname "$DECOMPRESSED_PATH")"
64+
rm -f "$DECOMPRESSED_PATH" || true
65+
66+
info "Storing Gentoo tar at $DECOMPRESSED_PATH"
67+
xz --decompress --stdout "$TAR_PATH" >"$DECOMPRESSED_PATH"
68+
rm -f "$TAR_PATH"{,.asc}

0 commit comments

Comments
 (0)