Skip to content

Commit e61eee4

Browse files
authored
ci: pin runs-on to ubuntu-24.04 and actions by SHA (#184)
* ci(release): make the tag build image-only, with no GHCR or chart push Releases are source only, so a v* tag must not publish anything. job-release-image.yaml now builds the manager image from the pinned web ref and runs it read-only against the same health check the PR image CI proves, with no registry login and no image or chart push: the chart job is gone and the image build no longer logs in to GHCR, pushes, or tags latest. Refs #181 Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com> * ci: pin runs-on to ubuntu-24.04 and actions by SHA ubuntu-latest moves to Ubuntu 26 on 2026-10-19, which can break builds without warning. Every GitHub-hosted job now runs on ubuntu-24.04 (the arm64 runner is unchanged), and every third-party action is pinned by full commit SHA with a version comment. Actions still on the Node 20 runtime are bumped to their current SHA-pinned release (Node 24); actions already past Node 20 are pinned at their current major. Refs CryptOS-PKI/.github#28 Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com> --------- Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com> Co-authored-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
1 parent 13c1b8c commit e61eee4

14 files changed

Lines changed: 123 additions & 85 deletions

‎.github/workflows/action-lint.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ jobs:
2121
actionlint:
2222
name: 🧹 Actionlint
2323
if: github.event.pull_request.draft == false
24-
runs-on: ubuntu-latest
24+
runs-on: ubuntu-24.04
2525
timeout-minutes: 10
2626
steps:
2727
- name: 📥 Checkout
28-
uses: actions/checkout@v4
28+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
2929
# The pinned release binary, checked against the SHA-256 the release
3030
# publishes, instead of compiling actionlint@latest with Go on every run.
3131
# Update ACTIONLINT_SHA256 together with ACTIONLINT_VERSION (from the

‎.github/workflows/ci-go.yaml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
go:
3232
name: 🧪 Go CI (fmt, vet, lint, build, test)
3333
if: github.event.pull_request.draft == false
34-
runs-on: ubuntu-latest
34+
runs-on: ubuntu-24.04
3535
timeout-minutes: 15
3636
services:
3737
postgres:
@@ -50,10 +50,10 @@ jobs:
5050
MANAGER_TEST_DATABASE_URL: postgres://postgres:test@localhost:5432/postgres?sslmode=disable
5151
steps:
5252
- name: 📥 Checkout
53-
uses: actions/checkout@v6
53+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
5454

5555
- name: 🐹 Set up Go
56-
uses: actions/setup-go@v6
56+
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
5757
with:
5858
go-version-file: go.mod
5959
cache-dependency-path: go.sum

‎.github/workflows/ci-image.yaml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,29 @@ jobs:
3232
image:
3333
name: 🐳 Image CI (build, run read-only, health)
3434
if: github.event.pull_request.draft == false
35-
runs-on: ubuntu-latest
35+
runs-on: ubuntu-24.04
3636
timeout-minutes: 30
3737
env:
3838
IMAGE: manager:ci
3939
NET: fleet-ci
4040
steps:
4141
- name: 📥 Checkout manager
42-
uses: actions/checkout@v4
42+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
4343
with:
4444
path: manager
4545

4646
- name: 📥 Checkout web
47-
uses: actions/checkout@v4
47+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
4848
with:
4949
repository: CryptOS-PKI/cryptos-web
5050
ref: ${{ vars.WEB_RELEASE_REF || 'main' }}
5151
path: web
5252

5353
- name: 🛠️ Set up Docker Buildx
54-
uses: docker/setup-buildx-action@v3
54+
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
5555

5656
- name: 🏗️ Build (not pushed)
57-
uses: docker/build-push-action@v6
57+
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
5858
with:
5959
context: .
6060
file: manager/Dockerfile

‎.github/workflows/job-dco.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
dco:
2626
name: ✍️ DCO sign-off
2727
if: github.event.pull_request.draft == false
28-
runs-on: ubuntu-latest
28+
runs-on: ubuntu-24.04
2929
timeout-minutes: 5
3030
steps:
3131
- name: ✍️ Check every commit is signed off by its author

‎.github/workflows/job-golic.yaml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ jobs:
2020
golic:
2121
name: 🔏 License headers
2222
if: github.event.pull_request.draft == false
23-
runs-on: ubuntu-latest
23+
runs-on: ubuntu-24.04
2424
timeout-minutes: 10
2525
steps:
2626
- name: Checkout
27-
uses: actions/checkout@v6
27+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
2828
- name: Setup Go
29-
uses: actions/setup-go@v6
29+
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
3030
with:
3131
go-version: 'stable'
3232
- name: Install Task
33-
uses: arduino/setup-task@v2
33+
uses: arduino/setup-task@c0bc642852239c2689f73f4ea6459c29405f3c52 # v3.0.0
3434
with:
3535
version: 3.x
3636
# setup-task reads its token from this input, not env. Without it

‎.github/workflows/job-label-checker.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
github.event.pull_request.draft == false &&
4343
github.event.action != 'labeled' && github.event.action != 'unlabeled' &&
4444
github.event.pull_request.head.repo.full_name == github.repository
45-
runs-on: ubuntu-latest
45+
runs-on: ubuntu-24.04
4646
timeout-minutes: 10
4747
steps:
4848
# Map the conventional-commit prefix in the PR title to a categorizing
@@ -80,7 +80,7 @@ jobs:
8080
# Run even if autolabel was skipped/failed; the label may already be present
8181
# from the PR title or a maintainer. Drafts are still skipped.
8282
if: always() && github.event.pull_request.draft == false
83-
runs-on: ubuntu-latest
83+
runs-on: ubuntu-24.04
8484
timeout-minutes: 10
8585
permissions:
8686
pull-requests: read

‎.github/workflows/job-label-sync.yaml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ permissions:
1313
jobs:
1414
labeler:
1515
name: 🏷️ Sync labels
16-
runs-on: ubuntu-latest
16+
runs-on: ubuntu-24.04
1717
timeout-minutes: 10
1818
steps:
19-
- uses: actions/checkout@v4
20-
- uses: crazy-max/ghaction-github-labeler@v5
19+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20+
- uses: crazy-max/ghaction-github-labeler@548a7c3603594ec17c819e1239f281a3b801ab4d # v6.0.0
2121
with:
2222
yaml-file: .github/labels.yml
2323
skip-delete: false

‎.github/workflows/job-license-check-go.yaml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ jobs:
2222
go:
2323
name: ⚖️ Dependency licenses (Go)
2424
if: github.event.pull_request.draft == false
25-
runs-on: ubuntu-latest
25+
runs-on: ubuntu-24.04
2626
timeout-minutes: 15
2727
steps:
2828
- name: Checkout
29-
uses: actions/checkout@v4
29+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3030

3131
- name: Setup Go
32-
uses: actions/setup-go@v5
32+
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
3333
with:
3434
go-version: 'stable'
3535

‎.github/workflows/job-pr-checks.yaml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ jobs:
4040
checks:
4141
name: ✅ PR Checks
4242
if: github.event.pull_request.draft == false
43-
runs-on: ubuntu-latest
43+
runs-on: ubuntu-24.04
4444
timeout-minutes: 10
4545
steps:
4646
- name: 📝 PR Title
47-
uses: amannn/action-semantic-pull-request@v5
47+
uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
4848
env:
4949
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5050

@@ -72,7 +72,7 @@ jobs:
7272
- name: Checkout
7373
id: checkout
7474
if: ${{ !cancelled() }}
75-
uses: actions/checkout@v6
75+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
7676
with:
7777
# Full history: hygiene diffs base..head and gitleaks scans the PR's
7878
# commits, base..head.
Lines changed: 76 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
name: "🚀 Release image"
22

3+
# Releases are source only: a v* tag proves the manager image builds from the
4+
# pinned web ref and passes the read-only health check. Nothing is pushed —
5+
# no registry login, no image or chart publish, no `latest`. Adopters build
6+
# and push their own image (see README.md#-deploying).
7+
38
on:
49
push:
510
tags:
611
- "v*"
712

813
permissions:
914
contents: read
10-
packages: write
1115

1216
jobs:
1317
image:
14-
name: "Build and push the manager image"
15-
runs-on: ubuntu-latest
18+
name: "Build the manager image and prove it boots"
19+
runs-on: ubuntu-24.04
1620
# The image build compiles the web UI and the Go binary; the gha layer
1721
# cache keeps repeat builds well under this.
1822
timeout-minutes: 45
23+
env:
24+
IMAGE: manager:release-check
25+
NET: fleet-release-check
1926
steps:
2027
# A tagged image has to be rebuildable from the tag. Falling back to
2128
# web's main would embed whatever web happened to be at build time, so
@@ -31,12 +38,12 @@ jobs:
3138
echo "web ref: $WEB_RELEASE_REF"
3239
3340
- name: Checkout manager
34-
uses: actions/checkout@v4
41+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3542
with:
3643
path: manager
3744

3845
- name: Checkout web (pinned)
39-
uses: actions/checkout@v4
46+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
4047
with:
4148
repository: CryptOS-PKI/cryptos-web
4249
ref: ${{ vars.WEB_RELEASE_REF }}
@@ -56,61 +63,84 @@ jobs:
5663
echo "date=$(date -u -d "@$epoch" +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
5764
5865
- name: Set up Docker Buildx
59-
uses: docker/setup-buildx-action@v3
60-
61-
- name: Log in to GHCR
62-
uses: docker/login-action@v3
63-
with:
64-
registry: ghcr.io
65-
username: ${{ github.actor }}
66-
password: ${{ secrets.GITHUB_TOKEN }}
67-
68-
- name: Image metadata
69-
id: meta
70-
uses: docker/metadata-action@v5
71-
with:
72-
images: ghcr.io/cryptos-pki/cryptos-manager
73-
tags: |
74-
type=semver,pattern={{version}}
75-
type=raw,value=latest
66+
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
7667

77-
- name: Build and push
78-
uses: docker/build-push-action@v6
68+
- name: Build (not pushed)
69+
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
7970
env:
8071
SOURCE_DATE_EPOCH: ${{ steps.build.outputs.epoch }}
8172
with:
8273
context: .
8374
file: manager/Dockerfile
84-
push: true
75+
push: false
76+
load: true
77+
tags: ${{ env.IMAGE }}
8578
build-args: |
86-
VERSION=${{ steps.meta.outputs.version }}
79+
VERSION=${{ github.ref_name }}
8780
COMMIT=${{ github.sha }}
8881
BUILD_DATE=${{ steps.build.outputs.date }}
8982
WEB_REF=${{ steps.build.outputs.web_sha }}
90-
tags: ${{ steps.meta.outputs.tags }}
91-
labels: ${{ steps.meta.outputs.labels }}
9283
cache-from: type=gha
9384
cache-to: type=gha,mode=max
9485

95-
chart:
96-
name: "Package and push the Helm chart"
97-
runs-on: ubuntu-latest
98-
timeout-minutes: 10
99-
permissions:
100-
contents: read
101-
packages: write
102-
steps:
103-
- name: Checkout
104-
uses: actions/checkout@v4
86+
- name: Image runs as nonroot with a health check
87+
run: |
88+
set -euo pipefail
89+
user="$(docker image inspect -f '{{.Config.User}}' "$IMAGE")"
90+
echo "user=$user"
91+
[ "$user" = "65532:65532" ]
92+
docker image inspect -f '{{json .Config.Healthcheck}}' "$IMAGE" | tee /dev/stderr | grep -q -- '-healthcheck'
10593
106-
- name: Set up Helm
107-
uses: azure/setup-helm@v4
94+
- name: Start Postgres
95+
run: |
96+
set -euo pipefail
97+
docker network create "$NET"
98+
docker run -d --name pg --network "$NET" \
99+
-e POSTGRES_DB=manager -e POSTGRES_USER=manager -e POSTGRES_PASSWORD=release \
100+
postgres:18-alpine
101+
for _ in $(seq 1 30); do
102+
docker exec pg pg_isready -U manager -d manager && exit 0
103+
sleep 2
104+
done
105+
exit 1
108106
109-
- name: Log in to GHCR
110-
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin
107+
# No tlsCert/tlsKey or operator CA: the manager serves its self-signed
108+
# bootstrap certificate, which is enough to exercise the TLS listener the
109+
# health probe talks to.
110+
- name: Run the image read-only
111+
run: |
112+
set -euo pipefail
113+
cfg="$RUNNER_TEMP/fleet"
114+
mkdir -p "$cfg"
115+
cat > "$cfg/config.yaml" <<'EOF'
116+
listen: "0.0.0.0:8443"
117+
httpRedirectListen: ""
118+
database_url: "postgres://manager:release@pg:5432/manager?sslmode=disable"
119+
nodes: []
120+
EOF
121+
sudo chown -R 65532:65532 "$cfg"
122+
docker run -d --name manager --network "$NET" \
123+
--read-only --cap-drop ALL --security-opt no-new-privileges:true \
124+
--health-interval 2s --health-start-period 5s \
125+
-p 8443:8443 \
126+
-v "$cfg/config.yaml:/etc/cryptos/fleet/config.yaml:ro" \
127+
-v node-creds:/var/lib/cryptos-manager/node-creds \
128+
"$IMAGE"
111129
112-
- name: Package and push
130+
- name: Becomes healthy
113131
run: |
114-
version="${GITHUB_REF_NAME#v}"
115-
helm package chart/fleet-manager --version "$version" --app-version "$version"
116-
helm push "fleet-manager-${version}.tgz" oci://ghcr.io/cryptos-pki/charts
132+
set -euo pipefail
133+
for _ in $(seq 1 60); do
134+
state="$(docker inspect -f '{{.State.Health.Status}}' manager)"
135+
echo "health=$state"
136+
[ "$state" = healthy ] && break
137+
[ "$(docker inspect -f '{{.State.Running}}' manager)" = true ] || break
138+
sleep 2
139+
done
140+
[ "$state" = healthy ]
141+
curl -sSk https://127.0.0.1:8443/healthz | tee /dev/stderr | grep -q '"status":"ok"'
142+
curl -sSk https://127.0.0.1:8443/version | tee /dev/stderr | grep -q "\"version\":\"${GITHUB_REF_NAME}\""
143+
144+
- name: Manager log
145+
if: ${{ always() }}
146+
run: docker logs manager || true

0 commit comments

Comments
 (0)