-
Notifications
You must be signed in to change notification settings - Fork 8
84 lines (76 loc) · 3.82 KB
/
Copy pathrelease-gate.yml
File metadata and controls
84 lines (76 loc) · 3.82 KB
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
74
75
76
77
78
79
80
81
82
83
84
name: Release gate (self-hosted)
# Tier-4 end-to-end validation against the REAL synced Monero + Tari nodes — the pre-release
# gate (#54). It runs on the dedicated, self-hosted release server (which holds real wallet /
# onion keys), so it MUST only ever run code we trust.
#
# SECURITY: there is deliberately NO `pull_request` trigger. A fork PR's code running on this
# runner could steal the box's keys or persist a backdoor (GitHub recommends against self-hosted
# runners on public repos for exactly this reason). The gate runs only on:
# - workflow_dispatch — a maintainer manually runs it on a ref they've reviewed, OR
# - push to main — post-merge, on trusted code.
# To end-to-end a specific fork PR, review it first, then dispatch this workflow on that ref.
# See docs/dev/release-server.md.
on:
workflow_dispatch:
inputs:
stack_dir:
description: "Path to the deployed Pithead stack on the runner (absolute; default $HOME/code/pithead)"
required: false
default: ""
mode:
description: "check = non-destructive; matrix = full destructive config matrix (with a safety backup + auto-rollback)"
required: false
default: "check"
type: choice
options: [check, matrix]
push:
branches: [main]
# Never run two gates against the one shared box at the same time.
concurrency:
group: release-gate
cancel-in-progress: false
# Least privilege (#282): this runs on a self-hosted box holding real keys — keep the token read-only.
permissions:
contents: read
jobs:
release-gate:
name: Tier-4 live matrix (real nodes)
# Only run automatically once a self-hosted runner is actually wired up — set the repo variable
# ENABLE_RELEASE_GATE=true when one is registered. Without this guard, every push to main queues
# a job no runner can claim, and GitHub auto-cancels it after a 24h timeout — a permanent red ✗
# on main. A skipped job is green/neutral instead. A manual workflow_dispatch ALWAYS runs, so a
# maintainer can still validate a reviewed ref on a registered runner on demand.
if: ${{ github.event_name == 'workflow_dispatch' || vars.ENABLE_RELEASE_GATE == 'true' }}
# Register the server with these labels: `pithead-release` scopes the gate to the dedicated
# box; prefer an ephemeral / just-in-time runner in its own runner group.
runs-on: [self-hosted, pithead-release]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Validate against the real synced nodes
# Inputs go through env (not interpolated into the script) to avoid shell injection.
env:
STACK_DIR_INPUT: ${{ github.event.inputs.stack_dir }}
MODE_INPUT: ${{ github.event.inputs.mode }}
run: |
set -euo pipefail
DIR="${STACK_DIR_INPUT:-$HOME/code/pithead}"
MODE="${MODE_INPUT:-check}"
echo "Release gate: stack dir=$DIR, mode=$MODE"
# Always assess fitness + the non-destructive live state first.
bash tests/integration/run.sh --local --dir "$DIR" --readiness
bash tests/integration/run.sh --local --dir "$DIR" --check
# The full destructive config matrix is opt-in; --safety-backup rolls the box back if
# anything fails, so a red run leaves the server as it found it.
if [ "$MODE" = "matrix" ]; then
bash tests/integration/run.sh --local --dir "$DIR" --workers 2 --safety-backup --lifecycle
fi
- name: Upload artifacts (redacted)
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-gate-results
path: tests/integration/results/
if-no-files-found: ignore
retention-days: 14