Skip to content

feat: ship v8.93 signed Compose blueprint catalog #635

feat: ship v8.93 signed Compose blueprint catalog

feat: ship v8.93 signed Compose blueprint catalog #635

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test-and-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Check for critical vulnerabilities (production deps only)
# npm's retired Quick Audit fallback can reject a valid lockfile when the
# Bulk Advisory endpoint returns invalid data. Use Google's first-party
# OSV scanner instead, pinned and checksum-verified for reproducibility.
# The validator preserves the existing policy: dev-only findings are
# excluded and only production findings with CVSS >= 9.0 fail the build.
env:
OSV_VERSION: '2.3.8'
OSV_LINUX_AMD64_SHA256: 'bc98e15319ed0d515e3f9235287ba53cdc5535d576d24fd573978ecfe9ab92dc'
run: |
curl --fail --silent --show-error --location \
"https://github.com/google/osv-scanner/releases/download/v${OSV_VERSION}/osv-scanner_linux_amd64" \
--output /tmp/osv-scanner
echo "${OSV_LINUX_AMD64_SHA256} /tmp/osv-scanner" | sha256sum --check --strict
chmod +x /tmp/osv-scanner
set +e
/tmp/osv-scanner scan source \
--lockfile package-lock.json \
--format json \
--verbosity error \
--output-file /tmp/osv-results.json
SCAN_STATUS=$?
set -e
# OSV returns 1 when it found vulnerabilities. Other non-zero exit
# codes represent scanner/input failures and must not be suppressed.
if [ "$SCAN_STATUS" -ne 0 ] && [ "$SCAN_STATUS" -ne 1 ]; then
exit "$SCAN_STATUS"
fi
node scripts/check-osv-results.js /tmp/osv-results.json 9
- name: Validate JavaScript syntax (backend)
run: |
echo "Checking backend JS files..."
find src -name '*.js' -not -path '*__tests__*' -exec node --check {} \;
echo "All backend files OK"
- name: Validate JavaScript syntax (frontend)
run: |
echo "Checking frontend JS files..."
for f in public/js/*.js public/js/pages/*.js public/js/components/*.js public/js/i18n/*.js; do
node --check "$f" || exit 1
done
echo "All frontend files OK"
- name: Lint (ESLint)
# v7.7.0: enforce 0 warnings / 0 errors. CONTRIBUTING.md tells contributors
# `npm run lint` must be clean — without this step, that promise was on the honor system.
run: npm run lint
- name: Run tests
id: tests
run: |
# Capture Jest output, extract counts, and expose as step outputs so
# the Summary step below can report accurate numbers instead of a
# hardcoded string that rotted across releases pre-v6.15.0.
set -o pipefail
npm test 2>&1 | tee /tmp/jest.out
TEST_LINE=$(grep -oE 'Tests:\s+.*(passed|skipped|failed)' /tmp/jest.out | tail -1 || echo "")
PASSED=$(echo "$TEST_LINE" | grep -oE '[0-9]+ passed' | head -1 | grep -oE '[0-9]+' || echo "0")
SKIPPED=$(echo "$TEST_LINE" | grep -oE '[0-9]+ skipped' | head -1 | grep -oE '[0-9]+' || echo "0")
echo "passed=$PASSED" >> "$GITHUB_OUTPUT"
echo "skipped=$SKIPPED" >> "$GITHUB_OUTPUT"
env:
APP_SECRET: ci-test-secret-key-not-for-production
ENCRYPTION_KEY: ci-test-encryption-key-32-chars-min
APP_ENV: test
# v6.9.2: live Cloudflare smoke test. Skipped when secret absent.
# Provision: Repo Settings → Secrets → Actions → CLOUDFLARE_TEST_TOKEN
# (scoped token, `User:Read` only — no Zone or DNS permissions needed).
CLOUDFLARE_TEST_TOKEN: ${{ secrets.CLOUDFLARE_TEST_TOKEN }}
- name: Validate i18n completeness
run: |
node -e "
global.window = {};
global.localStorage = { getItem: ()=>null, setItem: ()=>{} };
eval(require('fs').readFileSync('public/js/i18n.js', 'utf8'));
const i18n = window.i18n;
const langFiles = require('fs').readdirSync('public/js/i18n')
.filter(f => f.endsWith('.js') && f !== 'TEMPLATE.js');
for (const f of langFiles) {
eval(require('fs').readFileSync('public/js/i18n/' + f, 'utf8'));
}
console.log('Languages:', i18n.languages.map(l => l.code).join(', '));
const enKeys = JSON.stringify(i18n._translations.en).match(/\"[^\"]+\":/g)?.length || 0;
console.log('EN keys: ~' + enKeys);
if (enKeys < 100) { console.error('ERROR: EN translation seems incomplete'); process.exit(1); }
console.log('i18n validation passed');
"
- name: Validate self-service localization safety copy
run: npm run check:self-service-i18n
- name: Validate self-service accessibility contract
run: npm run check:self-service-a11y
- name: Validate virtualization research registry
run: npm run check:virtualization-research
- name: Summary
if: always()
run: |
echo "### CI Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Node.js syntax: ✅ (backend + frontend)" >> $GITHUB_STEP_SUMMARY
echo "- Lint (ESLint): ✅" >> $GITHUB_STEP_SUMMARY
echo "- Tests: ✅ (${{ steps.tests.outputs.passed || 'unknown' }} passed, ${{ steps.tests.outputs.skipped || '0' }} skipped — 100% passing)" >> $GITHUB_STEP_SUMMARY
echo "- Security audit: ✅" >> $GITHUB_STEP_SUMMARY
echo "- i18n: ✅ (11 languages)" >> $GITHUB_STEP_SUMMARY
echo "- Dependencies: installed" >> $GITHUB_STEP_SUMMARY