-
Notifications
You must be signed in to change notification settings - Fork 1
268 lines (257 loc) · 10.2 KB
/
Copy pathci.yml
File metadata and controls
268 lines (257 loc) · 10.2 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
name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: npm
cache-dependency-path: |
backend/package-lock.json
frontend/package-lock.json
- name: Backend — install & typecheck
working-directory: backend
run: |
npm ci
npx tsc --noEmit
- name: Frontend — install & typecheck
working-directory: frontend
run: |
npm ci
npx tsc --noEmit
secret-scan:
name: Built-bundle secret scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Frontend — install & build
working-directory: frontend
run: |
npm ci
npm run build
# Fails the build if the Supabase service-role JWT (or its literal
# "role":"service_role" marker) ever lands in a shipped client bundle.
# The backend holds service-role; frontend never should. A bundler
# misconfig (e.g. an accidental `import` from a backend-only file, or
# a mis-named VITE_* env) would leak it silently without this gate.
- name: Scan dist/ for service-role markers
working-directory: frontend
run: |
set -euo pipefail
if grep -r -E '"role"\s*:\s*"service_role"|SUPABASE_SERVICE_ROLE_KEY' dist/; then
echo "::error::Frontend bundle contains a service-role marker. Refuse to ship."
exit 1
fi
echo "No service-role markers in frontend/dist."
content-lint:
name: Content lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: npm
cache-dependency-path: frontend/package-lock.json
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'
- name: Frontend — install & content-lint
working-directory: frontend
run: |
npm ci
npm run lint:content
solutions-pass:
name: Verify golden solutions
needs: content-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: npm
cache-dependency-path: frontend/package-lock.json
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'
- name: Frontend — install & verify solutions
working-directory: frontend
run: |
npm ci
npm run verify:solutions
test:
name: Test (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: npm
cache-dependency-path: |
backend/package-lock.json
frontend/package-lock.json
- name: Backend — install & test
working-directory: backend
run: |
npm ci
npm test
- name: Frontend — install & test
working-directory: frontend
run: |
npm ci
npm test
powershell:
name: PowerShell parse + lint
runs-on: windows-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Parse all .ps1 files
shell: pwsh
run: |
$failed = $false
Get-ChildItem -Recurse -File -Include *.ps1 | ForEach-Object {
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile(
$_.FullName, [ref]$null, [ref]$errors
) | Out-Null
if ($errors -and $errors.Count -gt 0) {
Write-Host "Parse errors in $($_.FullName):" -ForegroundColor Red
$errors | ForEach-Object { Write-Host " $_" }
$script:failed = $true
}
}
if ($failed) { exit 1 }
- name: PSScriptAnalyzer (errors only)
shell: pwsh
run: |
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser -SkipPublisherCheck
$results = Invoke-ScriptAnalyzer -Path . -Recurse -Severity Error
if ($results) {
$results | Format-Table -AutoSize
exit 1
}
Write-Host "No PSScriptAnalyzer errors."
shellcheck:
name: Shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install shellcheck
run: sudo apt-get update && sudo apt-get install -y shellcheck
- name: Run shellcheck
run: |
find . -type f -name "*.sh" \
-not -path "*/node_modules/*" \
-not -path "./temp/*" \
-print0 | xargs -0 --no-run-if-empty shellcheck --severity=warning
cloud-init-drift:
# I-4 (bucket 7): cloud-init.yaml is consumed by Azure *once* per VM
# provision — after first boot, the live VM runs copies of those scripts
# from /usr/local/bin/ and /etc/systemd/system/ that never re-sync from
# the repo. So a PR editing cloud-init.yaml does nothing to production
# unless someone SSHes in and applies the diff manually, or the VM is
# re-provisioned. Surface that as an explicit warning so the next
# reviewer doesn't assume the deploy pipeline will propagate it.
#
# Also shellcheck the embedded refresh-env script — cloud-init.yaml
# ships shell-in-YAML that the main shellcheck job's `*.sh` glob misses.
name: Cloud-init drift warning
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Warn on cloud-init.yaml edits
run: |
set -euo pipefail
base="${{ github.event.pull_request.base.sha }}"
if git diff --name-only "$base"...HEAD | grep -qE '^infra/azure/cloud-init\.yaml$'; then
echo "::warning file=infra/azure/cloud-init.yaml::cloud-init.yaml changed in this PR. Most cloud-init contents (systemd units, runcmd, cert-expiry-check, /etc/codetutor/env.conf) are still consumed only at first-boot, so the live VM does not pick them up automatically. refresh-env IS deploy-synced from infra/scripts/refresh-env.sh, so changes there land on every deploy. For other edits, plan a VM reprovision or apply manually via SSH/az run-command."
else
echo "cloud-init.yaml unchanged in this PR."
fi
- name: Install shellcheck
run: sudo apt-get update && sudo apt-get install -y shellcheck
- name: Shellcheck refresh-env script
# refresh-env was extracted from cloud-init.yaml's inline write_files
# into infra/scripts/refresh-env.sh on 2026-04-29 to close the drift
# gap (live VM no longer froze the script at first-boot). The main
# shellcheck job picks this up via its `*.sh` glob, but linting it
# explicitly here guards against accidentally renaming/relocating it
# in a way that would silently bypass the canonical-source contract.
run: |
set -euo pipefail
if [ ! -f infra/scripts/refresh-env.sh ]; then
echo "::error::infra/scripts/refresh-env.sh missing — this is the canonical source consumed by both first-boot (cloud-init.yaml) and every deploy (vm-deploy-backend.sh). Restore it or update both touchpoints."
exit 1
fi
shellcheck --severity=warning infra/scripts/refresh-env.sh
line-endings:
name: Line-endings (Windows checkout)
runs-on: windows-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: .sh files must be LF
shell: pwsh
run: |
$failed = @()
Get-ChildItem -Recurse -File -Include *.sh |
Where-Object { $_.FullName -notmatch "node_modules" } |
ForEach-Object {
$bytes = [System.IO.File]::ReadAllBytes($_.FullName)
if (($bytes | Where-Object { $_ -eq 13 }).Count -gt 0) {
$failed += $_.FullName
}
}
if ($failed) {
Write-Host ".sh files with CR bytes (expected LF only):" -ForegroundColor Red
$failed | ForEach-Object { Write-Host " $_" }
exit 1
}
Write-Host "All .sh files are LF."
- name: .ps1 files must be CRLF
shell: pwsh
run: |
$failed = @()
Get-ChildItem -Recurse -File -Include *.ps1 |
Where-Object { $_.FullName -notmatch "node_modules" } |
ForEach-Object {
$bytes = [System.IO.File]::ReadAllBytes($_.FullName)
$cr = ($bytes | Where-Object { $_ -eq 13 }).Count
$lf = ($bytes | Where-Object { $_ -eq 10 }).Count
if ($lf -gt 0 -and $cr -ne $lf) {
$failed += $_.FullName
}
}
if ($failed) {
Write-Host ".ps1 files missing CRLF line endings:" -ForegroundColor Red
$failed | ForEach-Object { Write-Host " $_" }
exit 1
}
Write-Host "All .ps1 files are CRLF."