diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9dd554..3f42e27 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,8 @@ make typecheck # Type check with mypy make test # Run tests make cov # Run tests with coverage make perf # Check spec-generation performance budgets -make check-all # Offline gate: lint-workflows + check + test + security +make check # Static gate: lint (format + mypy once) + Bandit + workflow lints +make check-all # Offline gate: check + test, each gate exactly once make integration # Real Functions host + Azurite smoke, using free ports make docs # Strict documentation build, matching CI make wheel-smoke # Build and test an installed wheel outside the checkout diff --git a/Makefile b/Makefile index 3cd7fe5..c406015 100644 --- a/Makefile +++ b/Makefile @@ -106,11 +106,10 @@ security-development: security-browser: @$(SECURITY_PYTHON) -m tools.browser_integrity --output "$(SECURITY_OUTPUT)" -# `hatch run lint` is `style` followed by `typecheck`, so `check` is `lint`: a further -# `make typecheck` would run the type check a second time. +# `lint` already includes formatting and mypy; keep each static gate once. .PHONY: check -check: lint - @echo "Lint and type check passed." +check: lint security-bandit lint-workflows + @echo "Static checks passed including security and workflow lints." .PHONY: lint-workflows lint-workflows: ensure-hatch @@ -120,10 +119,8 @@ lint-workflows: ensure-hatch .PHONY: check-all check-all: ensure-hatch - @$(MAKE) lint-workflows @$(MAKE) check @$(MAKE) test - @$(MAKE) security @echo "All checks passed including tests and security scan." .PHONY: precommit diff --git a/docs/development.md b/docs/development.md index 84edfd0..aa133f7 100644 --- a/docs/development.md +++ b/docs/development.md @@ -144,8 +144,8 @@ Use these as the **golden commands** for local validation and CI parity. Prefer | `make e2e-local` | Run e2e tests against local Azurite on `:7071` | | `make e2e-azure` | Run e2e tests against Azure (`E2E_BASE_URL` required) | | `make lint-workflows` | Lint release workflows, action pins, and the Hatch matrix | -| `make check` | Run `make lint`, which includes the type check, once | -| `make check-all` | Offline gate: lint-workflows + check + test + security | +| `make check` | Static gate: lint (format and mypy once), Bandit scope, and workflow lints | +| `make check-all` | Offline gate: check + test, each gate exactly once | | `make verify` | Full local gate: check + test + integration + strict docs + wheel-smoke, in order, failing fast | | `make docs` | Build the MkDocs site with `mkdocs build --strict`, like the CI docs gate | | `make docs-serve` | Serve the docs locally with live reload | @@ -208,8 +208,9 @@ locally (`PIP_NO_INDEX=1 PIP_FIND_LINKS=/path/to/wheels`). Neither smoke uses Az `make verify` runs check, test, integration, strict docs, then wheel-smoke sequentially, stopping at the first failing lane even under `make -j`. -`make check-all` remains the offline gate (lint-workflows + check + test + -security), with dependencies already installed; it does not invoke host smoke, +`make check-all` remains the offline gate (`check` + `test`), with dependencies +already installed. `check` includes lint, Bandit and workflow lints exactly once; +the aggregate does not invoke host smoke, docs, or wheel installation. > For the full release workflow, see [Release Process](release_process.md). diff --git a/tests/test_make_contract.py b/tests/test_make_contract.py index 172cc33..7b2b4df 100644 --- a/tests/test_make_contract.py +++ b/tests/test_make_contract.py @@ -134,10 +134,11 @@ def test_each_check_runs_once(target: str, tests: int) -> None: assert runs == [1, 1, tests] -def test_check_all_keeps_every_gate_it_had() -> None: +@pytest.mark.parametrize("target", ["check", "check-all"]) +def test_checks_include_workflow_and_bandit_gates_once(target: str) -> None: gates = ("lint_release_workflows", "lint_workflow_pins", "lint_hatch_matrix", "bandit") - assert [plan("check-all").count(gate) for gate in gates] == [1, 1, 1, 1] + assert [plan(target).count(gate) for gate in gates] == [1, 1, 1, 1] def test_makefile_never_upgrades_pip() -> None: