fix(e2e): python-multi-file-smoke completion test missed Check My Wor… #183
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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." |