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
name: CI
permissions:
contents: read
on:
push:
branches:
pull_request:
branches:
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
jobs:
quality-checks:
name: Quality Checks (${{ matrix.backend.name }})
runs-on: ubuntu-latest
services:
# Shared store for the rate-limit cross-instance reconciliation test.
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
strategy:
fail-fast: false
matrix:
backend:
# One leg per crypto backend, plus the build that links both: Cargo
# features are additive, so feature unification (and every tool that
# reaches for `--all-features`, docs.rs and cargo-semver-checks
# included) can produce that combination.
- name: rust_crypto
# Pure-Rust default backend (RustCrypto / rsa), with the binary
# (`cli` carries `redis`).
flags: "--features cli"
- name: aws_lc_rs
# Opt-in constant-time backend (aws-lc, C FFI); disables the default.
flags: "--no-default-features --features aws_lc_rs,redis"
- name: injected_verifier
# No built-in verifier at all: the build a consumer takes when it
# injects its own `hooks::TokenVerifier`. Links no JWT or TLS
# crypto (and so no `rsa`), which is only true as long as nothing
# outside the backend features reaches for jsonwebtoken or a
# rustls provider — this leg is what keeps that honest. The binary
# builds without a verifier too.
flags: "--no-default-features --features cli"
- name: all_features
# Both backends at once, the build cargo-semver-checks and docs.rs
# take. `aws_lc_rs` wins the tie; this leg keeps that wiring honest.
flags: "--all-features"
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
# Third-party action: pinned to a commit SHA (dependabot keeps it fresh).
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
# Runs each test in its own process, so a hang names the test that hung
# instead of timing the whole job out. Third-party action: pinned to a
# commit SHA (dependabot keeps it fresh).
- uses: taiki-e/install-action@94c31af3204a9f15ab40b35ad084410b905bbc73 # v2
with:
tool: cargo-nextest
- name: Format
if: matrix.backend.name == 'rust_crypto'
run: cargo fmt --all -- --check
# The default and injected-verifier builds are pure Rust: no C crypto
# (ring, aws-lc) on any target. The aws_lc_rs and all-features legs link
# aws-lc by choice.
- name: No C crypto
if: matrix.backend.name == 'rust_crypto' || matrix.backend.name == 'injected_verifier'
run: |
tree=$(cargo tree -e normal --target all --prefix none --format '{p}' ${{ matrix.backend.flags }})
if printf '%s\n' "$tree" | grep -E '^(ring|aws-lc-rs|aws-lc-sys) v'; then
echo "::error::C crypto is linked into the ${{ matrix.backend.name }} build"
exit 1
fi
# A build without a crypto backend (`default-features = false`, what a
# transcoding-only consumer takes) must pass an advisory scan without
# the ignores in deny.toml: none of the crates they cover is linked.
- name: No ignored advisories without a crypto backend
if: matrix.backend.name == 'injected_verifier'
run: |
tree=$(cargo tree -e normal --target all --prefix none --format '{p}' ${{ matrix.backend.flags }})
if printf '%s\n' "$tree" | grep -E '^(rsa|rustls-rustcrypto|paste) v|^rustls-webpki v0\.102\.'; then
echo "::error::the build without a crypto backend links a crate with an ignored advisory"
exit 1
fi
# `cargo add structured-proxy` takes the default features: the library
# must compile none of the binary's dependencies, which sit behind `cli`.
- name: No CLI dependencies by default
if: matrix.backend.name == 'rust_crypto'
run: |
tree=$(cargo tree -e normal --target all --prefix none --format '{p}')
if printf '%s\n' "$tree" | grep -E '^(clap|tracing-subscriber|redis) v'; then
echo "::error::the default build links a CLI-only dependency"
exit 1
fi
- name: Clippy
run: cargo clippy --all-targets ${{ matrix.backend.flags }}
- name: Build
run: cargo build --release ${{ matrix.backend.flags }}
- name: Test
env:
# Exercises the rate-limit reconciliation against the Redis service.
SHIELD_REDIS_TEST_URL: redis://127.0.0.1:6379/
run: cargo nextest run ${{ matrix.backend.flags }}
# nextest does not run doctests; cargo does.
- name: Doc tests
run: cargo test --doc ${{ matrix.backend.flags }}
# With `cli`, so the packaged crate's binary compiles too: without the
# feature cargo verifies the library alone.
- name: Publish dry-run
if: matrix.backend.name == 'rust_crypto'
run: cargo publish --dry-run --features cli
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
# Scans Cargo.lock for RustSec advisories; honors the ignore list in
# deny.toml. Third-party action: pinned to a commit SHA (dependabot
# keeps it fresh).
- uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1
with:
command: check advisories