Repository navigation
218 lines (213 loc) · 11.1 KB
/
Copy pathci.yml
File metadata and controls
218 lines (213 loc) · 11.1 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
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
reject-fork-pr:
# A skipped job is not a failed check, so without this a fork PR would look
# green while the Rust build below never ran. Fail closed instead.
name: Reject fork PR (Rust CI needs the tailnet runner)
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Explain and fail
run: |
echo "Fork PRs cannot run the Rust CI: it needs the tailnet-only cargo registry and runs on a persistent self-hosted host that must not execute fork code."
echo "A maintainer must push the branch to this repository to get a real run."
exit 1
build:
# Never run fork PR code on the persistent self-hosted host.
if: >-
github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name == github.repository
# Self-hosted: GitHub-hosted runners cannot download crates from the
# private Terraphim registry (Caddy on bigbox rejects off-tailnet requests
# without a Bearer header, and cargo sends no token on .crate downloads
# because the registry advertises auth-required:false). The release-linux
# runner resolves git.terraphim.cloud over the tailnet, as
# release-binaries.yml relies on (#366).
runs-on: [self-hosted, Linux, X64, release-linux]
# The registry token is exposed to the "Fetch dependencies" step only, which
# runs no repository code (cargo fetch executes no build scripts). Every
# later step runs offline without the secret. A fresh CARGO_HOME has no
# cached index, and the registry index then requires the token.
env:
# The runner is a persistent host: select the toolchain per job through
# the environment so the host's default toolchain is never changed.
# RUSTUP_HOME stays shared on purpose: the toolchain is pinned and the
# step only installs it, so sharing saves a download without letting job
# code change what other workflows resolve. Everything else mutable is
# per-run (see "Isolate cargo state").
RUSTUP_TOOLCHAIN: 1.96.0
# The host config sets a host-only rustc wrapper; disable it.
RUSTC_WRAPPER: ""
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Assert clean checkout
run: test -z "$(git status --porcelain)"
- name: Isolate cargo state per run
# PR code (build scripts, proc macros, tests) must not mutate
# ~/.cargo, which release-binaries.yml also uses on this host. The
# runner.* context is not available in job-level env, hence this step.
run: |
set -euo pipefail
cargo_home="$RUNNER_TEMP/cargo-home"
mkdir -p "$cargo_home" "$RUNNER_TEMP/tools/bin"
# Keep the registry definitions, drop the host-only rustc wrapper.
if [ -f "$HOME/.cargo/config.toml" ]; then
sed '/rustc-wrapper/d' "$HOME/.cargo/config.toml" > "$cargo_home/config.toml"
fi
{
echo "CARGO_HOME=$cargo_home"
echo "CARGO_TARGET_DIR=$RUNNER_TEMP/target"
} >> "$GITHUB_ENV"
echo "$RUNNER_TEMP/tools/bin" >> "$GITHUB_PATH"
- name: Install exact Rust toolchain
run: rustup toolchain install 1.96.0 --profile minimal --component rustfmt,clippy
# No rust-cache: its toolchain detection breaks on the host's rustup
# wrapper output, and cargo state is deliberately per run (cold cache).
- name: Install release signature verifier
# Per-run root: never writes into the shared ~/.cargo/bin.
run: cargo install zipsign --version 0.2.1 --locked --root "$RUNNER_TEMP/tools"
- name: Fetch dependencies (the only step holding the registry token)
env:
CARGO_REGISTRIES_TERRAPHIM_TOKEN: ${{ secrets.CARGO_REGISTRIES_TERRAPHIM_TOKEN }}
run: |
set -euo pipefail
cargo fetch --locked
# Everything after this point resolves from the per-run cache.
echo "CARGO_NET_OFFLINE=true" >> "$GITHUB_ENV"
- name: Install pinned actionlint
run: .github/scripts/install-actionlint.sh
- name: Release workflow and sealing contracts
run: |
python3 -m unittest discover -s tests -p 'test_*release*contract.py' -v
python3 -m unittest tests.test_build_manifest_contract -v
python3 -m unittest tests.test_promotion_contract -v
python3 -m unittest tests.test_package_metadata_contract -v
python3 -m unittest tests.test_manifest_builder_compatibility -v
- run: cargo fmt --all -- --check
- run: cargo clippy --workspace --all-targets -- -D warnings
- run: cargo build --workspace
- run: cargo test --workspace --lib --no-fail-fast
- name: Persist and recover authored memory through the CLI
run: cargo test --locked -p terraphim_agent --test memory_capture_cli_tests --test memory_apply_cli_tests --test memory_rubric_cli_tests --test agent_store_contract --test agent_learning_store_contract
# Exercise the released grep command against real files and exported
# synonym graphs, including Linux-only hostile filesystem names.
- run: cargo test --locked -p terraphim_grep --test synonym_retrieval --test answer_request --test path_guard_hostile_tree --test single_file_search
- name: Verify authored synonyms and role boundaries over real MCP stdio
run: cargo test --locked -p terraphim_mcp_server --test test_mcp_role_contract --test test_mcp_agent_contract
# GitHub-side home for the updater integration contracts (managed-mode
# receipt/refusal, strict v2 manifest readers, R2 checksum fail-closed).
# On Gitea these lanes live in .gitea/workflows/native-ci.yml, which is
# intentionally not part of the GitHub port.
- run: cargo test -p terraphim_update --test manifest --test r2_update --test managed_mode --test policy --no-fail-fast
- name: Assert the build left the checkout and lockfile untouched
run: |
set -euo pipefail
git diff --exit-code -- Cargo.toml Cargo.lock
test -z "$(git status --porcelain)"
- name: Remove per-run state
if: always()
run: rm -rf "$RUNNER_TEMP/cargo-home" "$RUNNER_TEMP/target" "$RUNNER_TEMP/tools"
client-packaging-contracts:
name: Client DEB/RPM packaging producer contracts
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.x'
- name: Install pinned nFPM
shell: bash
env:
NFPM_VERSION: 2.47.0
NFPM_ARCHIVE_SHA256: 0660ca602b2d2d2ae4781a06c692b3eeb9d437ffea05b831d76e41f4a3188783
NFPM_BINARY_SHA256: 17133a2467ffb7cec851c2d7bae0c6098d09d7ed7d3d101a9605f6a473323936
run: |
set -euo pipefail
install_dir="/tmp/nfpm-bin"
mkdir -p "$install_dir"
archive="$install_dir/nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz"
url="https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz"
curl -fsSL "$url" -o "$archive"
printf '%s %s\n' "$NFPM_ARCHIVE_SHA256" "$archive" | sha256sum -c -
tar -xzf "$archive" -C "$install_dir" nfpm
printf '%s %s\n' "$NFPM_BINARY_SHA256" "$install_dir/nfpm" | sha256sum -c -
mv "$install_dir/nfpm" "$install_dir/nfpm-${NFPM_VERSION}"
chmod 0755 "$install_dir/nfpm-${NFPM_VERSION}"
.github/scripts/nfpm/verify-nfpm.sh \
--binary "$install_dir/nfpm-${NFPM_VERSION}" \
--version "$NFPM_VERSION" \
--sha256 "$NFPM_BINARY_SHA256"
# #326: these suites protect the DEB/RPM managed-package producer's
# fail-closed properties (arch/version normalization, payload
# byte-equivalence, receipt contract, lint policy, checksum-manifest
# round-trip verification, all-or-nothing inventory assembly). Without
# a CI home a future edit could weaken any of them with no signal.
# REQUIRE_TOOLS=1 turns every prerequisite SKIP inside these suites
# into a hard failure so this step can never pass vacuously if nFPM,
# dpkg-deb, rpm/rpm2cpio, cpio, or a C compiler are missing from the
# runner image.
#
# #26: rpm2cpio and cpio are NOT on the ubuntu-latest image. Without
# them verify_rpm falls back to docker_rpm_tool, and the arch regression
# suite reported "RPM payload extraction failed" even though every
# payload member extracted cleanly (run 35434267810 assert failed on
# the missing "RPM arch mismatch" line while the extraction log showed
# all five members plus "26 blocks"). Provision the host RPM toolchain
# explicitly so the suite exercises the production host path it is
# meant to protect, deterministically, against a pinned image.
- name: Install RPM payload tooling
shell: bash
run: |
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends rpm2cpio cpio rpm
# rpm2cpio has no --version/--help flag: it takes an RPM path as its
# only argument, so probe for the executable itself. cpio and rpm do
# support --version and are checked that way.
command -v rpm2cpio >/dev/null 2>&1 ||
{ echo "rpm2cpio missing after install" >&2; exit 1; }
cpio --version >/dev/null 2>&1 ||
{ echo "cpio missing after install" >&2; exit 1; }
rpm --version >/dev/null 2>&1 ||
{ echo "rpm missing after install" >&2; exit 1; }
- name: Install pinned actionlint
run: .github/scripts/install-actionlint.sh
- name: Managed package producer contracts (workflow, shell)
shell: bash
env:
NFPM_BIN: /tmp/nfpm-bin/nfpm-2.47.0
REQUIRE_TOOLS: "1"
run: |
set -euo pipefail
# #326 P1-1: the contract module is unittest-based (unittest.main());
# invoke it with the stdlib runner directly instead of requiring an
# undeclared pytest dependency the runner image never installs.
python3 -m unittest -v tests.test_release_binaries_workflow_contract
for t in \
.github/scripts/nfpm/tests/test_client_nfpm.sh \
.github/scripts/nfpm/tests/test_client_nfpm_arch.sh \
.github/scripts/nfpm/tests/test_client_nfpm_policy.sh \
.github/scripts/nfpm/tests/test_client_nfpm_static_lint.sh \
.github/scripts/nfpm/tests/test_client_nfpm_strip.sh \
.github/scripts/nfpm/tests/test_verify_nfpm.sh \
.github/scripts/release/tests/test_assemble_client_release_inventory.sh \
; do
echo "::group::$t"
bash "$t"
echo "::endgroup::"
done