Repository navigation
275 lines (266 loc) · 11.3 KB
/
Copy pathrust.yml
File metadata and controls
275 lines (266 loc) · 11.3 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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# envrypt CI. The project is a single publishable **library** crate (`envrypt`) — no
# CLI, no binary, no packaging. This workflow gates fmt/clippy, the workspace test
# suite (+ doctests + examples), the self-contained conformance corpus (checked-in
# spec cases and frozen crypto/interop vectors), and the positive-allowlist
# dependency budget.
name: rust
on:
push:
branches: [main]
paths:
- 'Cargo.toml'
- 'Cargo.lock'
- 'crates/**'
- 'conformance/**'
- 'rustfmt.toml'
- 'clippy.toml'
- '.github/workflows/rust.yml'
pull_request:
paths:
- 'Cargo.toml'
- 'Cargo.lock'
- 'crates/**'
- 'conformance/**'
- 'rustfmt.toml'
- 'clippy.toml'
- '.github/workflows/rust.yml'
permissions:
contents: read
concurrency:
group: rust-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# Fast gate: format, lint (warnings are errors), the full test suite, doctests,
# examples, and a bench build-check.
test:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 (2025-11-13)
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master (2026-07-16)
with:
toolchain: 1.97.1
components: rustfmt, clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 (2026-03-12)
- name: rustfmt
run: cargo fmt --all --check
- name: clippy (all targets, all features, deny warnings)
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
# Network-off unit tests (#68): run the test binaries inside a network
# namespace with only loopback up, so any real outbound call fails while
# localhost fixture servers still work — the compiled-language equivalent
# of the JS/TS `nock.disableNetConnect()` gate. Deps are pre-fetched online
# first; the sandbox only wraps the test *run*. Fail-closed: if no namespace
# can be created the job errors, never silently runs tests with the network
# up. See docs/agents.md/fleet/no-live-network-in-tests.md.
- name: prepare + verify network-off sandbox
run: |
set -euo pipefail
# Ubuntu 24.04 restricts unprivileged user namespaces via AppArmor;
# relax it on this ephemeral runner (passwordless sudo is present).
if [ -e /proc/sys/kernel/apparmor_restrict_unprivileged_userns ]; then
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 >/dev/null 2>&1 || true
fi
if ! unshare --map-root-user --net true 2>/dev/null; then
echo "::error::network-off: unprivileged net namespace unavailable on this runner; refusing to run tests with the network up." >&2
exit 1
fi
cat > "${RUNNER_TEMP}/run-offline.sh" <<'OFFLINE'
#!/usr/bin/env bash
# Run "$@" with external network disabled — fresh net namespace, loopback
# only. Loopback is up so localhost fixture servers work; there is no
# route off-box, so any real outbound call fails.
set -euo pipefail
exec unshare --map-root-user --net -- \
bash -c 'ip link set lo up 2>/dev/null || true; exec "$@"' _ "$@"
OFFLINE
chmod +x "${RUNNER_TEMP}/run-offline.sh"
# Prove the sandbox actually blocks egress before trusting it: a reach
# to a public host MUST fail inside the namespace.
if "${RUNNER_TEMP}/run-offline.sh" timeout 5 curl -sS -o /dev/null https://example.com 2>/dev/null; then
echo "::error::network-off self-check: reached example.com inside the sandbox — egress is NOT blocked." >&2
exit 1
fi
echo "network-off: verified — egress blocked, loopback available."
- name: pre-fetch deps (online, before the sandbox)
run: cargo fetch --locked
- name: test (workspace, all features — network-off)
run: '"${RUNNER_TEMP}/run-offline.sh" cargo test --workspace --all-features --offline'
- name: doctests (network-off)
run: '"${RUNNER_TEMP}/run-offline.sh" cargo test --doc -p envrypt --offline'
- name: examples build
run: cargo build --examples -p envrypt
- name: bench build (cargo bench --no-run, default features)
run: cargo bench --no-run -p envrypt
# Cross-platform compile gate: the envrypt LIBRARY must build on Windows. Every
# unix-only path — sockeye pipe IPC (fork/pipe/from_raw_fd), fsio permission
# bits, the unix keychain backends, and unix shell exec — is cfg(unix)-gated
# with a cfg(windows)/cfg(not(unix)) counterpart. This job keeps that gating
# honest: a newly-added ungated unix API fails the Windows build here instead of
# shipping a crate that only compiles on unix. Compile-only (no test run — the
# sockeye test harness uses raw unix syscalls under #[cfg(test)]).
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 (2025-11-13)
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master (2026-07-16)
with:
toolchain: 1.97.1
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 (2026-03-12)
- name: cargo check (envrypt library, all features, windows-msvc)
run: cargo check -p envrypt --all-features
# Library-level parse conformance: the tier-1 spec corpus (88 spec cases) + the
# case-28 encoding slice, asserted through envrypt's parse pipeline. The corpus is
# fully checked in and self-contained; frozen crypto/interop vector checks run in
# the `test` job's `cargo test --workspace` (crates/envrypt/tests).
conformance:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 (2025-11-13)
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master (2026-07-16)
with:
toolchain: 1.97.1
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 (2026-03-12)
- name: tier-1 spec + case-28 parse conformance (no binary)
run: cargo test -p envrypt-conformance
# Dependency-budget gate for the `envrypt` library default features, run as a
# POSITIVE ALLOWLIST: `cargo tree -e normal` must contain ONLY the audited
# pure-Rust set, so any NEW crate (including a missed device-store dep) fails the
# build, not just the named banlist. The banlist stays as a secondary
# belt-and-suspenders assertion.
deps:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 (2025-11-13)
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master (2026-07-16)
with:
toolchain: 1.97.1
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 (2026-03-12)
- name: positive allowlist — envrypt default-features tree is the audited set only
run: |
set -euo pipefail
# The audited pure-Rust dependency set (linux/default features). ADD a crate
# here only after auditing it (no HTTP/async/openssl/CLI machinery).
# v3 value-format crypto (docs/envrypt/crypto-v3.md) adds: argon2 (+blake2,
# Argon2id KDF), chacha20poly1305 (+chacha20/poly1305, XChaCha20 AEAD),
# x25519-dalek (+curve25519-dalek and its derive), and the zeroize derive
# closure (zeroize_derive → proc-macro2/quote/syn/unicode-ident, compile-time
# proc-macros for secret zeroization) — all RustCrypto/dalek, pure Rust.
cat > /tmp/allow.txt <<'EOF'
aead
aes
aes-gcm
aho-corasick
argon2
base16ct
base64ct
bit-set
bit-vec
blake2
block-buffer
cfg-if
chacha20
chacha20poly1305
cipher
const-oid
cpufeatures
crypto-bigint
crypto-common
ctr
curve25519-dalek
curve25519-dalek-derive
der
digest
elliptic-curve
envrypt
equivalent
fancy-regex
ff
generic-array
getrandom
ghash
group
hashbrown
hkdf
hmac
indexmap
inout
itoa
k256
libc
memchr
opaque-debug
password-hash
pbkdf2
poly1305
polyval
proc-macro2
quote
rand_core
regex
regex-automata
regex-syntax
salsa20
scrypt
sec1
serde_core
serde_json
sha2
subtle
syn
typenum
unicode-ident
universal-hash
x25519-dalek
zeroize
zeroize_derive
zmij
EOF
# The heredoc preserves the YAML indentation, so trim to bare crate names.
awk 'NF{print $1}' /tmp/allow.txt | sort -u > /tmp/allow.sorted && mv /tmp/allow.sorted /tmp/allow.txt
cargo tree -e normal -p envrypt --prefix none \
| awk '{print $1}' | grep -vE '^$' | sort -u > /tmp/tree.txt
echo "=== envrypt -e normal tree ==="; cat /tmp/tree.txt
extra=$(comm -23 /tmp/tree.txt /tmp/allow.txt || true)
if [ -n "$extra" ]; then
echo "::error::envrypt pulled crate(s) not on the audited allowlist:"
echo "$extra"
echo "audit the crate, then add it to the allowlist in .github/workflows/rust.yml"
exit 1
fi
echo "OK — every envrypt dependency is on the audited allowlist"
- name: banlist (secondary) — no CLI/HTTP/async/device-store crates
run: |
set -euo pipefail
tree=$(cargo tree -e normal -p envrypt)
# openssl-sys/tokio/reqwest/hyper (HTTP/async); clap/signal-hook/nix/portable-pty
# (CLI); cbc (the dropped device-store cipher). aes/cipher/pbkdf2 remain as
# audited TRANSITIVE deps of aes-gcm/scrypt, so they are NOT banned by name.
if echo "$tree" | grep -Eiq '(^|[^-])openssl-sys|(^|[^-])tokio |reqwest|hyper |(^|[^-])clap |signal-hook|(^|[^-])nix |portable-pty|(^|[^-])cbc '; then
echo "::error::envrypt pulled a banned CLI/HTTP/async/device-store crate"
echo "$tree" | grep -Ei 'openssl-sys|tokio|reqwest|hyper|clap|signal-hook|nix|portable-pty|cbc'
exit 1
fi
echo "no banned crates in the envrypt default-features tree"
- name: no openssl-sys anywhere (incl. dev/build deps)
run: |
full=$(cargo tree --workspace --all-features -e normal,build,dev)
if echo "$full" | grep -iq 'openssl-sys'; then
echo "::error::openssl-sys present in the dependency graph (pure-Rust crypto only)"
echo "$full" | grep -i 'openssl'
exit 1
fi
echo "no openssl-sys in the workspace graph"