@@ -14,7 +14,7 @@ permissions:
1414
1515concurrency :
1616 group : labs-pages-${{ github.ref }}
17- cancel-in-progress : false
17+ cancel-in-progress : true
1818
1919jobs :
2020 build :
@@ -24,21 +24,38 @@ jobs:
2424 working-directory : site
2525 steps :
2626 - name : Checkout
27- uses : actions/checkout@v4
27+ uses : actions/checkout@v7
2828 with :
2929 fetch-depth : 0
3030
3131 - name : Setup Node
32- uses : actions/setup-node@v4
32+ uses : actions/setup-node@v7
3333 with :
3434 node-version : " 24"
35+ check-latest : true
36+ package-manager-cache : false
3537
3638 - name : Install dependencies
3739 run : npm install --no-audit --no-fund
3840
3941 - name : Build Docusaurus and overlay existing labs
4042 run : npm run build:deploy
4143
44+ - name : Verify dynamic catalogue and favicon artifacts
45+ run : |
46+ test -f build/catalog/labs.json
47+ test -s build/favicon.ico
48+ node - <<'NODE'
49+ const fs = require('node:fs');
50+ const labs = JSON.parse(fs.readFileSync('build/catalog/labs.json', 'utf8'));
51+ if (!Array.isArray(labs)) throw new Error('build/catalog/labs.json must contain an array');
52+ const available = labs.filter((lab) => String(lab.status || '').toLowerCase() === 'available');
53+ if (!available.length) throw new Error('No available labs found in build/catalog/labs.json');
54+ console.log(`Verified ${available.length} available lab record(s) in the deployed catalogue artifact.`);
55+ NODE
56+ grep -q 'catalog/labs.json' build/index.html
57+ grep -q '/favicon.ico' build/index.html
58+
4259 - name : Enforce canonical Academy shell on every published HTML page
4360 run : |
4461 python3 - <<'PY'
@@ -112,17 +129,25 @@ jobs:
112129 needs : deploy
113130 runs-on : ubuntu-latest
114131 steps :
115- - name : Verify Labs production domain and representative routes
132+ - name : Verify Labs production domain, dynamic catalogue and representative routes
116133 run : |
117134 version='2026.08.15.2'
118135 for attempt in {1..30}; do
119136 home="$(curl --location --fail --silent --show-error --max-time 20 https://labs.skunkworksacademy.com/ || true)"
120137 legacy="$(curl --location --fail --silent --show-error --max-time 20 https://labs.skunkworksacademy.com/labs/bits-and-bytes-101/ || true)"
138+ catalogue="$(curl --location --fail --silent --show-error --max-time 20 https://labs.skunkworksacademy.com/catalog/labs.json || true)"
139+ favicon_ok=0
140+ curl --location --fail --silent --show-error --max-time 20 --output /dev/null https://labs.skunkworksacademy.com/favicon.ico && favicon_ok=1 || true
141+
121142 if printf '%s' "$home" | grep -q "academy-navigation.js?v=${version}" \
122143 && printf '%s' "$home" | grep -q "data-skunkworks-global-shell=\"${version}\"" \
144+ && printf '%s' "$home" | grep -q "catalog/labs.json" \
145+ && printf '%s' "$home" | grep -q "/favicon.ico" \
123146 && printf '%s' "$legacy" | grep -q "academy-navigation.js?v=${version}" \
124- && printf '%s' "$legacy" | grep -q "data-skunkworks-global-shell=\"${version}\""; then
125- echo 'Labs production verification succeeded on Docusaurus and legacy lab routes.'
147+ && printf '%s' "$legacy" | grep -q "data-skunkworks-global-shell=\"${version}\"" \
148+ && printf '%s' "$catalogue" | grep -q '"status": "available"' \
149+ && [ "$favicon_ok" -eq 1 ]; then
150+ echo 'Labs production verification succeeded for dynamic catalogue, favicon, Docusaurus shell and legacy lab route.'
126151 exit 0
127152 fi
128153 sleep 10
0 commit comments