ci: run lint + tests on GitHub Actions; make env fixture hermetic

Add a `test` workflow that runs `mise run verify` (ruff lint + pytest) on
every push and PR, dogfooding the same verify task the control layer's Stop
hook enforces — giving CI visibility into the suite.

Also clear HANDLER_SECRET_KEY and CLAUDE_BIN in the `env` test fixture. When
the suite runs inside a Handler-managed container these are set in the ambient
environment and leaked into tests asserting the unset behavior (secretstore
refusing without a key; login using the default `claude` binary), which then
failed. Clearing them (as the fixture already does for WEBHOOK_URL) keeps
behavior test-driven, not host-driven.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
tester
2026-07-24 02:41:24 +00:00
parent 2ca93a2bc9
commit dd9d913e63
2 changed files with 37 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
name: test
# Runs the linter and the full pytest suite for visibility on every push and PR.
# Dogfoods the repo's own mise tasks: `mise run verify` == lint (ruff) then test (pytest),
# the same `verify` task the control layer's Stop hook enforces on managed projects.
on:
push:
branches: ["**"]
tags: ["v*"]
pull_request:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# Installs the toolchain pinned in .mise.toml (Python 3.11).
- name: Set up mise
uses: jdx/mise-action@v2
# Dev extras carry pytest + respx + ruff; the package itself is installed editable so
# `pythonpath = ["src"]` in pyproject resolves the `handler` package under test.
- name: Install dependencies
run: pip install -e '.[dev]'
- name: Lint and test
run: mise run verify
+6
View File
@@ -33,6 +33,12 @@ def env(tmp_path, monkeypatch):
monkeypatch.setenv("SHARED_CONTEXT_WRITE_TOKEN", "shared-token")
monkeypatch.setenv("PROJECTS_ROOT", str(tmp_path / "projects"))
monkeypatch.delenv("WEBHOOK_URL", raising=False)
# Keep the fixture hermetic: when the suite runs inside a Handler-managed container
# (dogfooding), these are set in the ambient env and would leak into tests that assert
# the *unset* behavior — e.g. secretstore refusing without a key, or login using the
# default `claude` binary. Clear them so behavior is driven by each test, not the host.
monkeypatch.delenv("HANDLER_SECRET_KEY", raising=False)
monkeypatch.delenv("CLAUDE_BIN", raising=False)
_reset_caches()
cfg = Config(str(REPO_ROOT / "alembic.ini"))