feat(spa): detail page opens read-only details by default (#682) + 1.13.0 #176
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
| # CI test gate — run the test suites on every pull request and on push to | |
| # `main`, so a red suite can't merge. | |
| # | |
| # WHY: until now the lint/test pipeline was local-only — `scripts/lint.sh` | |
| # + the pre-commit hooks, run on a contributor's laptop before the Merger | |
| # pulled a PR (the deliberate "no CI in pre-alpha" posture). With many | |
| # agents merging in parallel and only CodeQL gating server-side, test | |
| # regressions slipped onto `main` green (e.g. #401 broke | |
| # `tests/test_logentry.py`, undetected until a later full local run — | |
| # #451). This enforces the suites server-side. Resolves the core of #452 | |
| # (run the test suites in CI); the no-CI revisit is recorded in | |
| # `SECURITY.md` §8 / `docs/agents/decisions.md` / OQ-A-001. | |
| # | |
| # SCOPE: the backend job runs the Python lint gate (ruff check + ruff | |
| # format --check + mypy + bandit) and then `pytest`. The frontend job | |
| # runs the full `pnpm` gate — typecheck + lint + test + build. The Python | |
| # lint stack was collapsed onto a single Ruff-based chain in #651/#652 | |
| # (black/isort/flake8 removed), which made the gate satisfiable on a | |
| # clean tree and let it be wired in here. | |
| # | |
| # SECURITY POSTURE: | |
| # - Least-privilege: top-level `contents: read`; no job needs write. | |
| # - All third-party actions are pinned to a full commit SHA (a tag can | |
| # be moved, a SHA cannot) — consistent with codeql.yml / publish.yml | |
| # and the supply-chain hardening in #331. | |
| # - This is a *gate*, not a publisher: it has no access to PyPI, no | |
| # `id-token`, and no stored secrets. | |
| # | |
| # NOTE: making these checks *required* (branch protection) is a separate | |
| # owner action in repo Settings → Branches — see #452 / #331. | |
| name: ci | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| # A newer push to the same ref supersedes an in-flight run — don't burn | |
| # minutes finishing a run whose commit is already stale. | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| backend: | |
| name: Backend (pytest py${{ matrix.python }} / Django ${{ matrix.django }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Django 4.2 LTS is supported through April 2026 (#622). Add it | |
| # alongside 5.x and 6.0 so the package keeps working for the | |
| # majority of installed Django by deployment count. | |
| python: ["3.12"] | |
| django: ["4.2", "5.2"] | |
| # 4.2 added Python 3.13 support in 4.2.16 but pip may resolve to | |
| # an earlier 4.2.x; skip 3.13 + 4.2 conservatively. (We only | |
| # exercise py3.12 here today; the matrix is set up for an easy | |
| # future expansion.) | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Set up Python | |
| uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Install Poetry | |
| # Poetry is pinned to the version that generated poetry.lock (see | |
| # its header). `poetry install` compares the lock's content-hash | |
| # against the one it computes from pyproject; a different Poetry | |
| # can compute it differently and reject an otherwise-valid lock. | |
| # Bump this in lockstep whenever the lock is regenerated. | |
| run: pipx install poetry==2.1.4 | |
| - name: Install dependencies (locked) | |
| run: poetry install --no-interaction | |
| - name: Pin Django to the matrix version | |
| run: poetry run pip install "django~=${{ matrix.django }}.0" | |
| # Python lint gate (#651/#652): a single Ruff-based stack — | |
| # ruff check (lint, incl. `I` import order) + ruff format --check + | |
| # mypy (strict subset on the package) + bandit (security). Black, | |
| # standalone isort, and flake8 were removed. This is the same gate | |
| # scripts/lint.sh runs locally. | |
| - name: Lint (ruff + mypy + bandit) | |
| run: | | |
| poetry run ruff check django_admin_react tests | |
| poetry run ruff format --check django_admin_react tests | |
| poetry run mypy django_admin_react | |
| poetry run bandit -r django_admin_react -c pyproject.toml -q | |
| # pytest with coverage (per pyproject `addopts`), including | |
| # tests/test_security.py. `filterwarnings = ["error"]` means a new | |
| # warning fails the run. | |
| - name: Tests (pytest) | |
| run: poetry run pytest | |
| frontend: | |
| name: Frontend (typecheck + lint + test + build) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Set up pnpm | |
| uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 | |
| with: | |
| version: 9 | |
| - name: Set up Node | |
| uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: frontend/pnpm-lock.yaml | |
| - name: Install dependencies (frozen lockfile) | |
| run: pnpm install --frozen-lockfile | |
| - name: Typecheck (tsc --noEmit, every package) | |
| run: pnpm -r typecheck | |
| - name: Lint (eslint --max-warnings 0 + stylelint + dark-mode coverage) | |
| run: pnpm lint | |
| - name: Unit tests (vitest) | |
| run: pnpm test | |
| - name: Build (Vite bundle, every package) | |
| run: pnpm -r build |