mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 18:16:25 +00:00
feat(phase-2): forge integration — credentials, role skills, approval gate, CI poller
Phase 2 configures forge for the agents (operator only sets a credential_ref + optional version pin) and lets them drive a junior→senior→deploy workflow: - Credential resolution/injection (control/credentials.py): credential_ref pointers (env:/file:/cmd:) resolved only at spawn, injected as FORGE_TOKEN + host var, with a forge-host-scoped git credential helper reading the token from env (never on disk / in the DB). Resolution is a fail-fast spawn gate. - Role-based forge skills committed into the managed repo (control/skills_gen.py, `handler forge-init`): forge-junior/senior/deploy + a workflow overview. - Hard approval gate (hooks/gate.py, approvals table, migration 0002): merge/deploy — and direct pushes to protected branches — are denied unless a DIFFERENT agent has an `approved` record for the branch, pinned to the reviewed commit (approved_sha). Senior records verdicts via `handler approve`/`reject`. - forge/git seams (control/forge.py, control/gitops.py) matching the Phase 1 seam pattern. - CI status poller (control/poller.py, `handler poll-ci [--watch]`) backfilling ci_status/ci_checked_at via `forge ci list`. - Fix: migrations/env.py commits explicitly after run_migrations — pysqlite on Py 3.12+ was rolling back the final migration's DDL + alembic_version stamp (latent in Phase 1). Reviewed via a separate code-reviewer pass; gate-bypass and credential-scoping findings addressed. 106 tests, ruff clean, verified end-to-end against real git + migrations.
This commit is contained in:
@@ -105,3 +105,45 @@ def fake_tmux(monkeypatch):
|
||||
monkeypatch.setattr(tmux, "list_sessions", list_sessions)
|
||||
|
||||
return {"calls": calls, "live": live}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_gitops(monkeypatch):
|
||||
"""Fake the git seam: record config/add/commit, return a controllable branch/sha."""
|
||||
from handler.control import gitops
|
||||
|
||||
state = {"branch": "feat/x", "sha": "abc123def456", "config": [], "add": [], "commit": []}
|
||||
|
||||
def config_local(cwd, key, value):
|
||||
state["config"].append({"cwd": cwd, "key": key, "value": value})
|
||||
return True, ""
|
||||
|
||||
def add(cwd, paths):
|
||||
state["add"].append({"cwd": cwd, "paths": paths})
|
||||
return True, ""
|
||||
|
||||
def commit(cwd, message):
|
||||
state["commit"].append({"cwd": cwd, "message": message})
|
||||
return True, ""
|
||||
|
||||
monkeypatch.setattr(gitops, "current_branch", lambda cwd: state["branch"])
|
||||
monkeypatch.setattr(gitops, "head_sha", lambda cwd: state["sha"])
|
||||
monkeypatch.setattr(gitops, "config_local", config_local)
|
||||
monkeypatch.setattr(gitops, "add", add)
|
||||
monkeypatch.setattr(gitops, "commit", commit)
|
||||
return state
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_forge(monkeypatch):
|
||||
"""Fake the forge seam: controllable version check + CI runs."""
|
||||
from handler.control import forge
|
||||
|
||||
state = {"version_ok": True, "version_out": "forge 1.2.3", "ci_ok": True, "runs": []}
|
||||
|
||||
monkeypatch.setattr(
|
||||
forge, "check_version", lambda cwd=".": (state["version_ok"], state["version_out"])
|
||||
)
|
||||
monkeypatch.setattr(forge, "ci_list", lambda cwd, sha: (state["ci_ok"], state["runs"]))
|
||||
monkeypatch.setattr(forge, "ci_log", lambda cwd, run_id: (True, "log"))
|
||||
return state
|
||||
|
||||
Reference in New Issue
Block a user