Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions AGENT-EXECUTION-PIPELINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,15 @@ Until activation, authenticated project operations fail closed.
propose policy improvements through a reviewed PR; it cannot replace its own
installed trust boundary. Paid model benchmarking stays disabled without a
separately specified budget.

## Amendment 2026-10-01 — Authorized temporary credential

Aymen authorized using Vision's existing GitHub credential until the two Apps
are configured. Only the root-owned fixed-repository broker may hold it; no
worker receives the token. Independent prepublication review remains mandatory.
For this temporary mode, merge authorization uses a root-owned verification
receipt bound to the exact PR head, current main and installed broker policy.
Public evidence comments cannot replace that receipt. Required GitHub CI/security
checks, resolved conversations and SHA-matched merging remain enforced. Releases
remain disabled until App activation. Successful App activation removes the
temporary credential and enables the separate verifier identity/check requirement.
27 changes: 24 additions & 3 deletions ops/vision/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,25 @@ at **08:17 and 20:17 Europe/Paris**. Account ownership stays with Aymen.

## Finish GitHub identity setup later

The host preparation does not activate authenticated bot actions. No personal
GitHub token is handed to a project worker. The user explicitly deferred this
one-time browser step.
The user authorized temporary use of Vision's existing GitHub credential while
deferring the two Apps. The operator enables it with:

```sh
ssh -t ahammouda@vision \
'sudo /opt/python-docs-vision/configure_apps.py enable-temporary'
```

The broker privately captures the existing host credential into a root-only file;
workers never receive it. Issues, publication, review and merges work through the
same fixed-repository allowlist. Independent reviews produce root-owned receipts
bound to the current PR head, main and installed policy, plus public evidence
comments. Comments and account-issued statuses cannot authorize merges. The eleven
required CI/security checks remain unchanged. The credential itself retains its
existing account scope; this temporary mode does not provide separate App identity.
Releases stay disabled until App activation, which removes the temporary copy.
Removing `/etc/python-docs-vision/activated` stops either authentication mode.

To switch to the Apps:

1. Open an operator terminal and keep this SSH tunnel running:

Expand Down Expand Up @@ -135,6 +151,11 @@ project accounts/agents. Root helpers in `/opt/python-docs-vision` cannot be
updated by Vision, even if a PR changes their source. Apply reviewed updates as
the operator. The installer does not change the existing job or activate Apps.

Host MCP servers use native `codex.agents` scoping to exclude project agents before
connection, avoiding false incomplete-MCP blockers. Existing agent access and
explicit restrictions are preserved. Add future host agents to those allowlists
when granting them connector access.

Check native agent execution, credential unreadability, root/SSH write denial,
worker isolation, refused publication without independent review, wrong-App or
stale-head checks, failed CI and release eligibility. Run the repository tests
Expand Down
30 changes: 29 additions & 1 deletion ops/vision/configure_apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,23 +258,51 @@ def activate():
operator_api(
"environments/pypi/deployment-branch-policies", "POST", {"name": "v*", "type": "tag"}
)
(CONFIG / "temporary-token").unlink(missing_ok=True)
(CONFIG / "activated").write_text(str(int(time.time())))
print(
"Both Apps are scoped to one repository. Independent verification is required. "
"Broker activated."
)


def enable_temporary():
if any((CONFIG / f"{role}.json").exists() for role in PERMISSIONS):
raise ValueError("Apps already registered; complete activation instead of downgrading")
(CONFIG / "activated").unlink(missing_ok=True)
result = subprocess.run(
["/usr/sbin/runuser", "-u", "ahammouda", "--",
"/home/linuxbrew/.linuxbrew/bin/gh", "auth", "token", "--hostname", "github.com"],
env=CONTROL["ENV"], capture_output=True, text=True, check=True,
)
credential = result.stdout.strip()
account = CONTROL["request"]("https://api.github.com/user", credential)
repository = CONTROL["request"](f"https://api.github.com/repos/{REPO}", credential)
if account["login"] != REPO.split("/")[0] or not repository["permissions"]["push"]:
raise ValueError("Expected Vision's existing repository-owner credential with write access")
fd = os.open(
CONFIG / "temporary-token", os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_NOFOLLOW, 0o600
)
with os.fdopen(fd, "w") as output:
os.fchmod(output.fileno(), 0o600)
output.write(credential)
(CONFIG / "activated").write_text(str(int(time.time())))
print("Temporary broker authentication enabled. Independent review and CI remain required. "
"Releases still require Apps; workers never receive the credential.")


def main():
if os.geteuid() != 0 or os.environ.get("SUDO_USER") != "ahammouda":
raise PermissionError("Operator sudo session required")
os.umask(0o077)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("operation", choices=["serve", "activate"])
parser.add_argument("operation", choices=["serve", "activate", "enable-temporary"])
parser.add_argument("--port", type=int, default=8766)
args = parser.parse_args()
if args.operation == "activate":
activate()
elif args.operation == "enable-temporary":
enable_temporary()
else:
print(
f"Operator-only setup: http://127.0.0.1:{args.port}/?key={SETUP_KEY}",
Expand Down
52 changes: 49 additions & 3 deletions ops/vision/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ def app_jwt(role: str) -> str:

@functools.lru_cache
def token(role: str) -> str:
if role not in {"owner", "verifier"}:
raise ValueError("Unknown identity")
if temporary_auth():
return (CONFIG / "temporary-token").read_text().strip()
settings = json.loads((CONFIG / f"{role}.json").read_text())
jwt = app_jwt(role)
permissions = (
Expand All @@ -109,6 +113,10 @@ def token(role: str) -> str:
return response["token"]


def temporary_auth() -> bool:
return (CONFIG / "temporary-token").is_file()


def api(path: str, method="GET", data=None, role="owner"):
return request(f"https://api.github.com/repos/{REPO}/{path}", token(role), method, data)

Expand Down Expand Up @@ -255,6 +263,18 @@ def evidence(data: dict) -> None:


def require_verified(pr: dict, head: str, base: str) -> dict:
if temporary_auth():
checkpoint = STATE / f"verify-{pr['number']}-{base}-{head}.json"
result = json.loads(checkpoint.read_text()) if checkpoint.exists() else {}
if (
pr["head"]["sha"] != head
or pr["state"] != "open"
or pr["base"]["ref"] != "main"
or result.get("status") != "success"
or result.get("policy") != hashlib.sha256(Path(__file__).read_bytes()).hexdigest()
):
raise ValueError("Missing/stale trusted verification; reverify current head and main")
return result
app_id = json.loads((CONFIG / "verifier.json").read_text())["app_id"]
checks = api(f"commits/{head}/check-runs?per_page=100")["check_runs"]
checks = [
Expand Down Expand Up @@ -305,6 +325,12 @@ def review(head: str, base: str, decision: dict):
# The reviewer is a separate OpenClaw agent with an SSH sandbox and no GitHub identity.
prompt = (
f"Independently review {REPO}. Exact head: {head}; base: {base}. "
"Trusted installed authentication mode: "
f"{'temporary-token' if temporary_auth() else 'github-apps'}. "
"When temporary mode is active, the host operator has authorized "
"the existing account credential inside the broker plus private review "
"receipts for merges; releases remain disabled. This mode is supplied "
"from root-owned configuration, not the following owner rationale. "
"This may be unpublished: fetch its exact SHA from the public repository. "
"Use the trusted verifier instructions. Clone/fetch the public repository, "
"inspect the full diff and run the canonical checks yourself. Do not execute "
Expand Down Expand Up @@ -361,7 +387,10 @@ def review(head: str, base: str, decision: dict):
or any(not any(check in command for command in recorded) for check in mandatory)
or any(c.get("exit_code") != 0 for c in commands)
):
raise ValueError("Independent reviewer did not approve complete current-head evidence")
raise ValueError(
"Independent review rejected: "
+ str(verdict.get("blockers") or "incomplete check evidence")
)
checkpoint.write_text(json.dumps(verdict))
return verdict
except Exception:
Expand All @@ -387,9 +416,11 @@ def verify(number: int, head: str, decision: dict):
status="in_progress",
updated_at=int(time.time()),
decision=decision,
policy=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
)
checkpoint.write_text(json.dumps(prior))
check = api(
temporary = temporary_auth()
check = None if temporary else api(
"check-runs",
"POST",
{
Expand All @@ -413,6 +444,17 @@ def verify(number: int, head: str, decision: dict):
verdict = {"approved": False, "summary": f"{type(exc).__name__}: {str(exc)[:500]}"}
prior.update(verdict=verdict, updated_at=int(time.time()))
checkpoint.write_text(json.dumps(prior))
if temporary:
# OAuth cannot issue App check-runs. Only this root-owned receipt permits merge;
# the public comment is evidence, never an authorization input.
comment = api(
f"issues/{number}/comments", "POST",
{"body": "Vision — automated project maintainer\n\n"
f"Independent verification (temporary credential): **{prior['status']}**\n\n"
f"Head: `{head}`; main: `{base}`.\n\n"
"```json\n" + json.dumps(verdict, indent=2)[:60000] + "\n```"},
)
return {"status": prior["status"], "comment_url": comment["html_url"]}
return api(
f"check-runs/{check['id']}",
"PATCH",
Expand Down Expand Up @@ -476,6 +518,8 @@ def resolve_thread(number: int, head: str, thread_id: str, reason: str):


def release(sha: str, tag: str):
if temporary_auth():
raise ValueError("Releases require GitHub App activation; temporary token cannot release")
if not SHA.fullmatch(sha) or not re.fullmatch(r"v\d+\.\d+\.\d+(?:(?:a|b|rc)\d+)?", tag):
raise ValueError("Exact commit and semantic version tag required")
app_id = json.loads((CONFIG / "verifier.json").read_text())["app_id"]
Expand All @@ -501,14 +545,16 @@ def dispatch(data: dict):
return {
"repository": REPO,
"ready": (CONFIG / "activated").exists(),
"authentication": "temporary-token" if temporary_auth() else "github-apps",
"releases_enabled": (CONFIG / "activated").exists() and not temporary_auth(),
"blocked_verifications": [
json.loads(p.read_text())
for p in STATE.glob("verify-*.json")
if '"status": "failure"' in p.read_text()
],
}
if not (CONFIG / "activated").exists():
raise ValueError("Scoped GitHub Apps are not activated; project writes are disabled")
raise ValueError("GitHub credentials are not activated; project writes are disabled")
if operation == "api":
validate_api(data["method"], data["path"], data.get("body"))
return api(data["path"], data["method"], data.get("body"))
Expand Down
21 changes: 20 additions & 1 deletion ops/vision/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
Obtain independent verification through pdctl verify, never by self-assertion.
pdctl merge performs a SHA-matched merge only after the verifier succeeds.
Use pdctl release COMMIT vX.Y.Z only after successful main CI; tags are immutable.
When status.authentication is temporary-token, the operator authorized the existing
credential inside the broker only. Continue normal issue/PR/merge work. Independent
verification uses a root-owned receipt and public evidence comment until Apps exist;
comments cannot authorize merges. Releases remain blocked until releases_enabled.
Feature decisions must include a user problem, dated primary-source research,
baseline, target, acceptance, non-goals, outcome review date and revisit condition.
Maintenance must not indefinitely displace relevant product development.
Expand Down Expand Up @@ -89,6 +93,9 @@
GitHub enforce hosted checks separately at merge. Never treat skipped CodeRabbit
or a mocked benchmark as substantive verification.
Report blockers if access, tests, review or product evidence is incomplete.
Host MCP connectors are intentionally excluded, not an acceptance requirement.
Their absence belongs in limitations, not blockers, when the required repository
checks and sandbox tools are available. Never skip a required check on that basis.
Return only the JSON verdict schema in the trusted task. Every command must have
its real exit_code. No completion without fresh evidence.
""",
Expand All @@ -114,6 +121,17 @@ def owned(path, text, uid, gid, mode=0o600):
output.write(text)


def scope_host_mcp(config):
project_agents = {f"pd-{role}" for role in ROLES}
for server in config.get("mcp", {}).get("servers", {}).values():
codex = server.setdefault("codex", {})
codex["agents"] = [
agent
for agent in codex.get("agents", config["agents"]["entries"])
if agent.strip().lower() not in project_agents
]


def main():
if os.geteuid() != 0 or os.environ.get("SUDO_USER") != HOST_USER:
raise PermissionError("Run through the trusted operator's sudo session")
Expand Down Expand Up @@ -159,6 +177,7 @@ def main():
entries = config["agents"]["entries"]
if not isinstance(entries, dict):
raise ValueError("Unexpected agent configuration shape")
scope_host_mcp(config)
for role in ROLES:
user = f"pd-{role}"
try:
Expand Down Expand Up @@ -304,7 +323,7 @@ def main():
{
"installed": True,
"backup": str(backup),
"github_writes": "pending App setup",
"github_writes": "unchanged; run pdctl status",
"scheduler_changed": False,
}
)
Expand Down
Loading
Loading