Files
aios/docs/gitops/authorized-task-writer-provisioning.md
T

100 lines
4.0 KiB
Markdown

# Owner Authorization → Task Writer Provisioning Bridge
## Purpose
This change closes the control-plane gap where an authenticated Owner can
approve a task in the API, but the runtime cannot automatically produce the
machine-verifiable, signed, one-time grant required by
`aios-task-writer-provisioner`.
The bridge adds one high-risk endpoint:
`POST /api/task-writer/provision-authorized`
It does not add a general branch endpoint to the hardened writer. Branch and
worktree creation remain the responsibility of the existing root-governed
one-shot provisioner. Source commits continue through the isolated writer's
existing `POST /api/commit-file` route.
## Trust boundary
The API must authenticate the caller as `role=owner` and require the
`writer:provision` scope. The request contains an auditable Owner authorization
reference; it never contains a private key, token or signature.
The bridge:
1. Validates an exact repository, base ref, base OID and target branch.
2. Rejects all production, tag, baseline and direct-main capabilities.
3. Generates a canonical approval plan and short-lived grant request.
4. Calls the root-owned signer adapter.
5. Calls the independent grant validator.
6. Calls the one-shot task writer provisioner.
7. Verifies the resulting branch, writer scope and negative policy tests.
8. Stores a redacted, fsynced idempotency receipt.
The bridge never executes `git update-ref`, `git branch`, `git push`, a tag
operation, a baseline mutation or a deployment command directly.
## Required runtime configuration
```text
AIOS_GITOPS_REPOSITORY_IDENTITY=aios/aios
AIOS_GITOPS_AUTHORITY_GIT_DIR=/data/aios-gitops/repo.git
AIOS_GITOPS_AUTHORIZED_WRITER_STATE_ROOT=/var/lib/aios-gitops/authorized-writer-bridge
AIOS_GITOPS_GRANT_SIGNER_ADAPTER=/usr/local/libexec/aios-grant-signer-adapter
AIOS_GITOPS_GRANT_VALIDATOR=/usr/local/libexec/aios-grant-validator
AIOS_GITOPS_TASK_WRITER_PROVISIONER=/usr/local/libexec/aios-task-writer-provisioner
AIOS_GITOPS_OWNER_PROVISION_SCOPE=writer:provision
AIOS_GITOPS_GOVERNED_USE_SUDO=true
AIOS_GITOPS_SUDO_PATH=/usr/bin/sudo
```
When the API service is non-root, `AIOS_GITOPS_GOVERNED_USE_SUDO=true`
uses the fixed `/usr/bin/sudo -n -- <governed executable>` form. Sudoers must
allow only the three exact executables and must not allow a shell, arbitrary
environment preservation or arbitrary command paths.
The three governed executables must be absolute, regular, executable,
non-symlink files and must not be group/world writable. Each must expose:
```text
--help
--self-test
--grant-dir
--result-json
```
The signer result must bind `approval_plan_id`, `grant_id`,
`grant_digest_sha256`, `signing_key_identity` and proof that a signature is
present. The validator must independently attest the exact repository,
base/target bindings, signature, lifetime, operation lists and one-time-use
property. The provisioner must return `READY_FOR_CODE_AUTHORING`, consume the
grant, create the exact branch at the exact base OID, start a writer bound only
to `POST /api/commit-file`, and report successful negative policy tests.
## Deployment model
Run `aios_authorized_task_writer_api.py` as the ChatGPT Actions API entrypoint.
It delegates all existing routes to `aios_chatgpt_actions_api` and intercepts
only the new provisioning endpoint.
Do not enable this endpoint until:
- the Owner scope is present in the API authorization registry;
- the signer adapter uses a runtime secret reference;
- the validator and provisioner pass their self-tests;
- the state directory is root-owned and mode `0700`;
- the negative tests show main, other branches, tags, baseline, force push and
branch deletion are denied.
## Failure behavior
Every mismatch fails closed. A changed `main` OID, existing conflicting branch,
expired or untrusted signature, missing negative test, writer scope expansion,
or unconsumed grant returns an error and leaves production state untouched.
Idempotent retries return the existing redacted receipt. A retry with a
different task, repository, branch, base or Owner authorization reference is
rejected.