-
Notifications
You must be signed in to change notification settings - Fork 0
172 lines (156 loc) · 7.01 KB
/
Copy pathsigning-e2e.yml
File metadata and controls
172 lines (156 loc) · 7.01 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
name: Signing E2E
# End-to-end validation of the `synth compile --sign-output` Phase 5 path
# against a real `wsc` binary from pulseengine/sigil. This workflow closes the
# "not validated end-to-end" gap explicitly flagged when Phase 5 shipped in
# PR #135 — synth-cli's unit test only pins the argv shape, not the actual
# sign + verify round-trip. The test script lives at `tests/wsc_sign_e2e.sh`.
#
# Trust model: the wsc binary is downloaded from a pinned sigil release,
# its sha256 is verified against a value pinned in this workflow file. The
# sha256 reference value was taken from the sigil v0.9.0 release's
# `wsc-linux-x86_64.sha256` sidecar at publish time. If sigil rotates the
# binary without bumping the version, this workflow fails loudly — that is
# the rigor pattern: pin the contract.
#
# Why release-download and not Bazel:
# - sigil ships ready-to-run binaries with per-asset sha256 sidecars and
# SLSA build provenance. Pinning by version + sha256 is sufficient to
# guarantee a known binary.
# - rules_wasm_component (already in MODULE.bazel) is a WASM-component
# toolchain ruleset, not a `wsc` CLI distribution. Wiring wsc through
# Bazel would require a custom binary-import rule for marginal hermetic
# benefit over a sha256-pinned curl.
# - Sigil's own CI builds wsc from source (cargo build), which is even
# slower than downloading a release binary and offers nothing we can't
# reproduce locally with `cargo install --git ...`.
#
# Untrusted-input safety: this workflow does NOT read PR titles, comment
# bodies, head_ref, or any other user-controlled field into `run:` blocks.
# All values interpolated into shell commands come from workflow `env:`
# keys (pinned in this file) or from `secrets`/`runner.temp` (controlled
# by GitHub). Bound via env: and dereferenced as $VAR per the standard
# workflow-injection mitigation.
on:
push:
tags:
- "v*"
branches: [main]
paths:
# PR triggers below already cover crates/synth-cli/src/sign.rs and the
# release workflow; on push-to-main we run on the same set so a
# branch-protection bypass doesn't skip the e2e.
- "crates/synth-cli/src/sign.rs"
- "crates/synth-cli/src/main.rs"
- "tests/wsc_sign_e2e.sh"
- "tests/integration/add.wat"
- ".github/workflows/signing-e2e.yml"
pull_request:
branches: [main]
paths:
# Run on PRs that touch the synth-side signing contract or the test
# itself. Catches future breaks where someone changes the argv shape
# in sign.rs without updating the wsc pin.
- "crates/synth-cli/src/sign.rs"
- "crates/synth-cli/src/main.rs"
- "tests/wsc_sign_e2e.sh"
- "tests/integration/add.wat"
- ".github/workflows/signing-e2e.yml"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
# Pinned wsc release. Bumped manually in lockstep with the wsc CLI
# contract assumption documented in crates/synth-cli/src/sign.rs. If
# sigil ships a new wsc with a different CLI shape (e.g. dropping
# --keyless in favor of --mode keyless), bumping this here without
# updating sign.rs is intended to make the test fail loudly.
WSC_VERSION: "v0.9.0"
# sha256 of the Linux x86_64 wsc binary at $WSC_VERSION. Source:
# https://github.com/pulseengine/sigil/releases/download/v0.9.0/wsc-linux-x86_64.sha256
WSC_SHA256_LINUX_X86_64: "9054b4b066e2b0a954110851a43266ff0e9ef12b4e1ecc03c333943fd52cecb6"
jobs:
signing-e2e:
name: synth compile --sign-output e2e
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
# Required for `wsc sign --keyless` to obtain an OIDC token from
# GitHub Actions; Fulcio short-lived certs are bound to that token's
# workflow identity. Without `id-token: write` the keyless flow
# cannot produce a Fulcio certificate at all.
contents: read
id-token: write
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target/
key: ${{ runner.os }}-cargo-sign-e2e-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-sign-e2e-
- name: Build synth-cli (release)
run: cargo build --release -p synth-cli
- name: Install wabt for wat2wasm
# wat2wasm is used by tests/wsc_sign_e2e.sh case 1 to turn the WAT
# fixture into a real WASM module for the keyless sign+verify
# round-trip. wabt is a small package in the standard Ubuntu repos.
run: sudo apt-get update && sudo apt-get install -y wabt
- name: Download pinned wsc binary
env:
# Bound through env: per the workflow-injection-mitigation pattern.
# Values come from workflow-level env (pinned in this file), not
# from any user-controlled field.
WSC_TAG: ${{ env.WSC_VERSION }}
WSC_SHA: ${{ env.WSC_SHA256_LINUX_X86_64 }}
run: |
set -euo pipefail
ASSET="wsc-linux-x86_64"
URL="https://github.com/pulseengine/sigil/releases/download/${WSC_TAG}/${ASSET}"
echo "::notice::Downloading wsc from $URL"
curl --fail --location --silent --show-error \
-o "$RUNNER_TEMP/wsc" "$URL"
# Verify sha256 against the pinned digest. Use `sha256sum -c` with
# the pinned value rather than parsing the upstream .sha256 sidecar
# (which would also need to be downloaded and trusted, leaving a
# TOCTOU window). This makes the workflow file itself the trust
# anchor — auditable in one place.
echo "${WSC_SHA} $RUNNER_TEMP/wsc" | sha256sum --check --strict
echo "::notice::wsc sha256 matches pinned value"
chmod +x "$RUNNER_TEMP/wsc"
# Make wsc discoverable on PATH for synth-cli's `Command::new("wsc")`.
mkdir -p "$RUNNER_TEMP/wsc-bin"
mv "$RUNNER_TEMP/wsc" "$RUNNER_TEMP/wsc-bin/wsc"
echo "$RUNNER_TEMP/wsc-bin" >> "$GITHUB_PATH"
- name: Show wsc version
run: |
set -euo pipefail
which wsc
wsc --version
- name: Run end-to-end signing test
env:
SYNTH: ${{ github.workspace }}/target/release/synth
# WSC is set from PATH inside the script (via `command -v wsc`), but
# the script also accepts $WSC as an env override; pass it for
# belt-and-suspenders.
WSC: ${{ runner.temp }}/wsc-bin/wsc
run: |
set -euo pipefail
chmod +x ./tests/wsc_sign_e2e.sh
./tests/wsc_sign_e2e.sh
- name: Upload test artefacts on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: wsc-sign-e2e-artefacts
path: |
/tmp/wsc-sign-e2e.*/**
retention-days: 7
if-no-files-found: ignore