402 lines
9.9 KiB
Markdown
402 lines
9.9 KiB
Markdown
# Agent Deployment Requirements: Owner Authorization Broker V2
|
|
|
|
## Objective
|
|
|
|
Deploy the audited Owner Authorization Broker that closes the bootstrap gap
|
|
without issuing a new general-purpose Owner credential and without modifying
|
|
`/data/aios-gitops/runtime/secrets/gitops.tokens`.
|
|
|
|
The broker reuses one existing, non-wildcard Owner credential only to
|
|
authenticate the Owner identity through one pre-existing exact scope. It then
|
|
records an immutable task authorization event and directly invokes the
|
|
existing signed grant -> validator -> one-shot provisioner chain.
|
|
|
|
Production deployment of V2R1C6 is **not** authorized by this task.
|
|
|
|
## Fixed bindings
|
|
|
|
```yaml
|
|
task_id: V2R1C6_TASK_SCOPED_WRITER_PROVISIONING
|
|
repository: aios/aios
|
|
base_ref: refs/heads/main
|
|
base_oid: 875d41c3101093149414292067fd700dc214d4d3
|
|
target_branch: agent/v2r1c6-mainline-reconciliation-20260805
|
|
production_change_authorized: false
|
|
tag_change_authorized: false
|
|
baseline_change_authorized: false
|
|
main_write_authorized: false
|
|
```
|
|
|
|
The existing V2R1C5 objects are frozen:
|
|
|
|
```yaml
|
|
tag_oid: 9e65bd59baea392294c0f253046d3ab116f63145
|
|
peeled_target_oid: aa60e891547abd7e215af7cf2bf3f21fd23541da
|
|
baseline_version: V2R1C5
|
|
baseline_status: PRODUCTION_DEPLOYED
|
|
```
|
|
|
|
## 1. Package verification
|
|
|
|
Verify `MANIFEST.sha256` before installation. Reject any mismatch.
|
|
|
|
Run:
|
|
|
|
```bash
|
|
python3 -m unittest -v \
|
|
tests/test_authorized_task_writer_provisioning.py \
|
|
tests/test_owner_authorization_broker.py
|
|
|
|
python3 scripts/smoke_authorized_task_writer_provisioning.py
|
|
python3 scripts/smoke_owner_authorization_broker.py
|
|
python3 -m py_compile \
|
|
active-runtime/app/authorized_task_writer_provisioning.py \
|
|
active-runtime/app/aios_authorized_task_writer_api.py \
|
|
active-runtime/app/owner_authorization_broker.py \
|
|
active-runtime/app/aios_owner_authorization_broker_api.py
|
|
```
|
|
|
|
All checks must pass.
|
|
|
|
## 2. Existing Owner credential selection
|
|
|
|
Read only the non-secret registry metadata. Select one existing credential
|
|
that satisfies all of the following:
|
|
|
|
```yaml
|
|
role: owner
|
|
wildcard_scope: false
|
|
account: exact known Owner identity
|
|
contains_exact_intake_scope: true
|
|
```
|
|
|
|
Use one existing exact scope such as `commit:create` or `file:write`. Prefer
|
|
the narrowest scope already assigned to the intended Owner.
|
|
|
|
Do not:
|
|
|
|
- use the historical wildcard Owner credential;
|
|
- add `writer:provision` to any bearer token;
|
|
- create or modify a bearer credential;
|
|
- print, copy or commit bearer-token material.
|
|
|
|
Record only:
|
|
|
|
```yaml
|
|
owner_account: <non-secret account>
|
|
credential_id: <non-secret ID, when available>
|
|
intake_scope: <one exact existing scope>
|
|
scope_readback_available: true|false
|
|
```
|
|
|
|
If `handler.need()` returns the exact scope set, configure the Owner account
|
|
allowlist and leave the credential ID allowlist empty.
|
|
|
|
If scope metadata is not returned, configure the exact non-secret credential
|
|
ID allowlist. If neither exact scope metadata nor a stable non-secret
|
|
credential ID can be proven, stop:
|
|
|
|
```yaml
|
|
STATUS: BLOCKED
|
|
REASON: OWNER_CREDENTIAL_SCOPE_NOT_PROVABLE
|
|
```
|
|
|
|
## 3. Staging installation
|
|
|
|
Install the four application modules in a root-owned staging directory:
|
|
|
|
```text
|
|
authorized_task_writer_provisioning.py
|
|
aios_authorized_task_writer_api.py
|
|
owner_authorization_broker.py
|
|
aios_owner_authorization_broker_api.py
|
|
```
|
|
|
|
The directory and files must not be group/world writable.
|
|
|
|
Prepare environment values:
|
|
|
|
```yaml
|
|
AIOS_GITOPS_OWNER_AUTHORIZATION_BROKER_ENABLED: "true"
|
|
AIOS_GITOPS_OWNER_AUTHORIZATION_INTAKE_SCOPES: <one exact existing scope>
|
|
AIOS_GITOPS_OWNER_AUTHORIZATION_ALLOWED_IDENTITIES: <exact owner account>
|
|
AIOS_GITOPS_OWNER_AUTHORIZATION_ALLOWED_CREDENTIAL_IDS: <exact ID or empty>
|
|
AIOS_GITOPS_OWNER_AUTHORIZATION_MAX_EXPIRY_SECONDS: "900"
|
|
AIOS_GITOPS_OWNER_AUTHORIZATION_STATE_ROOT:
|
|
/var/lib/aios-gitops/owner-authorization-broker
|
|
```
|
|
|
|
Use the existing signer, validator and provisioner paths. Do not change their
|
|
root governance configuration or disable signature checks.
|
|
|
|
Start a localhost-only staging instance on a temporary port. Do not replace
|
|
the production service yet.
|
|
|
|
## 4. Authentication fail-closed tests
|
|
|
|
The staging endpoint is:
|
|
|
|
```text
|
|
POST /api/governance/owner-authorizations
|
|
```
|
|
|
|
Required tests:
|
|
|
|
```yaml
|
|
unauthenticated:
|
|
expected: 401
|
|
|
|
wrong_role:
|
|
expected: 403
|
|
|
|
wrong_scope:
|
|
expected: 403
|
|
|
|
wildcard_owner:
|
|
expected: 403
|
|
error: WILDCARD_OWNER_CREDENTIAL_REJECTED
|
|
|
|
unallowlisted_owner:
|
|
expected: 403
|
|
error: OWNER_IDENTITY_NOT_ALLOWED
|
|
|
|
production_capability_true:
|
|
expected: 403
|
|
error: PRODUCTION_CAPABILITY_REJECTED
|
|
```
|
|
|
|
A connection failure, 404 or 500 is not an authorization-policy pass.
|
|
|
|
## 5. Formal provisioning request
|
|
|
|
Use the selected existing non-wildcard Owner credential through its runtime
|
|
secret reference. Never place the bearer token in the request body, command
|
|
line, shell history, output report or Git.
|
|
|
|
Request:
|
|
|
|
```json
|
|
{
|
|
"action": "AUTHORIZE_TASK_WRITER_PROVISIONING",
|
|
"task_id": "V2R1C6_TASK_SCOPED_WRITER_PROVISIONING",
|
|
"repository": "aios/aios",
|
|
"base_ref": "refs/heads/main",
|
|
"base_oid": "875d41c3101093149414292067fd700dc214d4d3",
|
|
"target_branch": "agent/v2r1c6-mainline-reconciliation-20260805",
|
|
"one_time_use": true,
|
|
"expires_in_seconds": 900,
|
|
"production_change_authorized": false,
|
|
"tag_change_authorized": false,
|
|
"baseline_change_authorized": false,
|
|
"main_write_authorized": false,
|
|
"allowed_operations": [
|
|
"create_worktree",
|
|
"create_target_branch_if_absent",
|
|
"commit_to_target_branch",
|
|
"push_target_branch"
|
|
],
|
|
"denied_operations": [
|
|
"direct_main_push",
|
|
"force_push",
|
|
"tag_create",
|
|
"tag_update",
|
|
"tag_delete",
|
|
"branch_delete",
|
|
"repository_admin",
|
|
"baseline_write",
|
|
"production_deploy",
|
|
"production_marker_write",
|
|
"history_rewrite"
|
|
]
|
|
}
|
|
```
|
|
|
|
The Owner authorization reference is generated by the broker. The caller must
|
|
not submit or invent one.
|
|
|
|
Expected result:
|
|
|
|
```yaml
|
|
status: READY_FOR_CODE_AUTHORING
|
|
owner_authorization_event_id: generated
|
|
owner_authorization_reference: generated
|
|
owner_authorization_digest_sha256: generated
|
|
owner_authorization_consumed: true
|
|
approval_plan_id: generated
|
|
grant_digest_sha256: generated
|
|
grant_consumed: true
|
|
|
|
branch_oid: 875d41c3101093149414292067fd700dc214d4d3
|
|
|
|
writer_scope:
|
|
workspace_role: task-scoped-isolated-writer
|
|
writes_enabled: true
|
|
allowed_branch: agent/v2r1c6-mainline-reconciliation-20260805
|
|
allowed_base_oid: 875d41c3101093149414292067fd700dc214d4d3
|
|
allow_main_write: false
|
|
allow_tag_write: false
|
|
allow_baseline_write: false
|
|
allow_force_push: false
|
|
```
|
|
|
|
## 6. Independent post-provisioning verification
|
|
|
|
Verify the Authority ref:
|
|
|
|
```bash
|
|
git --git-dir=/data/aios-gitops/repo.git rev-parse \
|
|
refs/heads/agent/v2r1c6-mainline-reconciliation-20260805
|
|
```
|
|
|
|
It must equal:
|
|
|
|
```text
|
|
875d41c3101093149414292067fd700dc214d4d3
|
|
```
|
|
|
|
Verify `main` remains unchanged, V2R1C5 tag object and peeled target remain
|
|
unchanged, and the Production Baseline remains V2R1C5.
|
|
|
|
Verify the broker audit event under:
|
|
|
|
```text
|
|
/var/lib/aios-gitops/owner-authorization-broker/events/
|
|
```
|
|
|
|
Requirements:
|
|
|
|
```yaml
|
|
status: CONSUMED
|
|
wildcard_scope_used: false
|
|
grant_consumed: true
|
|
permissions:
|
|
directory: "0700"
|
|
json_files: "0600"
|
|
```
|
|
|
|
Do not return bearer-token material in the report.
|
|
|
|
## 7. Commit the broker through the new writer
|
|
|
|
After `READY_FOR_CODE_AUTHORING`, use only the writer's
|
|
`POST /api/commit-file` route to put this code bundle on:
|
|
|
|
```text
|
|
agent/v2r1c6-mainline-reconciliation-20260805
|
|
```
|
|
|
|
Commit the bridge and broker as separate intentional commits when practical:
|
|
|
|
1. Owner-authorized task-writer bridge.
|
|
2. Audited Owner authorization broker and deployment docs.
|
|
|
|
Do not merge to `main` directly. Create a protected PR after branch commits
|
|
and tests are complete.
|
|
|
|
## 8. Permanent service deployment
|
|
|
|
Only after protected review and merge:
|
|
|
|
1. Install the reviewed files from the merge commit.
|
|
2. Apply a reviewed systemd drop-in based on the provided example.
|
|
3. Start the wrapper entrypoint:
|
|
`aios_owner_authorization_broker_api.py`.
|
|
4. Verify all existing API routes still work.
|
|
5. Verify the broker remains localhost/reverse-proxy constrained as intended.
|
|
6. Re-run authentication and policy tests.
|
|
7. Remove the temporary staging instance.
|
|
|
|
This permanent bridge deployment does not authorize a V2R1C6 production tag,
|
|
Baseline update or application deployment.
|
|
|
|
## 9. Fail-closed conditions
|
|
|
|
Stop with `BLOCKED` for any of the following:
|
|
|
|
- Authority `main` no longer equals the fixed base OID.
|
|
- Target branch exists at a different OID.
|
|
- Only a wildcard Owner credential can authenticate.
|
|
- Exact credential scope cannot be proven.
|
|
- Owner identity is not explicitly allow-listed.
|
|
- Signer, validator or provisioner self-test fails.
|
|
- Grant is not marked one-time and consumed.
|
|
- Writer allows main, tag, Baseline, force-push or branch-delete operations.
|
|
- Audit event contains sensitive material.
|
|
- V2R1C5 tag or Baseline changes.
|
|
|
|
## 10. Required Agent result
|
|
|
|
```yaml
|
|
STATUS: READY_FOR_CODE_AUTHORING | BLOCKED | FAILED
|
|
|
|
PACKAGE:
|
|
manifest_verified:
|
|
unit_tests:
|
|
smoke_tests:
|
|
py_compile:
|
|
|
|
OWNER_CREDENTIAL:
|
|
account:
|
|
credential_id:
|
|
intake_scope:
|
|
exact_scope_proven:
|
|
wildcard_used: false
|
|
token_logged: false
|
|
|
|
BROKER:
|
|
staging_listener:
|
|
endpoint_status:
|
|
event_id:
|
|
authorization_reference:
|
|
authorization_digest_sha256:
|
|
event_consumed:
|
|
audit_permissions_valid:
|
|
|
|
GRANT:
|
|
approval_plan_id:
|
|
grant_digest_sha256:
|
|
signer_identity:
|
|
signature_valid:
|
|
one_time_use:
|
|
consumed:
|
|
|
|
BRANCH:
|
|
name:
|
|
oid:
|
|
base_oid:
|
|
ref_exists:
|
|
worktree_path:
|
|
worktree_clean:
|
|
|
|
WRITER:
|
|
status:
|
|
writes_enabled:
|
|
allowed_branch:
|
|
allowed_base_oid:
|
|
allowed_routes:
|
|
main_write_denied:
|
|
tag_write_denied:
|
|
baseline_write_denied:
|
|
force_push_denied:
|
|
|
|
POSTCHECK:
|
|
main_unchanged:
|
|
V2R1C5_tag_unchanged:
|
|
baseline_unchanged:
|
|
|
|
REPOSITORY_INTEGRATION:
|
|
commit_oids:
|
|
protected_pr:
|
|
merged:
|
|
permanent_bridge_deployed:
|
|
|
|
BLOCKERS:
|
|
|
|
GOVERNANCE:
|
|
force_push_used: false
|
|
tag_rewritten: false
|
|
direct_main_push: false
|
|
secrets_committed: false
|
|
owner_approval_respected: true
|
|
```
|