Repository navigation
213 lines (187 loc) · 9.09 KB
/
Copy pathci.yml
File metadata and controls
213 lines (187 loc) · 9.09 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
# Source Kit 0.1.0 — five gates every push runs
# Written with AI assistance. Verification: docs/PROVENANCE.md.
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
test-suites:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
- name: Install ffmpeg (media fixtures)
run: sudo apt-get update && sudo apt-get install -y ffmpeg
- name: Install c2patool 0.14.0 (independent verifier)
# The binary below is the independent oracle for every claim this
# suite makes — it is downloaded, never built here, so its bytes
# are pinned: sha256 of the exact release tarball, verified BEFORE
# extraction. Bumping c2patool means updating both numbers.
env:
C2PATOOL_SHA256: c635061cb38d32710f5033ceae61f31fd06c7ced1486a18c7ffa2b8fea726592
run: |
curl -sL -o c2patool.tar.gz \
https://github.com/contentauth/c2pa-rs/releases/download/c2patool-v0.14.0/c2patool-v0.14.0-x86_64-unknown-linux-gnu.tar.gz
echo "$C2PATOOL_SHA256 c2patool.tar.gz" | sha256sum -c -
tar xzf c2patool.tar.gz
chmod +x c2patool/c2patool
./c2patool/c2patool --version
echo "C2PATOOL=$PWD/c2patool/c2patool" >> "$GITHUB_ENV"
- name: Stage the validation lab
run: node tests/stage.mjs
- name: Install staged dependencies (exact versions)
# The staged lab is generated by tests/stage.mjs and carries no
# committed lockfile — generate it from the staged package.json
# (every dep pinned exactly there), then let npm ci enforce it.
run: npm install --package-lock-only --no-audit --no-fund && npm ci --no-audit --no-fund
working-directory: tests/.staged
- name: Every suite
# tests/run-all.mjs discovers test-*.mts in the staged lab, so a new
# suite runs with nothing to add here. It prints one tally and exits
# non-zero if any suite does.
run: node tests/run-all.mjs
app-typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
- name: Stage the app core (real code + device shims)
run: node tests/stage.mjs
- name: Install staged dependencies
run: npm install --package-lock-only --no-audit --no-fund && npm ci --no-audit --no-fund
working-directory: tests/.staged
- name: Typecheck the staged tree (strict)
# The staged lab is the app's real shipped code with device services
# rewired to shims, so that is what gets typechecked.
run: |
npm install --no-save --no-audit --no-fund typescript@5.6.3 @types/node@20.14.0
./node_modules/.bin/tsc --noEmit --strict --skipLibCheck \
--target ES2022 --lib ES2022,DOM,DOM.Iterable \
--module ESNext --moduleResolution bundler \
--allowImportingTsExtensions --resolveJsonModule \
$(ls *.mts | grep -v -E '^(test|tool|build)-')
working-directory: tests/.staged
- name: Typecheck the app (strict, tsconfig.json)
# Screens and components, against the versions the lockfile pins.
# --legacy-peer-deps because the lockfile was generated with it.
run: |
npm ci --legacy-peer-deps --no-audit --no-fund
npx tsc --noEmit -p tsconfig.json
ios-build:
# The Swift gate. Nothing else in this workflow runs a Swift compiler, so
# without this job a type error, a bad selector, or a renamed API in
# modules/ reaches a device build and never reaches CI.
#
# It compiles for the simulator, which typechecks every module against the
# iOS SDK. Multi-cam capture itself needs real hardware and is covered by
# the on-device soak run, not here. macOS runners are free on public
# repositories, so this runs on every change rather than behind a filter:
# a gate that can be skipped is a gate that gets skipped.
# macos-15 carries exactly two Xcodes, 26.0.1 and 26.3, and the Expo pod
# chain needs one between them: 26.0.1 rejects its `weak let`, 26.3 cannot
# infer a type in its date coding. A newer image carries a newer set.
runs-on: macos-26
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
- name: Select the Xcode that EAS builds with
# Pinned to the toolchain the shipping build uses, so this gate and the
# real build cannot drift. Not "newest": Swift's type checker changed
# between 26.0.1, 26.3, and 26.6, and each version breaks a different
# part of the Expo pod chain. Matching EAS is the only version known to
# compile the whole tree.
#
# If the image stops carrying it, this fails loudly rather than
# silently building with something else. Update both sides together.
env:
EAS_XCODE: '26.6'
run: |
set -euo pipefail
echo "Xcodes on this image:"
ls -d /Applications/Xcode*.app
APP="/Applications/Xcode_${EAS_XCODE}.app"
if [ ! -d "$APP" ]; then
echo "Xcode ${EAS_XCODE} is not on this image. EAS builds with it, so" >&2
echo "building with anything else would not prove what ships." >&2
exit 1
fi
sudo xcode-select -s "$APP"
xcodebuild -version
swift --version
- name: Install
run: npm ci --legacy-peer-deps --no-audit --no-fund
- name: Fetch the C2PAC xcframework
# Not committed. The script checks the download against the SHA-256
# upstream pins in c2pa-swift's own Package.swift before unpacking.
run: ./scripts/fetch-c2pa-framework.sh
- name: Generate the iOS project
# ios/ is not committed either; prebuild writes it from app.json and
# the local modules, which is what a real build does.
run: npx expo prebuild --platform ios --no-install
- name: Install pods
run: pod install
working-directory: ios
- name: Compile the local Swift modules
# The gate compiles OUR modules, not the whole app. Building the app
# drags in every upstream pod, and expo-modules-jsi does not compile
# on either Xcode these images carry — too old for `weak let`, too new
# for its own type inference. That is an upstream problem and it is
# not what this job exists to catch.
#
# Each local module is a pod target, so they can be built directly
# against the SDK and ExpoModulesCore. A type error, a bad selector,
# or a renamed API under modules/ fails here.
run: |
set -euo pipefail
echo "Xcodes on this image:"; ls -d /Applications/Xcode*.app
xcodebuild -version
xcodebuild -project ios/Pods/Pods.xcodeproj -list || true
for T in ExhibitCamera CaptureKit C2paIos SecureEnclave AudioCapture WifiInfo; do
echo "::group::$T"
xcodebuild build \
-project ios/Pods/Pods.xcodeproj \
-target "$T" \
-configuration Debug \
-sdk iphonesimulator \
CODE_SIGNING_ALLOWED=NO \
ONLY_ACTIVE_ARCH=NO
echo "::endgroup::"
done
dead-code:
# Catches the class no compiler and no test reaches: a module nothing
# imports. A component wired to a Settings toggle but rendered by nothing
# typechecks, passes every suite, and does nothing — this is what names it.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
- name: Install
run: npm ci --legacy-peer-deps --no-audit --no-fund
- name: Unreferenced files
# knip.json lists the real entry points: expo-router screens, the
# scripts, and every module tests/stage.mjs copies into
# the lab (the lab copies rather than imports, so knip cannot see
# that reach on its own). Anything outside that graph is unreachable.
run: npx knip --include files
supply-chain:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
- name: Dependency budget (allow-list + caps + lockfiles)
run: node scripts/check-dependency-budget.mjs
- name: Audit gate — app
# Every high or critical advisory fails unless it is declared in the
# script with the reason it cannot reach the shipped app.
run: node scripts/check-audit.mjs .