Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .github/workflows/refresh-pins.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: refresh image pins

# Every module's default image is pinned to a digest, so upstream releases no
# longer reach users on their own. This workflow is how they reach users
# deliberately: it re-resolves each pinned tag to whatever digest it points at
# today and opens a PR with the diff.
#
# It NEVER pushes to main and NEVER auto-merges. A pin refresh means "the game
# binary changes for everyone on next restart", which is exactly the event
# pinning exists to put a human in front of. Review the PR, and let the
# `validate modules` workflow re-check the new digests against their OCI
# configs before merging.
#
# Entries tagged `# gameplane:floating` in a template are skipped by the
# pinner and stay moving on purpose (factorio's Experimental channel,
# terraria's tModLoader preview).

on:
workflow_dispatch:
schedule:
# 04:00 UTC on the 1st of each month. Monthly rather than nightly: these
# are game-server images, and a PR nobody has time to review is worse than
# no PR at all.
- cron: "0 4 1 * *"

permissions:
contents: write
pull-requests: write

jobs:
refresh:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install PyYAML
run: pip install --disable-pip-version-check --user pyyaml

- name: Re-resolve every pinned tag
id: pin
# `--pin` exits non-zero when a ref could not be resolved. It leaves
# those refs untouched rather than writing a guessed digest, so a
# partial refresh is still a safe diff — surface it in the PR body
# instead of failing the job outright.
run: |
set +e
python3 validate.py --pin | tee /tmp/pin.log
echo "exit=$?" >> "$GITHUB_OUTPUT"

- name: Check for changes
id: diff
run: |
if git diff --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No digest movement — every pinned tag still resolves to the same image."
else
echo "changed=true" >> "$GITHUB_OUTPUT"
git diff --stat
fi

- name: Re-validate the refreshed pins
if: steps.diff.outputs.changed == 'true'
# Non-blocking: the point is to attach the validator's opinion of the
# NEW images to the PR, not to stop the PR from being opened. A new
# upstream build that trips a rule is precisely what a reviewer needs
# to see.
continue-on-error: true
run: python3 validate.py | tee /tmp/validate.log

- name: Open a pull request
if: steps.diff.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# NOTE: a PR opened with the default GITHUB_TOKEN does not itself
# trigger other workflows, so `validate modules` will not run on it
# automatically. The validator output is attached to the PR body
# above; close and reopen the PR (or push an empty commit) to get a
# real CI run before merging.
run: |
BRANCH="chore/refresh-image-pins-$(date -u +%Y%m%d)"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
# Two -m flags rather than one embedded newline: an unindented
# continuation line would terminate this YAML block scalar.
git commit -as \
-m "chore: refresh module image pins" \
-m "Re-resolved every pinned tag to its current digest. Review what actually moved before merging - each changed digest is a game binary that changes for every server on its next restart."
git push origin "$BRANCH"
{
echo "Automated pin refresh. **Each changed digest changes the game binary**"
echo "for every server using that module on its next pod restart."
echo
echo "## Pinner output"
echo '```'
cat /tmp/pin.log
echo '```'
echo "## Validator output for the new images"
echo '```'
cat /tmp/validate.log 2>/dev/null || echo "(validator did not run)"
echo '```'
} > /tmp/body.md
gh pr create --title "chore: refresh module image pins" \
--body-file /tmp/body.md --base main --head "$BRANCH"
23 changes: 22 additions & 1 deletion 7-days-to-die/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,28 @@ spec:
Gameplane's single data volume can't all cover at once, and world
persistence was the fix this template needed.

image: vinanrra/7dtd-server:latest
image: vinanrra/7dtd-server:latest@sha256:e3c479866744a65c1bec2b1a4691e08baff2938cf674d4674cd9e8975cd21e4c

versions:
- id: v0-9-3
displayName: "Image v0.9.3"
image: vinanrra/7dtd-server:v0.9.3@sha256:75d1193fb2470687ee8748f27482524c170f6cbca110e15f48db8d8ff48f15ca
default: true
- id: v0-9-2
displayName: "Image v0.9.2"
image: vinanrra/7dtd-server:v0.9.2@sha256:2ba7b9d4b1a7f66b5b7e00755f62169583930e64c49cf400b69c4f1f2d126a9c
- id: v0-9-1
displayName: "Image v0.9.1"
image: vinanrra/7dtd-server:v0.9.1@sha256:f6c6572a77c1503d6ddafe08fdc873daff974e24ef3a929881b4d184aae8c2ca
- id: v0-9-0
displayName: "Image v0.9.0"
image: vinanrra/7dtd-server:v0.9.0@sha256:83d203f74af22f8bef9600723c7463845070f0724142b09d6d89f7ffe1c86a19
- id: v0-7-10
displayName: "Image v0.7.10"
image: vinanrra/7dtd-server:v0.7.10@sha256:8e5cadc01af04a53db2832ae46f919275cec484b5d58350af7e8aad6fff83af5
- id: latest
displayName: "Latest (moves on restart)"
image: vinanrra/7dtd-server:latest # gameplane:floating

env:
# Required by the image — with no env at all (the previous draft's
Expand Down
20 changes: 19 additions & 1 deletion ark-survival-ascended/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,25 @@ spec:
RCON-backed console and moderation. CurseForge mod management via the
Mods tab.

image: mschnitzer/asa-linux-server:latest
image: mschnitzer/asa-linux-server:latest@sha256:6a62f7c6eb77ba4b4b79ef6c2981a0bd9fab287e744d9797e66efc762ebb811e

versions:
- id: 1-5-1
displayName: "Image 1.5.1"
image: mschnitzer/asa-linux-server:1.5.1@sha256:6a62f7c6eb77ba4b4b79ef6c2981a0bd9fab287e744d9797e66efc762ebb811e
default: true
- id: 1-5-0
displayName: "Image 1.5.0"
image: mschnitzer/asa-linux-server:1.5.0@sha256:4b8df632b2070af60fddd6f77cc43f6397feed06ca7f29d80455e9b6ac2057d5
- id: 1-4-1
displayName: "Image 1.4.1"
image: mschnitzer/asa-linux-server:1.4.1@sha256:b2b7bad7b388853b7f152723f6dcbf0a40504beefb23568def85f61b56028cb9
- id: 1-4-0
displayName: "Image 1.4.0"
image: mschnitzer/asa-linux-server:1.4.0@sha256:c16a19aef7804e38ec4d6860f1ca038ccd83d606dd221877bccc862446eb8a85
- id: latest
displayName: "Latest (moves on restart)"
image: mschnitzer/asa-linux-server:latest # gameplane:floating

# REQUIRED. The image declares no ENTRYPOINT and its CMD is /bin/bash, so
# without this the container gets a non-interactive bash, which reads EOF
Expand Down
20 changes: 19 additions & 1 deletion cs2/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,25 @@ spec:
the console and the broadcast/stop actions; Metamod and
CounterStrikeSharp plugins install under `game/csgo/addons`.

image: joedwards32/cs2:latest
image: joedwards32/cs2:latest@sha256:41b826d6280d1aa9e41c866a6d88cc7f523e027f16c47a313b20c2d7a17f2680

versions:
- id: 4-0-1
displayName: "Image 4.0.1"
image: joedwards32/cs2:4.0.1@sha256:34c093d24a23751fb409ae41dffe88884fb36964b365fcd25a31ec45e88ad8cf
default: true
- id: 4-0-0
displayName: "Image 4.0.0"
image: joedwards32/cs2:4.0.0@sha256:36febab2abdabbeffa06edfda88c1d5603805a17287ae0658e23d07d5d07cda7
- id: 3-0-9
displayName: "Image 3.0.9"
image: joedwards32/cs2:3.0.9@sha256:bd6eec1fb4ae614c9c88680aaab41c7a43de40825476528f7542694ea213e13d
- id: 3-0-7
displayName: "Image 3.0.7"
image: joedwards32/cs2:3.0.7@sha256:5ef9a47b92cb017d6d94f2723bdad8a76be0dfcb24c2d438b257d14ed51697b5
- id: latest
displayName: "Latest (moves on restart)"
image: joedwards32/cs2:latest # gameplane:floating

# REQUIRED. The image config declares User "1000:1000" — it starts as a
# non-root user with no root step to self-chown, so a fresh PVC is EACCES
Expand Down
11 changes: 10 additions & 1 deletion dayz/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ spec:
BattlEye targets players by number rather than name, so a button would
risk hitting the wrong one — moderate in-game instead.

image: registry.godbleak.dev/godbleak/serverz:latest
image: registry.godbleak.dev/godbleak/serverz:latest@sha256:5e8757beae763c862d08a9c08587c35211cda74ce399f7419492d7520adab4fe

versions:
- id: 2-0-0
displayName: "Image 2.0.0"
image: registry.godbleak.dev/godbleak/serverz:2.0.0@sha256:5e8757beae763c862d08a9c08587c35211cda74ce399f7419492d7520adab4fe
default: true
- id: latest
displayName: "Latest (moves on restart)"
image: registry.godbleak.dev/godbleak/serverz:latest # gameplane:floating

env:
# Fixed to match the declared ports[] below.
Expand Down
15 changes: 14 additions & 1 deletion dont-starve-together/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,20 @@ spec:
categories: [Survival, Co-op]
accentColor: "#cc0000"
description: DST dedicated server.
image: jamesits/dst-server:latest
image: jamesits/dst-server:latest@sha256:fa61065f8d2d770bc5d45f1a160b87b1deada3fd5903d9524b771321ca98dc58

versions:
- id: vanilla
displayName: "Vanilla"
image: jamesits/dst-server:vanilla@sha256:fa61065f8d2d770bc5d45f1a160b87b1deada3fd5903d9524b771321ca98dc58
default: true
- id: nightly
displayName: "Nightly (moving)"
image: jamesits/dst-server:nightly # gameplane:floating
- id: latest
displayName: "Latest"
image: jamesits/dst-server:latest # gameplane:floating

ports:
- name: game
containerPort: 10999
Expand Down
18 changes: 17 additions & 1 deletion enshrouded/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,23 @@ spec:
categories: [Survival, Co-op, Building, Adventure]
accentColor: "#2a4b7c"
description: Enshrouded dedicated server.
image: mornedhels/enshrouded-server:latest
image: mornedhels/enshrouded-server:latest@sha256:85978a10f88a85ab0a0aa92e9821d30424895d38bf81fe543532451219c42d0d

versions:
- id: 1-7-2
displayName: "Game v1.7.2"
image: mornedhels/enshrouded-server:1.7.2@sha256:85978a10f88a85ab0a0aa92e9821d30424895d38bf81fe543532451219c42d0d
default: true
- id: 1-7-1
displayName: "Game v1.7.1"
image: mornedhels/enshrouded-server:1.7.1@sha256:67fe03f7a7b9932d269757604c97b85bbee125270c5cfc746d00dd21a2309ddc
- id: 1-7-0
displayName: "Game v1.7.0"
image: mornedhels/enshrouded-server:1.7.0@sha256:ca12415986fe84e585a2bd6cf5ba0a822a5c85c6caf1d557f5e607fdb2a84682
- id: latest
displayName: "Latest (moves on restart)"
image: mornedhels/enshrouded-server:latest # gameplane:floating

ports:
- name: game
containerPort: 15636
Expand Down
8 changes: 4 additions & 4 deletions factorio/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ spec:

# Fallback image when a server selects no version. versions[] below is the
# authoritative source for the wizard's picker.
image: factoriotools/factorio:stable
image: factoriotools/factorio:stable@sha256:7052b3cca8ca7790f99f4058617d5c8089df544de736b1baa23f2c5f58fb7f48

env:
# Load the newest save on boot (the entrypoint generates one on first
Expand Down Expand Up @@ -91,16 +91,16 @@ spec:
versions:
- id: stable
displayName: "Stable channel"
image: factoriotools/factorio:stable
image: factoriotools/factorio:stable@sha256:7052b3cca8ca7790f99f4058617d5c8089df544de736b1baa23f2c5f58fb7f48
loader: native
default: true
- id: latest
displayName: "Experimental channel"
image: factoriotools/factorio:latest
image: factoriotools/factorio:latest # gameplane:floating
loader: native
- id: stable-2-0-77
displayName: "2.0.77 (pinned stable)"
image: factoriotools/factorio:stable-2.0.77
image: factoriotools/factorio:stable-2.0.77@sha256:7052b3cca8ca7790f99f4058617d5c8089df544de736b1baa23f2c5f58fb7f48
loader: native
gameVersion: "2.0"

Expand Down
2 changes: 1 addition & 1 deletion garrys-mod/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ spec:
`addons/`, `gamemodes/`, and `cfg/` into the image and only persists
`garrysmod/data`).

image: ceifa/garrysmod:latest
image: ceifa/garrysmod:latest@sha256:26439fe29c2d66f4241a4db46e3c7088e9eb37356f2bd441dc0c3c86e8acb180

env:
# Debian production image variant (per the image's own recommendation
Expand Down
Loading
Loading