-
Notifications
You must be signed in to change notification settings - Fork 8
259 lines (245 loc) · 11.7 KB
/
Copy pathci.yml
File metadata and controls
259 lines (245 loc) · 11.7 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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
name: CI
on:
push:
branches: [main, develop]
pull_request:
# Least privilege (#282): every job here only reads the repo — none push commits, comment, or
# publish packages. Narrowing the default GITHUB_TOKEN limits the blast radius of a compromised step.
permissions:
contents: read
# Cancel superseded runs of the same PR; never cancel push runs on main/develop (they set the
# diff-cover baseline and are required checks on the protected branch). #415.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
dashboard:
name: Dashboard tests (pytest + coverage)
runs-on: ubuntu-latest
timeout-minutes: 15
env:
UV_PYTHON_DOWNLOADS: never # use the setup-python 3.11; don't fetch another interpreter
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0 # full history so diff-cover can diff the PR against origin/develop (#286)
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
- name: "Install uv (pinned — reproducible, hash-locked installs, #283)"
# Curl the pinned installer (same posture as hadolint below); avoids a mutable-tag action.
run: |
export UV_INSTALL_DIR="$HOME/.local/bin" # deterministic install dir (runners may set CARGO_HOME)
curl -LsSf https://astral.sh/uv/0.10.10/install.sh | sh
echo "$UV_INSTALL_DIR" >> "$GITHUB_PATH"
- name: Dashboard tests + coverage gate (emits coverage.xml)
run: make test-dashboard
- name: "Patch-coverage gate — changed lines >=90% (diff-cover vs origin/develop, #286)"
run: |
git fetch --no-tags origin develop
make test-patch-coverage
- name: Fake-daemon contract test (real clients vs controllable fakes)
# Points the real Monero/Tari clients at the integration fakes and asserts they parse
# every state (synced/syncing/down). Docker-free, so it runs on every PR (issue #54).
run: make test-fakes
frontend:
name: Frontend logic tests (node --test)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "20"
# Pure client logic (worker sort, tooltip formatting) lives in static/logic.mjs and is
# tested with Node's built-in runner — no package.json/node_modules/build step. Component
# rendering is covered by a manual browser smoke test, not here.
- name: Run frontend logic tests
run: node --test build/dashboard/tests/frontend/*.test.mjs
dashboard-image:
name: Dashboard image (Docker test stage)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Build the dashboard test stage (installs package + runs the suite in-container)
run: docker build --target test ./build/dashboard
build-images:
# Build every build/* image so a broken Dockerfile / COPY path / entrypoint / pinned-digest is
# caught in CI instead of at deploy time (#124). Previously only the dashboard test stage was
# built, so e.g. the Tor image's entrypoint restructure (#180) shipped with no CI safety net.
# Tari is an upstream image (no Dockerfile here), so it's excluded. fail-fast: false so one
# broken image doesn't hide the others; empty build-args keep the dashboard build working bare.
name: Build image (${{ matrix.service }})
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
service: [monero, p2pool, tor, xmrig-proxy, dashboard]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: docker build ./build/${{ matrix.service }}
run: docker build -t "pithead-${{ matrix.service }}:ci" "./build/${{ matrix.service }}"
- name: Scan image for CVEs (Trivy)
# Gate on actionable (fixable) HIGH/CRITICAL only; accepted findings live in .trivyignore.
# Must stay green before v1.1 images publish (#282).
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: pithead-${{ matrix.service }}:ci
scanners: vuln
severity: HIGH,CRITICAL
ignore-unfixed: true
exit-code: "1"
trivyignores: .trivyignore
hadolint:
name: Dockerfile lint (hadolint)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: "Install hadolint (pinned + sha256-verified, #286)"
run: |
curl -fsSL -o /tmp/hadolint \
https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64
echo "56de6d5e5ec427e17b74fa48d51271c7fc0d61244bf5c90e828aab8362d55010 /tmp/hadolint" | sha256sum -c -
sudo install -m 0755 /tmp/hadolint /usr/local/bin/hadolint
- name: Lint all build/* Dockerfiles (config in .hadolint.yaml)
run: hadolint build/*/Dockerfile
python-lint:
name: Python lint + format (ruff)
runs-on: ubuntu-latest
timeout-minutes: 15
env:
UV_PYTHON_DOWNLOADS: never
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
- name: Install uv (pinned)
run: |
export UV_INSTALL_DIR="$HOME/.local/bin" # deterministic install dir (runners may set CARGO_HOME)
curl -LsSf https://astral.sh/uv/0.10.10/install.sh | sh
echo "$UV_INSTALL_DIR" >> "$GITHUB_PATH"
- name: ruff check + format --check (config in build/dashboard/pyproject.toml + root ruff.toml)
# Single source of truth: the Makefile `lint-py` target, which runs ruff via uv from the
# locked `dev` extra — one pinned ruff for CI, pre-commit, and local devs.
run: make lint-py
gitleaks:
name: Secret scan (gitleaks)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0 # full history so the scan covers every commit, not just the tip
- name: Scan git history for secrets (gitleaks, pinned by digest)
# Run the binary via its pinned image (the gitleaks-action requires a license for org repos).
# Accepted false positives live in .gitleaks.toml.
run: |
docker run --rm -v "$PWD":/repo \
ghcr.io/gitleaks/gitleaks:v8.30.1@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f \
git /repo --no-banner --redact --config /repo/.gitleaks.toml
zizmor:
name: Workflow audit (zizmor)
runs-on: ubuntu-latest
timeout-minutes: 15
env:
UV_PYTHON_DOWNLOADS: never
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
- name: Install uv (pinned)
run: |
export UV_INSTALL_DIR="$HOME/.local/bin"
curl -LsSf https://astral.sh/uv/0.10.10/install.sh | sh
echo "$UV_INSTALL_DIR" >> "$GITHUB_PATH"
- name: Audit workflows (injection, token scope, self-hosted-runner risks)
run: uvx zizmor@1.25.2 --offline .github/workflows/
shell:
name: Shell tests (shellcheck + pithead suite)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: "Install shellcheck + shfmt (pinned + sha256-verified, #286)"
# Direct upstream-release downloads with a sha256 check (RigForge convention) instead of the
# runner's preinstalled shellcheck / apt — reproducible, and immune to the apt-mirror
# flakiness of #64. Keep these pins in sync with the local-dev tooling.
run: |
curl -fsSL -o /tmp/shfmt \
https://github.com/mvdan/sh/releases/download/v3.13.1/shfmt_v3.13.1_linux_amd64
echo "fb096c5d1ac6beabbdbaa2874d025badb03ee07929f0c9ff67563ce8c75398b1 /tmp/shfmt" | sha256sum -c -
sudo install -m 0755 /tmp/shfmt /usr/local/bin/shfmt
curl -fsSL -o /tmp/sc.tar.xz \
https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz
echo "8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198 /tmp/sc.tar.xz" | sha256sum -c -
tar -xJf /tmp/sc.tar.xz -C /tmp
sudo install -m 0755 /tmp/shellcheck-v0.11.0/shellcheck /usr/local/bin/shellcheck
- name: Lint pithead, build/* container scripts, and test scripts (shellcheck + shfmt)
# Single source of truth: the Makefile `lint-sh` target (so the file list can't drift
# between here and the Makefile). Covers build/*/*.sh — the entrypoints + healthchecks that
# run in every container (#124). Gate on warnings+errors; info-level style nits vary by
# shellcheck version. Python lint runs in its own `python-lint` job (ruff isn't on this
# runner; `make lint` runs both for local devs).
run: make lint-sh
- name: Run pithead test suite
run: bash tests/stack/run.sh
- name: Run integration harness self-test
# Pure-logic checks for the tests/integration/ harness (config rendering, matrix
# coverage, redaction). The LIVE matrix (tests/integration/run.sh) needs a real test
# server and runs as a gated/manual release gate (#54), not on every PR.
run: bash tests/integration/selftest.sh
compose:
name: Compose config + security hardening
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Validate docker-compose.yml interpolation + hardening invariants (#90)
run: bash tests/stack/test_compose.sh
lint-surfaces:
name: Lint per-surface (biome, yaml, markdown, proto, toml)
runs-on: ubuntu-latest
timeout-minutes: 15
env:
UV_PYTHON_DOWNLOADS: never
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "20"
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
- name: Install uv (pinned)
run: |
export UV_INSTALL_DIR="$HOME/.local/bin"
curl -LsSf https://astral.sh/uv/0.10.10/install.sh | sh
echo "$UV_INSTALL_DIR" >> "$GITHUB_PATH"
- name: Lint JS/CSS (Biome), YAML, Markdown, proto (buf), TOML (taplo), docs voice
# Single source of truth: the Makefile targets. Tools run via npx/uvx/docker (preinstalled).
run: make lint-js lint-yaml lint-md lint-proto lint-toml lint-docs-voice