diff --git a/.github/workflows/validate-branches.yml b/.github/workflows/validate-branches.yml index 1b30b99..7c606c6 100644 --- a/.github/workflows/validate-branches.yml +++ b/.github/workflows/validate-branches.yml @@ -57,6 +57,10 @@ jobs: node-version: '22' - name: Ensure base commit present run: git fetch --no-tags origin "$(node -e "console.log(require('./course-build/manifest.json').base.sha)")" || true + - name: Configure git identity (for git am) + run: | + git config user.name "acc-course-bot" + git config user.email "acc-course-bot@users.noreply.github.com" - name: Deterministic delta check (trees, assets, ancestry) run: node course-build/scripts/build-branches.mjs --check - name: Self-test (classification + path detection) @@ -69,6 +73,8 @@ jobs: echo "Buildable: $branches" # Secret scan of the delta store and everything the built branches would contain. + # Runs the gitleaks OSS binary directly rather than gitleaks/gitleaks-action@v2, + # which requires a paid GITLEAKS_LICENSE secret for organization repositories. secret-scan: runs-on: ubuntu-latest steps: @@ -77,10 +83,21 @@ jobs: fetch-depth: 0 ref: ${{ inputs.ref || github.ref }} - name: gitleaks (delta store + course-build) - uses: gitleaks/gitleaks-action@v2 env: - GITLEAKS_ENABLE_UPLOAD_ARTIFACT: 'false' - GITLEAKS_ENABLE_SUMMARY: 'true' + GITLEAKS_VERSION: '8.30.1' + # SHA256 of gitleaks_${VERSION}_linux_x64.tar.gz from the upstream + # gitleaks_${VERSION}_checksums.txt release asset. Bump both together on upgrade. + GITLEAKS_SHA256: '551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb' + run: | + set -euo pipefail + tarball="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" + curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${tarball}" -o /tmp/gitleaks.tar.gz + # Verify integrity before extracting/executing (pinned supply-chain check). + echo "${GITLEAKS_SHA256} /tmp/gitleaks.tar.gz" | sha256sum -c - + tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks + /tmp/gitleaks version + # Scan the full commit history (fetch-depth: 0). Exits non-zero on any finding. + /tmp/gitleaks git . --redact --verbose # Heavy gate: build each buildable learner branch from deltas and run the suites # that exist in that cumulative state (web / .NET / Java / Python / Playwright), @@ -117,6 +134,14 @@ jobs: run: | git config user.name "acc-course-bot" git config user.email "acc-course-bot@users.noreply.github.com" + - name: Provision /data volume for service DBs + # The services default their SQLite databases to /data/.db (overridable via + # *_DB_PATH), where /data is a mounted volume under docker compose. Bare `mvn test` + # / `dotnet test` / `pytest` on the runner have no such volume, so the Spring + # services abort at startup with "path to '/data/...': '/data' does not exist". + # Create it writable to mirror the runtime contract without touching learner-branch + # app files (which would change the delta-store tree SHAs verify-deltas asserts). + run: sudo mkdir -p /data && sudo chmod 777 /data - name: Build + validate ${{ matrix.start_branch }} run: bash course-build/scripts/validate-branch.sh "${{ matrix.start_branch }}" env: diff --git a/course-build/deltas/module-05/0001-feat-module-05-add-QR-barcode-support-QA-agent-resea.patch b/course-build/deltas/module-05/0001-feat-module-05-add-QR-barcode-support-QA-agent-resea.patch index b262338..f09435b 100644 --- a/course-build/deltas/module-05/0001-feat-module-05-add-QR-barcode-support-QA-agent-resea.patch +++ b/course-build/deltas/module-05/0001-feat-module-05-add-QR-barcode-support-QA-agent-resea.patch @@ -540,7 +540,7 @@ index 0000000..dee69bc + test('asset detail page shows an accessible QR code', async ({ page }) => { + // Land on the assets list and open the first asset's detail page. + await page.goto('/assets'); -+ const firstAsset = page.locator('a[href^="/assets/"]').first(); ++ const firstAsset = page.locator('tbody a[href^="/assets/"]').first(); + await firstAsset.click(); + + // The QR card heading and the accessible QR image are present. diff --git a/course-build/manifest.json b/course-build/manifest.json index efc4eb3..f3ce618 100644 --- a/course-build/manifest.json +++ b/course-build/manifest.json @@ -134,7 +134,7 @@ "patches": [ "0001-feat-module-05-add-QR-barcode-support-QA-agent-resea.patch" ], - "expectedTreeSha": "ba8126ae1414dbcc25cfed544071c848e33fcf1c", + "expectedTreeSha": "848992615da50a401c9db17da55840e5f6d93e67", "expectedAssets": [ ".github/agents/qa.agent.md", "reports/qr-code-research.md", @@ -156,7 +156,7 @@ "patches": [ "0001-feat-module-06-modernize-audit-svc-auth-svc-to-Sprin.patch" ], - "expectedTreeSha": "54a47a032fe12e6f9496040d93c6ed123c28f8b3", + "expectedTreeSha": "cb9a6a19492fa0b7d285685e875f1f03acfc27f7", "expectedAssets": [ ".github/lsp.json", ".github/agents/java-migrator.agent.md", diff --git a/course-build/scripts/validate-branch.sh b/course-build/scripts/validate-branch.sh index 5bbd2c7..fb672d4 100755 --- a/course-build/scripts/validate-branch.sh +++ b/course-build/scripts/validate-branch.sh @@ -77,8 +77,18 @@ echo "==> Java services build (all on Java 21; audit/auth target Java 17 bytecod echo "==> Python services install + pytest" for svc in reporting-svc notifications-svc; do if [ -f "services/$svc/pyproject.toml" ]; then - pip install -e "services/$svc" - if [ -d "services/$svc/tests" ]; then ( cd "services/$svc" && python -m pytest -q ); fi + # Early modules ship a tests/ dir containing only a README; real test files + # (test_*.py / *_test.py) appear from M03 onward. Only run pytest when they exist, + # otherwise just verify the service is installable. + if ls "services/$svc"/tests/test_*.py "services/$svc"/tests/*_test.py >/dev/null 2>&1; then + # Install the dev extra (pins pytest/pytest-asyncio) when declared, and guarantee + # pytest is importable so `python -m pytest` never fails with "No module named pytest". + pip install -e "services/$svc[dev]" + python -c "import pytest" 2>/dev/null || pip install pytest pytest-asyncio + ( cd "services/$svc" && python -m pytest -q ) + else + pip install -e "services/$svc" + fi fi done