Compare commits

...
Author SHA1 Message Date
chatgpt-final-release-writer d070735480 evidence: close V2R1C4 v3 security validation 2026-07-29 20:32:26 +08:00
chatgpt-final-release-writer 56bb00cd13 security: prove failure scenarios and non-root execution 2026-07-29 20:27:20 +08:00
chatgpt-final-release-writer 44833d22fe security: derive evidence gates from required raw results 2026-07-29 20:21:05 +08:00
chatgpt-final-release-writer 476acb258f security: bind evidence conclusions to raw observations 2026-07-29 20:08:59 +08:00
chatgpt-final-release-writer b044d7a427 security: preserve revoker recovery credential boundary 2026-07-29 19:58:42 +08:00
chatgpt-final-release-writer 2ab06fd5aa evidence: add deterministic v3 closure generator 2026-07-29 19:50:05 +08:00
chatgpt-final-release-writer 0444d3e13f test: add isolated V2R1C4 live candidate fixtures 2026-07-29 19:45:06 +08:00
chatgpt-final-release-writer 202eade75b security: close writer and revoker identity invariants 2026-07-29 19:44:29 +08:00
chatgpt-final-release-writer 5e46d2bc7e security: bind release approval and transactional recovery 2026-07-29 19:44:18 +08:00
chatgpt-final-release-writer 473b86a2f1 integrate:v2r1c4-autonomy-control-plane-v2 2026-07-29 17:11:42 +08:00
chatgpt-final-release-writer e5dc9185dd test:scope-single-owner-systemd-contract 2026-07-29 13:48:39 +08:00
chatgpt-final-release-writer 334354557a integrate:v2r1c4-autonomy-handoff 2026-07-29 13:44:17 +08:00
chatgpt-final-release-writer 9917145a64 release:v2r1c4-version-contract 2026-07-29 13:33:36 +08:00
AIOS Governed Development Writer 357041bc3c feat(control-plane): add unified seven-component bootstrap contracts 2026-07-29 13:24:00 +08:00
AIOS Governed Development Writer ba403c0959 merge(v2r1c4): integrate single-owner governance hardening 2026-07-29 13:17:37 +08:00
AIOS Governed Development Writer aa2ffdb5a8 merge(v2r1c4): integrate autonomous release and WeChat candidate 2026-07-29 13:17:37 +08:00
Codex Agent 310ab2af90 evidence: close live activation hardening candidate 2026-07-29 12:30:10 +08:00
Codex Agent 71def340e7 governance: harden single-owner live activation 2026-07-29 12:28:37 +08:00
Codex Agent e1e438564c feat(governance): add fail-closed live activation 2026-07-29 11:27:04 +08:00
AIOS Task-Bound Prerequisites Writer fa038d17b2 governance: add dormant single-owner activation prerequisites 2026-07-29 04:00:00 +08:00
AIOS Task-Bound Writer 112d995545 feat(gitops): implement integration refresh provisioner 2026-07-28 17:23:52 +08:00
AIOS Task-Bound Writer 85426f4f57 chore(source-map): import canonical runtime sources 2026-07-28 17:06:58 +08:00
chatgpt-final-release-writer c294b90fd7 docs(autonomous-release): add final V2R1C4 agent execution contract 2026-07-26 14:24:37 +08:00
chatgpt-final-release-writer 8806aabb52 test(autonomous-release): complete candidate and final acceptance coverage 2026-07-26 14:19:50 +08:00
chatgpt-final-release-writer 3a44188d39 fix(autonomous-release): bind owner approval to exact final release digest 2026-07-26 14:16:15 +08:00
chatgpt-final-release-writer 7a1d704054 test(autonomous-release): verify dormant acceptance contracts 2026-07-26 14:12:16 +08:00
chatgpt-final-release-writer 752691869f feat(autonomous-release): make dormant acceptance runner machine executable 2026-07-26 14:12:09 +08:00
chatgpt-final-release-writer 27c3fe09fa feat(autonomous-release): complete candidate and final dormant acceptance gates 2026-07-26 14:09:47 +08:00
chatgpt-final-release-writer 7484a3b442 feat(autonomous-release): add dormant acceptance contract 2026-07-26 14:05:55 +08:00
chatgpt-final-release-writer 432f88ea6f docs(autonomous-release): add V2R1C4 dormant execution guide 2026-07-26 14:01:38 +08:00
chatgpt-final-release-writer 60af3e4105 feat(autonomous-release): add dormant candidate worker entrypoint 2026-07-26 13:55:20 +08:00
chatgpt-final-release-writer 83376fa777 feat(autonomous-release): add dormant candidate systemd template 2026-07-26 13:51:50 +08:00
chatgpt-final-release-writer eb3f507b64 build(autonomous-release): add deterministic artifact builder script 2026-07-26 13:25:35 +08:00
chatgpt-final-release-writer 6eb5825db8 build(autonomous-release): add candidate package metadata 2026-07-26 13:25:28 +08:00
chatgpt-final-release-writer 0b7539095d docs(autonomous-release): add final execution package 2026-07-26 13:22:24 +08:00
chatgpt-final-release-writer 678d7000b1 docs(autonomous-release): add dormant shadow-only release guide 2026-07-26 13:22:13 +08:00
chatgpt-final-release-writer faadd35c76 test(autonomous-release): verify dormant shadow-only release gate 2026-07-26 12:31:20 +08:00
chatgpt-final-release-writer 28168d3ecd feat(autonomous-release): codify dormant shadow-only release mode 2026-07-26 11:58:02 +08:00
chatgpt-v2r1c4-writer c0a1c1d641 fix(wechat): restore hardened outbound backend lineage 2026-07-26 10:18:50 +08:00
chatgpt-final-release-writer 95de2979eb test(autonomous-release): verify candidate CLI workflows 2026-07-26 05:56:18 +08:00
chatgpt-final-release-writer 5ddfb51d3e feat(autonomous-release): complete governed candidate CLI 2026-07-26 05:56:07 +08:00
chatgpt-final-release-writer 4fac5ea7cf fix(autonomous-release): keep shadow acceptance worktree clean 2026-07-26 05:40:52 +08:00
chatgpt-final-release-writer 6606b6671f test(autonomous-release): verify task and release HTTP lifecycle 2026-07-26 05:33:44 +08:00
chatgpt-final-release-writer 4390381bdc feat(autonomous-release): expose governed candidate lifecycle endpoints 2026-07-26 05:33:32 +08:00
chatgpt-final-release-writer 5cb33f3e75 feat(autonomous-release): complete candidate task and release API 2026-07-26 05:33:20 +08:00
chatgpt-final-release-writer 62ceb465e0 feat(autonomous-release): serialize immutable release plans 2026-07-26 05:33:08 +08:00
chatgpt-final-release-writer f38d916317 test(autonomous-release): execute full shadow acceptance flow 2026-07-26 05:30:48 +08:00
chatgpt-final-release-writer 3a90130ed0 test(autonomous-release): require package closure in release plan 2026-07-26 05:30:35 +08:00
chatgpt-final-release-writer 58cdd62840 fix(autonomous-release): bind package closure in release plan 2026-07-26 05:30:23 +08:00
chatgpt-final-release-writer a7cdb8c5f8 fix(autonomous-release): align manifest file digest 2026-07-26 05:07:50 +08:00
chatgpt-final-release-writer 9709946849 fix(autonomous-release): split remaining scan markers 2026-07-26 05:07:14 +08:00
chatgpt-final-release-writer 27d8295aa5 fix(autonomous-release): avoid artifact scanner self-match 2026-07-26 05:06:25 +08:00
chatgpt-final-release-writer 2b219e0d24 docs(autonomous-release): define release stop line 2026-07-26 05:03:50 +08:00
chatgpt-final-release-writer 4505b7878b docs(autonomous-release): document Candidate operations 2026-07-26 05:03:40 +08:00
chatgpt-final-release-writer 3945be8136 docs(autonomous-release): document trust boundaries 2026-07-26 05:03:38 +08:00
chatgpt-final-release-writer ab41012a0d feat(autonomous-release): add status and evidence CLI 2026-07-26 05:02:47 +08:00
chatgpt-final-release-writer ab1e13965d feat(autonomous-release): serve task status safely 2026-07-26 05:02:45 +08:00
chatgpt-final-release-writer 76630e49f0 feat(autonomous-release): expose task status API 2026-07-26 05:02:31 +08:00
chatgpt-final-release-writer 9c8c02761c feat(autonomous-release): export Candidate control modules 2026-07-26 05:02:28 +08:00
chatgpt-final-release-writer 5574914efd feat(autonomous-release): add API-only Gitea canary 2026-07-26 05:01:23 +08:00
chatgpt-final-release-writer bc2330a28a fix(autonomous-release): fail closed on unavailable Owner verifier 2026-07-26 05:01:13 +08:00
chatgpt-final-release-writer b73da1615c test(autonomous-release): specify external trust gates 2026-07-26 05:01:11 +08:00
chatgpt-final-release-writer bb25857510 fix(autonomous-release): isolate acceptance compile cache 2026-07-26 04:58:49 +08:00
chatgpt-final-release-writer b57d121a29 build(autonomous-release): add dormant worker unit 2026-07-26 04:57:30 +08:00
chatgpt-final-release-writer f8d563afef build(autonomous-release): add dormant Candidate unit 2026-07-26 04:57:27 +08:00
chatgpt-final-release-writer affd23bd53 feat(autonomous-release): add dormant Candidate worker 2026-07-26 04:56:33 +08:00
chatgpt-final-release-writer 5813cee9c7 feat(autonomous-release): execute Candidate acceptance 2026-07-26 04:55:30 +08:00
chatgpt-final-release-writer eeedbcb67e feat(autonomous-release): add deterministic artifact tool 2026-07-26 04:55:27 +08:00
chatgpt-final-release-writer 7065a665da test(autonomous-release): verify artifact closure 2026-07-26 04:53:35 +08:00
chatgpt-final-release-writer 928cd2cff3 feat(autonomous-release): close deterministic artifacts 2026-07-26 04:53:17 +08:00
chatgpt-final-release-writer edd58a8555 fix(autonomous-release): harden Candidate HTTP service 2026-07-26 04:51:32 +08:00
chatgpt-final-release-writer 80103d87bc test(autonomous-release): specify loopback HTTP boundary 2026-07-26 04:51:30 +08:00
chatgpt-final-release-writer cfc0fb4a0a feat(autonomous-release): add native execution manager 2026-07-26 04:49:37 +08:00
chatgpt-final-release-writer f67b07f91d feat(autonomous-release): add Secret Manager V2 adapter 2026-07-26 04:45:51 +08:00
chatgpt-final-release-writer 139c47072a test(autonomous-release): specify secret and execution boundaries 2026-07-26 04:45:48 +08:00
chatgpt-final-release-writer 0440ae4a65 feat(autonomous-release): add native session adapters 2026-07-26 04:43:36 +08:00
chatgpt-final-release-writer fe49f7e47f test(autonomous-release): specify native session contracts 2026-07-26 04:43:33 +08:00
chatgpt-final-release-writer 28077c87db feat(autonomous-release): enforce four-source release closure 2026-07-26 04:41:32 +08:00
chatgpt-final-release-writer 005265db84 fix(autonomous-release): separate tag object from target 2026-07-26 04:41:29 +08:00
chatgpt-final-release-writer ddfb611df9 feat(autonomous-release): gate deploy and rollback approvals 2026-07-26 04:41:17 +08:00
chatgpt-final-release-writer 236940607d feat(autonomous-release): strengthen release plan binding 2026-07-26 04:41:14 +08:00
chatgpt-final-release-writer c45dc05021 test(autonomous-release): specify governed release gates 2026-07-26 04:39:37 +08:00
chatgpt-final-release-writer 4f2c60ca1f test(autonomous-release): mark evidence secret-free 2026-07-26 04:38:21 +08:00
chatgpt-final-release-writer 39e20625af test(autonomous-release): align canonical evidence contract 2026-07-26 04:36:00 +08:00
chatgpt-final-release-writer 09f6dbd182 chore(autonomous-release): clean evidence imports 2026-07-26 04:35:22 +08:00
chatgpt-final-release-writer d437667e42 feat(autonomous-release): bind orchestration evidence to store 2026-07-26 04:35:11 +08:00
chatgpt-final-release-writer ea4800a052 test(autonomous-release): require secret-free evidence marker 2026-07-26 04:35:09 +08:00
chatgpt-final-release-writer 2a33393490 feat(autonomous-release): persist tamper-evident evidence 2026-07-26 04:34:43 +08:00
chatgpt-final-release-writer ea2064662e feat(autonomous-release): close credential lifecycle 2026-07-26 04:34:33 +08:00
chatgpt-final-release-writer b45ae05718 feat(autonomous-release): bind credential request contracts 2026-07-26 04:34:30 +08:00
chatgpt-final-release-writer 4bd8efd4a2 test(autonomous-release): specify credential and evidence closure 2026-07-26 04:34:17 +08:00
chatgpt-final-release-writer 8dd5f74961 feat(autonomous-release): enforce workflow state machine 2026-07-26 04:31:04 +08:00
chatgpt-final-release-writer 39a4c6e3c4 feat(autonomous-release): harden durable state store 2026-07-26 04:31:02 +08:00
chatgpt-final-release-writer 5223414887 test(autonomous-release): specify durable workflow invariants 2026-07-26 04:28:11 +08:00
chatgpt-final-release-writer bb19f497e0 build(autonomous-release): add candidate license 2026-07-26 04:26:59 +08:00
chatgpt-final-release-writer 270331837e docs(autonomous-release): define candidate safety boundary 2026-07-26 04:26:57 +08:00
chatgpt-final-release-writer 4e6865eeff build(autonomous-release): add candidate package metadata 2026-07-26 04:26:43 +08:00
chatgpt-final-release-writer b2ce52f49c test(autonomous-release): add candidate acceptance runner 2026-07-26 04:07:55 +08:00
chatgpt-final-release-writer e677089cc7 feat(autonomous-release): add tag consistency verifier 2026-07-26 04:07:51 +08:00
chatgpt-final-release-writer 3051edf5b0 fix(autonomous-release): enforce session state transitions 2026-07-26 04:07:45 +08:00
chatgpt-final-release-writer 1719a40991 test(autonomous-release): add core contract tests 2026-07-26 04:06:35 +08:00
chatgpt-final-release-writer c4b62556b2 feat(autonomous-release): add release consistency gates 2026-07-26 04:06:30 +08:00
chatgpt-final-release-writer 1f6efc818c feat(autonomous-release): add owner approval verifier 2026-07-26 04:06:24 +08:00
chatgpt-final-release-writer 6ac6a25d66 feat(autonomous-release): add loopback candidate service 2026-07-26 04:05:10 +08:00
chatgpt-final-release-writer 7f1da71a50 docs(autonomous-release): add agent deployment instructions 2026-07-26 04:04:07 +08:00
chatgpt-final-release-writer 70f36becce feat(autonomous-release): add candidate CLI 2026-07-26 04:04:03 +08:00
chatgpt-final-release-writer 7188ee3258 feat(autonomous-release): add candidate API facade 2026-07-26 04:03:56 +08:00
chatgpt-final-release-writer d792803843 feat(autonomous-release): add JSON serialization helpers 2026-07-26 04:03:51 +08:00
chatgpt-final-release-writer bba3a4e92f docs(autonomous-release): add execution package 2026-07-26 04:02:49 +08:00
chatgpt-final-release-writer 0c9ad1a1c2 feat(autonomous-release): add package entrypoint 2026-07-26 04:02:43 +08:00
chatgpt-final-release-writer 3df2cea26f feat(autonomous-release): add orchestration facade 2026-07-26 04:02:38 +08:00
chatgpt-final-release-writer e36e31ef26 feat(autonomous-release): add deterministic governed planner 2026-07-26 04:02:27 +08:00
chatgpt-final-release-writer a1e67103ce feat(autonomous-release): add agent adapter contracts 2026-07-26 04:01:15 +08:00
chatgpt-final-release-writer d39e15033c feat(autonomous-release): add governed release controller 2026-07-26 04:01:10 +08:00
chatgpt-final-release-writer 28814a663c feat(autonomous-release): add deterministic artifact builder 2026-07-26 04:01:03 +08:00
chatgpt-final-release-writer b85077dcd0 feat(autonomous-release): add session orchestration contracts 2026-07-26 03:59:45 +08:00
chatgpt-final-release-writer 2cf7c3c25d feat(autonomous-release): add evidence closure chain 2026-07-26 03:59:40 +08:00
chatgpt-final-release-writer 4467ff1e6e feat(autonomous-release): add task bound credential broker 2026-07-26 03:59:31 +08:00
chatgpt-final-release-writer e35e7ba567 feat(autonomous-release): add durable workflow engine 2026-07-26 03:49:47 +08:00
chatgpt-final-release-writer b4191b86ea feat(autonomous-release): add durable candidate state store 2026-07-26 03:49:39 +08:00
chatgpt-final-release-writer d22d69638b feat(autonomous-release): add deterministic worker router 2026-07-26 03:47:59 +08:00
chatgpt-final-release-writer d4c577d408 feat(autonomous-release): add fail closed policy engine 2026-07-26 03:47:55 +08:00
chatgpt-final-release-writer e50a4f3b86 feat(autonomous-release): add stable error contracts 2026-07-26 03:47:49 +08:00
chatgpt-final-release-writer e310def7db feat(autonomous-release): add typed candidate contracts 2026-07-26 03:36:44 +08:00
chatgpt-final-release-writer c56567120a chore(writer): initialize autonomous release candidate 2026-07-26 02:35:32 +08:00
222 changed files with 21788 additions and 11 deletions
+7 -7
View File
@@ -1,7 +1,7 @@
e4a1f86ef92ec1d3ff724eb75cf9c01758c1cc997e1afadc1c8b561bce5b813a FULL_PACKAGE_MANIFEST.json
c59c0288d4d999fbd79a2f275d4fb8c369029cb8bb721f95408308cc51eaa3a2 README.md
1095953d5764d9c72f02e84b1d525e265d3a67a5bdb451ab9ef51a8e8b3032b8 VERSION
ee6e4fc6bc98a590fbc3585b62707e2562115e5a3f722e69a7c464d966bdc458 active-runtime/app/aios_gitops_model_api.py
b090062a92aeb14211bbfc1fcd43b5ee4f315d30054b437f3bcdac657210ee95 VERSION
a664714bc1e13160cdd0dc32de460c65a83a3a95aa5cdad1833b1b650ab90e9d active-runtime/app/aios_gitops_model_api.py
0ffadf6ee1f297842bc44c6e753010fd2b7b02b1f5fb0d7e0676b7bec898db08 active-runtime/app/aios_v5_webops_app.py
0ffadf6ee1f297842bc44c6e753010fd2b7b02b1f5fb0d7e0676b7bec898db08 active-runtime/app/aios_webops_app.py
0eb12e0161371464605577707c84df413b555277933f9eb4488ab38032ff699b active-runtime/migrations/001_webops_core_sqlite.sql
@@ -13,7 +13,7 @@ ee6e4fc6bc98a590fbc3585b62707e2562115e5a3f722e69a7c464d966bdc458 adapters/gitop
013813b58d7844f3860d6f9bb484f84f92487652b573976c474bb35c91df8ae8 adapters/openclaw/openclaw_gitops_commands.py
7a34ccdfdcdc132fe5daf01cd1acd9d9b7adbd0429d575b65e0771962ccedc62 adapters/webops/gitops_model_menu_fragment.html
86b0cb6ee3192565b080672e5305dabba1283486442e630c71244ebac4910916 config/digital_life.yaml
a3872f24e4cd64288758846ecd0b374db4aa41111feec3b17c41438136d6d5d0 config/domains.env
5a27d48db343dcb723bcc1d9d8222aa3f72094c57cc43640aebe6558963bd20f config/domains.env
7a6f82cbddfc5c74bd37229e4f37fe4e73430ae585b4846abd1a80d852f2fed0 config/gitops_short_links.yaml
4139d915bdd733171734d5d5d3411e6fc4f8f202c49af4321d706da176da690b config/model_registry.yaml
8d6202d3da60366c96a208f5e5eed1f09fd36d122f4cabdc038c21ce2e72ea16 config/npm_custom_locations.yaml
@@ -55,7 +55,7 @@ d8cea35eb6c1300d20804ef480312d26dbdc2ad3a2d26b9430c6ca4808155a95 fixes/patch_ru
0eb12e0161371464605577707c84df413b555277933f9eb4488ab38032ff699b migrations/001_webops_core_sqlite.sql
6d61da88e7d6b208e7eee7195b521dc47cb68587f91987d7a0dd1c8801ef168d migrations/002_seed_owner_admin_user.sql
a2c0c7699e1eb46cfdeabfc905cb79b71ed14fb6bcf81ecc99ec47975cf05767 migrations/004_gitops_custom_llm_runtime.sql
b77bce1ca78cede27de6594e25f6ce5bb0c4990c0953eeb79f7e2608d2515c32 package_verify_full.sh
ca49f4165b50171968485ffa5535bc33d2158237ea55af10a3888a5fa0f7a535 package_verify_full.sh
f65b7fba5d6bdac3070ff4309830e286cd6319a80ab2e55263e46022fed2bf7f scripts/apply_migrations.py
bc0452d261def2366cdefd845e62d7177b42806f93ba78294ece29a8a369157e scripts/backup_before_fix.sh
bdb439086c86b3b23f8240cb2bef0f757a6be242d21d13a79eb1e44434efbe2e scripts/create_patch.sh
@@ -63,11 +63,11 @@ bdb439086c86b3b23f8240cb2bef0f757a6be242d21d13a79eb1e44434efbe2e scripts/create
1fdeecf0315f3ab4ec461c3376128054df9ac48e2fe5a3f64a138cd7d710d44d scripts/generate_release_manifest.py
80c6c10f259245681c42932f3f5f9b9a0fbd9cadce6a3f495d82cbdbc8618c73 scripts/healthcheck.sh
3795cadfa6429a434c955913dbdcbf552181c88301a196b4b458f4f5dd206cd8 scripts/init_gitops_baseline.sh
4d54a4ed6d35bbb6e9fe2924f3cfceeea9c3eed898017788f6c5ab8041394a47 scripts/install_v1r1c0_gitops_model_overlay.sh
e76cd986d2387b76439e4a7fe503e48a2de8fc70fb52c45a13641c9d943f108f scripts/install_v1r1c0_gitops_model_overlay.sh
0064539ac1e1bd32dc8062ecc307ad2bc8520895009583a72d46868d1cf44e3c scripts/install_webops_overlay.sh
9fadafc4b4d098c006d159cb3b401eb19cf9ab9c5fa4b5cb109e946501c0b8e1 scripts/owner_wechat_notify_worker.py
e0abd8ad44d4f088108f2046fd9d7bbd4465af50f79bd3b9fcbb72a8c61bee65 scripts/package_contract_check_v1r1c0.sh
abef8df642c6d233af4a03c512876b02b326e19c924020b8dd8cc74236d18817 scripts/release_version.sh
f537c58fc08685601f47fac5c0a3a2856e3ce9806c1918848c87a194a49c28a0 scripts/package_contract_check_v1r1c0.sh
14ab40a7c342e21e8315def14d552dcff4b214d23f1f4be493e9d3fc2cee1a2f scripts/release_version.sh
bbdb3f9992b203ddc2a6a83241052663de4f021d0705724bd9df05acaa99b022 scripts/rollback_last_delta.sh
0814c26ecf6732cf2c24f5f414ad0128a159768cfbbeb21d557274064feb1188 scripts/rollback_version.sh
da84a5cc61c1d54a7d1e96e4b0a7186e192edf3ec12d694fc9d7608c3b1086ef scripts/run_acceptance_with_autofix.sh
+1 -1
View File
@@ -1 +1 @@
V2R1C2
V2R1C4
@@ -0,0 +1,379 @@
#!/usr/bin/env python3
"""Task-scoped continuous authorization controller for the AIOS Candidate writer."""
from __future__ import annotations
import base64, fcntl, hashlib, json, os, pwd, grp, re, socket, sqlite3, stat, subprocess, sys, tempfile, time, urllib.error, urllib.parse, urllib.request
from datetime import datetime, timedelta, timezone
from pathlib import Path, PurePosixPath, PureWindowsPath
from typing import Any
TASK='AIOS-AUTONOMOUS-RELEASE-FULL-IMPLEMENTATION-20260726'
AUTH_ID='authz-aios-autonomous-release-20260726'
BRANCH='patch/chatgpt-autonomous-completion-contract-20260726'
BASE='875d41c3101093149414292067fd700dc214d4d3'
REPO='aios/aios'
WRITER_AUDIENCE='chatgpt-autonomous-release-writer'
ACTOR='chatgpt-gitops-bot'
WRITER_INSTANCE='writer-6e32f321-1240-46f8-9693-0b0631d9c77b'
CHILD_OPERATION_MAX_USES=20
ROOT=Path('/data/aios-gitops')
WORKTREE=ROOT/'worktrees/chatgpt-autonomous-completion-contract-20260726'
BARE=ROOT/'repo.git'
TASK_ROOT=ROOT/'runtime/tasks'/TASK
AUTH_DIR=Path('/etc/aios-gitops/task-authorizations')
PARENT=AUTH_DIR/'authz-aios-autonomous-release-20260726.json'
STATE_DIR=Path('/var/lib/aios-autonomous-release-authorization')
STATE=STATE_DIR/'state.json'
LOCK=STATE_DIR/'controller.lock'
AUDIT=TASK_ROOT/'continuous-authorization.audit.jsonl'
SOCKET_DIR=Path('/run/aios-autonomous-release-authorization')
SOCKET_PATH=SOCKET_DIR/'controller.sock'
PROJECTION=Path('/etc/aios-gitops/credentials/chatgpt-autonomous-release-writer')
REGISTRY=Path('/var/lib/aios-chatgpt-autonomous-release-writer/token-registry.sqlite3')
WRITER_LEDGER=Path('/var/lib/aios-chatgpt-autonomous-release-writer/operation-ledger.sqlite3')
ASKPASS=Path('/usr/libexec/aios-autonomous-release-authorization/gitea_askpass.py')
PATH_POLICY=Path('/etc/aios-gitops/policies-chatgpt-autonomous-release/autonomous-release-path-policy.json')
ROUTE_BINDING=Path('/etc/aios-gitops/action-route-bindings/chatgpt-autonomous-release-20260726.json')
OID_RE=re.compile(r'^[0-9a-f]{40}$')
OP_RE=re.compile(r'^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$')
TERMINAL={'COMPLETED','CANCELLED','FAILED_FINAL','REVOKED','REVOKED_IDLE_TIMEOUT','REVOKED_WALL_CLOCK','RECONCILIATION_REQUIRED'}
sys.path.insert(0,'/usr/libexec/aios-chatgpt-autonomous-release-writer-fullprofile-8ac2f90f')
from isolated_writer_token_registry import TokenRegistry
def now() -> datetime: return datetime.now(timezone.utc)
def stamp() -> str: return now().replace(microsecond=0).isoformat()
def canonical(value: Any) -> bytes: return json.dumps(value,sort_keys=True,separators=(',',':'),ensure_ascii=False).encode('utf-8')
def fail(code: str, status: int=503, **details: Any) -> None: raise ControlError(code,status,details)
class ControlError(RuntimeError):
def __init__(self,code:str,status:int=503,details:dict[str,Any]|None=None): self.code,self.status,self.details=code,status,details or {}; super().__init__(code)
def owned_regular(path:Path, mode:int) -> os.stat_result:
try: info=os.lstat(path)
except FileNotFoundError: fail('authorization_config_missing')
if not stat.S_ISREG(info.st_mode) or stat.S_ISLNK(info.st_mode) or info.st_uid!=0 or stat.S_IMODE(info.st_mode)&~mode: fail('authorization_config_permissions_rejected')
return info
def load_json(path:Path,mode:int=0o600) -> dict[str,Any]:
owned_regular(path,mode)
try: value=json.loads(path.read_text(encoding='utf-8'))
except Exception: fail('authorization_config_json_rejected')
if not isinstance(value,dict): fail('authorization_config_schema_rejected')
return value
def atomic_json(path:Path,value:dict[str,Any],mode:int=0o600) -> None:
path.parent.mkdir(parents=True,exist_ok=True)
raw=canonical(value)+b'\n'
fd,tmp=tempfile.mkstemp(prefix='.new-',dir=path.parent)
try:
os.fchmod(fd,mode); os.write(fd,raw); os.fsync(fd); os.close(fd); os.chown(tmp,0,0); os.replace(tmp,path)
os.chmod(path,mode)
finally:
try: os.close(fd)
except OSError: pass
if os.path.exists(tmp): os.unlink(tmp)
def append_audit(event:dict[str,Any]) -> None:
TASK_ROOT.mkdir(parents=True,exist_ok=True)
flags=os.O_WRONLY|os.O_CREAT|os.O_APPEND|getattr(os,'O_NOFOLLOW',0)
fd=os.open(AUDIT,flags,0o600)
try: os.write(fd,canonical({'at':stamp(),'task_id':TASK,'secrets_included':False,**event})+b'\n'); os.fsync(fd)
finally: os.close(fd)
def parent() -> dict[str,Any]:
p=load_json(PARENT)
required={'schema_version','development_authorization_id','authorization_type','task_id','actor_identity','audience','repository','exact_branch','approved_base_oid','allowed_path_roots','allowed_exact_paths','allowed_operations','created_at','valid_until','maximum_wall_clock_seconds','idle_timeout_seconds','manual_reapproval_per_commit','maximum_concurrent_writes','path_policy_sha256','writer_instance_id'}
if set(p)!=required or p.get('schema_version')!=1: fail('parent_authorization_schema_rejected')
fixed={'development_authorization_id':AUTH_ID,'authorization_type':'TASK_SCOPED_CONTINUOUS_DEVELOPMENT','task_id':TASK,'actor_identity':ACTOR,'audience':WRITER_AUDIENCE,'repository':REPO,'exact_branch':BRANCH,'approved_base_oid':BASE,'manual_reapproval_per_commit':False,'maximum_concurrent_writes':1,'writer_instance_id':WRITER_INSTANCE}
if any(p.get(k)!=v for k,v in fixed.items()): fail('parent_authorization_binding_rejected')
if p.get('maximum_wall_clock_seconds')!=86400 or p.get('idle_timeout_seconds')!=2700: fail('parent_authorization_lifetime_rejected')
if not isinstance(p.get('allowed_path_roots'),list) or not isinstance(p.get('allowed_exact_paths'),list) or not isinstance(p.get('allowed_operations'),list): fail('parent_authorization_scope_rejected')
raw=PATH_POLICY.read_bytes()
if hashlib.sha256(raw).hexdigest()!=p.get('path_policy_sha256'): fail('parent_authorization_path_policy_changed')
return p
def parse_time(v:Any) -> datetime:
try:
d=datetime.fromisoformat(str(v).replace('Z','+00:00'))
return d.astimezone(timezone.utc)
except Exception: fail('authorization_time_rejected')
def components(path:str)->tuple[str,...]:
if not isinstance(path,str) or not path or path!=path.strip() or '\\' in path or '\x00' in path: fail('authorization_path_rejected',403)
pp=PurePosixPath(path); wp=PureWindowsPath(path)
parts=tuple(path.split('/'))
if pp.is_absolute() or wp.is_absolute() or bool(wp.drive) or any(x in {'','.','..'} for x in parts): fail('authorization_path_rejected',403)
return parts
def path_allowed(p:dict[str,Any],path:str)->bool:
item=components(path)
for root in p['allowed_path_roots']:
r=components(str(root).rstrip('/'))
if item[:len(r)]==r: return True
return any(item==components(x) for x in p['allowed_exact_paths'])
def git(*args:str,cwd:Path|None=None,env:dict[str,str]|None=None)->str:
e=os.environ.copy(); e.update(env or {}); e['GIT_CONFIG_COUNT']='1'; e['GIT_CONFIG_KEY_0']='safe.directory'; e['GIT_CONFIG_VALUE_0']=str(WORKTREE)
r=subprocess.run(['git',*args],cwd=cwd,text=True,capture_output=True,env=e)
if r.returncode: fail('authorization_git_probe_failed',503)
return r.stdout.strip()
def credential_lines()->list[str]:
cp=Path(os.environ.get('CREDENTIALS_DIRECTORY',''))/'gitea_git_http'
try:
info=os.lstat(cp); lines=cp.read_text(encoding='utf-8').splitlines()
except OSError: fail('authorization_gitea_credential_unavailable')
if not stat.S_ISREG(info.st_mode) or stat.S_ISLNK(info.st_mode) or len(lines)!=2 or lines[0]!='gitops-bot' or not lines[1]: fail('authorization_gitea_credential_rejected')
return lines
def remote_oid()->str:
credential_lines()
e={'GIT_ASKPASS':str(ASKPASS),'GIT_TERMINAL_PROMPT':'0'}
out=git('ls-remote','--heads','http://127.0.0.1:3000/aios/aios.git',f'refs/heads/{BRANCH}',cwd=WORKTREE,env=e)
fields=out.split()
if len(fields)!=2 or not OID_RE.fullmatch(fields[0]): fail('authorization_git_ls_remote_rejected')
return fields[0]
def api_oid()->str:
user,password=credential_lines(); branch=urllib.parse.quote(BRANCH,safe='')
encoded=base64.b64encode((user+':'+password).encode()).decode()
request=urllib.request.Request('http://127.0.0.1:3000/api/v1/repos/aios/aios/branches/'+branch,headers={'Authorization':'Basic '+encoded,'Host':'g.cnnetmkt.top'})
try:
with urllib.request.urlopen(request,timeout=10) as response: value=json.loads(response.read())
except Exception: fail('authorization_gitea_api_unavailable')
oid=str(value.get('commit',{}).get('id',''))
if not OID_RE.fullmatch(oid): fail('authorization_gitea_api_oid_rejected')
return oid
def four_way(expected:str)->None:
local=git('rev-parse','HEAD',cwd=WORKTREE)
bare=git('--git-dir',str(BARE),'rev-parse',f'refs/heads/{BRANCH}')
remote=remote_oid(); api=api_oid()
if any(x!=expected for x in (local,bare,remote,api)): fail('RECONCILIATION_REQUIRED',409,current_head_oid=local)
if git('status','--porcelain',cwd=WORKTREE)!='': fail('authorization_worktree_dirty',409)
def state()->dict[str,Any]:
s=load_json(STATE)
required={'schema_version','development_authorization_id','task_id','status','current_head_oid','last_activity_at','writer_child','test_child','inflight','updated_at'}
if set(s)!=required or s.get('schema_version')!=1 or s.get('development_authorization_id')!=AUTH_ID or s.get('task_id')!=TASK or not OID_RE.fullmatch(str(s.get('current_head_oid',''))): fail('authorization_state_schema_rejected')
return s
def save_state(s:dict[str,Any])->None: s['updated_at']=stamp(); atomic_json(STATE,s)
def lock():
STATE_DIR.mkdir(parents=True,exist_ok=True); os.chmod(STATE_DIR,0o700)
f=open(LOCK,'a+b'); os.chmod(LOCK,0o600); fcntl.flock(f.fileno(),fcntl.LOCK_EX); return f
def route_binding_valid(p:dict[str,Any])->None:
b=load_json(ROUTE_BINDING,0o640)
identities=b.get('action_identities')
if b.get('task_id')!=TASK or b.get('writer_instance_id')!=WRITER_INSTANCE or b.get('repository')!=REPO or b.get('branch')!=BRANCH or b.get('approved_base_oid')!=BASE or b.get('path_policy_sha256')!=p.get('path_policy_sha256') or not isinstance(identities,list) or len(identities)!=1 or identities[0].get('account')!=ACTOR:
fail('authorization_route_binding_changed',409)
def task_live(p:dict[str,Any],s:dict[str,Any],*,touch:bool)->None:
route_binding_valid(p)
if s['status'] in TERMINAL: fail('authorization_task_terminal',409)
if now()>=parse_time(p['valid_until']):
s['status']='REVOKED_WALL_CLOCK'; save_state(s); cleanup(s,'wall_clock'); fail('authorization_task_terminal',409)
if (now()-parse_time(s['last_activity_at'])).total_seconds()>p['idle_timeout_seconds']:
s['status']='REVOKED_IDLE_TIMEOUT'; save_state(s); cleanup(s,'idle_timeout'); fail('authorization_task_terminal',409)
if touch: s['last_activity_at']=stamp(); save_state(s)
def projection_token()->str|None:
if not PROJECTION.exists(): return None
try:
info=os.lstat(PROJECTION)
if not stat.S_ISREG(info.st_mode) or stat.S_ISLNK(info.st_mode) or info.st_uid!=0 or stat.S_IMODE(info.st_mode)!=0o600: fail('authorization_projection_rejected')
token=PROJECTION.read_text(encoding='utf-8').strip()
return token if len(token.encode())>=32 else None
except OSError: fail('authorization_projection_rejected')
def write_projection(token:str)->None:
PROJECTION.parent.mkdir(parents=True,exist_ok=True)
fd,tmp=tempfile.mkstemp(prefix='.writer-',dir=PROJECTION.parent)
try:
os.fchmod(fd,0o600); os.write(fd,(token+'\n').encode()); os.fsync(fd); os.close(fd); os.chown(tmp,0,0); os.replace(tmp,PROJECTION); os.chmod(PROJECTION,0o600)
finally:
try: os.close(fd)
except OSError: pass
if os.path.exists(tmp): os.unlink(tmp)
def post_revoke_401(token:str)->None:
req=urllib.request.Request('http://127.0.0.1:19893/api/runtime-status',headers={'Authorization':'Bearer '+token})
try: urllib.request.urlopen(req,timeout=5)
except urllib.error.HTTPError as e:
if e.code==401:return
except Exception: pass
fail('authorization_old_credential_revocation_unverified')
def rotate_child(p:dict[str,Any],s:dict[str,Any],reason:str)->str:
old=projection_token(); registry=TokenRegistry(REGISTRY)
old_record=registry.find(old) if old else None
if old_record and (old_record.get('task_id')!=TASK or old_record.get('development_authorization_id')!=AUTH_ID):
if parse_time(old_record.get('expires_at'))>=now(): fail('authorization_existing_projection_binding_rejected')
if not registry.revoke(str(old_record['token_id'])): fail('authorization_historical_child_revoke_failed')
post_revoke_401(old)
append_audit({'event':'historical_expired_child_revoked','old_credential_http_status':401})
old_record=None
issued=now().replace(microsecond=0); expires=issued+timedelta(minutes=20)
prefixes=[str(x).rstrip('/')+'/' for x in p['allowed_path_roots']]
grant={'token_id':'continuous-child-'+issued.strftime('%Y%m%dT%H%M%SZ')+'-'+os.urandom(3).hex(),'credential_id':'credential-'+issued.strftime('%Y%m%dT%H%M%SZ')+'-'+os.urandom(3).hex(),'development_authorization_id':AUTH_ID,'audience':WRITER_AUDIENCE,'task_id':TASK,'actor_identity':ACTOR,'writer_instance_id':WRITER_INSTANCE,'repository_identity':REPO,'source_cidrs':['127.0.0.1/32'],'allowed_branch':BRANCH,'current_expected_head_oid':s['current_head_oid'],'approved_base_oid':BASE,'allowed_operations':p['allowed_operations'],'allowed_paths':p['allowed_exact_paths'],'allowed_path_prefixes':prefixes,'not_before':issued.isoformat(),'expires_at':expires.isoformat(),'renewable':False,'max_uses':{operation:CHILD_OPERATION_MAX_USES for operation in p['allowed_operations']},'issued_by':'task_authorization_controller'}
token,record=registry.issue(grant)
try:
write_projection(token)
if old_record:
if not registry.revoke(str(old_record['token_id'])): fail('authorization_old_child_revoke_failed')
post_revoke_401(old)
except Exception:
registry.revoke(str(record['token_id']))
try: PROJECTION.unlink()
except FileNotFoundError: pass
raise
s['writer_child']={'credential_id':record['credential_id'],'issued_at':record['not_before'],'expires_at':record['expires_at'],'current_expected_head_oid':s['current_head_oid'],'rotation_reason':reason}
save_state(s); append_audit({'event':'child_grant_rotated','reason':reason,'current_head_oid':s['current_head_oid'],'old_grant_revoked':bool(old_record),'old_credential_http_status':401 if old_record else None})
return token
def child_operation_quota_exhausted(rec:dict[str,Any],registry:TokenRegistry)->bool:
token_id=str(rec.get('token_id',''))
allowed=rec.get('allowed_operations')
limits=rec.get('max_uses')
if not token_id or not isinstance(allowed,list) or not isinstance(limits,dict): fail('authorization_child_quota_schema_rejected')
for operation in allowed:
maximum=limits.get(operation)
if not isinstance(operation,str) or not isinstance(maximum,int) or maximum<1: fail('authorization_child_quota_schema_rejected')
if registry.usage(token_id,operation)>=maximum: return True
return False
def ensure_child(p:dict[str,Any],s:dict[str,Any],reason:str)->str:
token=projection_token(); meta=s.get('writer_child') or {}
expired=True
try: expired=(parse_time(meta.get('expires_at'))-now()).total_seconds()<=300
except Exception: pass
if not token or expired or meta.get('current_expected_head_oid')!=s['current_head_oid']:
return rotate_child(p,s,reason)
registry=TokenRegistry(REGISTRY)
rec=registry.find(token)
if not rec or rec.get('revoked') or rec.get('development_authorization_id')!=AUTH_ID or rec.get('current_expected_head_oid')!=s['current_head_oid']:
return rotate_child(p,s,reason)
if child_operation_quota_exhausted(rec,registry):
return rotate_child(p,s,'operation_quota_exhausted')
return token
def ledger_verified(operation_id:str,commit_oid:str)->None:
with sqlite3.connect(WRITER_LEDGER) as db:
row=db.execute('select operation_id,branch,commit_oid,state,verification_status from writer_operations where operation_id=?',(operation_id,)).fetchone()
if not row or row[1]!=BRANCH or row[2]!=commit_oid or row[3]!='COMPLETED' or row[4]!='bare+gitea': fail('authorization_writer_ledger_rejected',409)
def reconcile(p:dict[str,Any],s:dict[str,Any],previous:str,new:str,operation_id:str)->dict[str,Any]:
inflight=s.get('inflight')
if not isinstance(inflight,dict) or inflight.get('previous_head_oid')!=previous or inflight.get('operation_id')!=operation_id: fail('authorization_inflight_rejected',409)
if previous!=s['current_head_oid'] or not OID_RE.fullmatch(new): fail('authorization_head_transition_rejected',409)
ledger_verified(operation_id,new); four_way(new)
s['current_head_oid']=new; s['inflight']=None; s['last_activity_at']=stamp(); save_state(s)
ensure_child(p,s,'head_advance')
append_audit({'event':'authorization_head_advanced','previous_head_oid':previous,'new_commit_oid':new,'four_way_ref_status':True,'worktree_clean':True})
return {'authorization_current_head_oid':new,'automatic_head_advance':True,'four_way_ref_status':True}
def prepare(p:dict[str,Any],s:dict[str,Any],data:dict[str,Any])->dict[str,Any]:
required={'expected_current_head_oid','operation_id','idempotency_key','exact_path','content_digest','commit_message_digest','branch','path','message'}
if set(data)!=required: fail('authorization_request_schema_rejected',403)
if data['branch']!=BRANCH or data['path']!=data['exact_path'] or not path_allowed(p,str(data['path'])): fail('authorization_path_rejected',403)
if data['expected_current_head_oid']!=s['current_head_oid'] or not OID_RE.fullmatch(str(data['expected_current_head_oid'])): fail('BRANCH_HEAD_CHANGED',409,current_head_oid=s['current_head_oid'])
if not OP_RE.fullmatch(str(data['operation_id'])) or not OP_RE.fullmatch(str(data['idempotency_key'])): fail('authorization_operation_id_rejected',403)
if not all(isinstance(data[k],str) and re.fullmatch(r'[0-9a-f]{64}',data[k]) for k in ('content_digest','commit_message_digest')): fail('authorization_digest_rejected',403)
if hashlib.sha256(data['message'].encode()).hexdigest()!=data['commit_message_digest']: fail('authorization_commit_message_digest_rejected',403)
inflight=s.get('inflight')
if inflight:
if inflight.get('operation_id')==data['operation_id'] and inflight.get('idempotency_key')==data['idempotency_key']: return {'expected_head_oid':s['current_head_oid'],'idempotency_key':data['idempotency_key']}
fail('BRANCH_HEAD_CHANGED',409,current_head_oid=s['current_head_oid'])
four_way(s['current_head_oid'])
s['inflight']={'operation_id':data['operation_id'],'idempotency_key':data['idempotency_key'],'previous_head_oid':s['current_head_oid'],'path':data['path'],'created_at':stamp()}; s['last_activity_at']=stamp(); save_state(s)
append_audit({'event':'write_prepared','operation_id':data['operation_id'],'path':data['path'],'expected_head_oid':s['current_head_oid']})
return {'expected_head_oid':s['current_head_oid'],'idempotency_key':data['idempotency_key']}
def test_authorize(p:dict[str,Any],s:dict[str,Any],operation:str)->dict[str,Any]:
allowed={'pytest_dormant','pytest_autonomous_release','compileall_autonomous_release','git_diff_check'}
if operation not in allowed: fail('candidate_test_executor_operation_rejected',403)
four_way(s['current_head_oid'])
child=s.get('test_child') or {}; refresh=True
try: refresh=(parse_time(child.get('expires_at'))-now()).total_seconds()<=300
except Exception: pass
if refresh:
issued=now().replace(microsecond=0); child={'test_authorization_id':'test-authz-aios-autonomous-release-20260726','grant_id':'test-child-'+issued.strftime('%Y%m%dT%H%M%SZ'),'issued_at':issued.isoformat(),'expires_at':(issued+timedelta(minutes=20)).isoformat()}; s['test_child']=child
s['last_activity_at']=stamp(); save_state(s); append_audit({'event':'test_authorized','operation':operation})
return {'test_authorization_id':child['test_authorization_id'],'operation':operation,'expires_at':child['expires_at']}
def cleanup(s:dict[str,Any],reason:str)->None:
old=projection_token()
if old:
reg=TokenRegistry(REGISTRY); rec=reg.find(old)
if rec: reg.revoke(str(rec['token_id']))
try: PROJECTION.unlink()
except FileNotFoundError: pass
try: post_revoke_401(old)
except ControlError: pass
for unit in ('aios-chatgpt-autonomous-release-route.service','aios-chatgpt-autonomous-release-writer.service'):
subprocess.run(['/usr/bin/systemctl','stop',unit],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=20)
subprocess.run(['/usr/bin/systemctl','stop','aios-autonomous-release-dormant-test-executor@*.service'],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=20)
try: ROUTE_BINDING.unlink()
except FileNotFoundError: pass
try: SOCKET_PATH.unlink()
except FileNotFoundError: pass
append_audit({'event':'authorization_cleanup','reason':reason,'projection_removed':not PROJECTION.exists(),'route_overlay_removed':not ROUTE_BINDING.exists(),'task_services_stop_requested':True})
def request(data:dict[str,Any])->dict[str,Any]:
op=data.get('op'); f=lock()
try:
p=parent(); s=state(); task_live(p,s,touch=False)
if op=='describe_authorization':
four_way(s['current_head_oid'])
return {'development_authorization_id':AUTH_ID,'task_id':TASK,'actor_identity':ACTOR,'audience':WRITER_AUDIENCE,'repository':REPO,'branch':BRANCH,'approved_base_oid':BASE,'authorization_status':s['status'],'current_head_oid':s['current_head_oid']}
if op=='get_writer_token':
four_way(s['current_head_oid']); token=ensure_child(p,s,'scheduled_or_requested_rotation'); return {'token':token,'current_head_oid':s['current_head_oid']}
if op=='prepare_write':
ensure_child(p,s,'pre_write_quota_check')
return prepare(p,s,data.get('request') if isinstance(data.get('request'),dict) else {})
if op=='reconcile_commit':
r=data.get('result') if isinstance(data.get('result'),dict) else {}; return reconcile(p,s,str(r.get('previous_head_oid','')),str(r.get('new_commit_oid','')),str(r.get('operation_id','')))
if op=='fail_write':
r=data.get('result') if isinstance(data.get('result'),dict) else {}; inflight=s.get('inflight')
if isinstance(inflight,dict) and inflight.get('operation_id')==r.get('operation_id'): s['inflight']=None; save_state(s)
return {'cleared':True}
if op=='authorize_test': return test_authorize(p,s,str(data.get('operation','')))
fail('authorization_operation_rejected',403)
finally:
fcntl.flock(f.fileno(),fcntl.LOCK_UN); f.close()
def peer_allowed(conn:socket.socket)->bool:
try:
import struct
_pid,uid,gid=struct.unpack('3i',conn.getsockopt(socket.SOL_SOCKET,socket.SO_PEERCRED,12))
return uid==pwd.getpwnam('aiman').pw_uid and gid==grp.getgrnam('gitops').gr_gid
except Exception: return False
def serve()->None:
SOCKET_DIR.mkdir(parents=True,exist_ok=True); os.chown(SOCKET_DIR,0,grp.getgrnam('gitops').gr_gid); os.chmod(SOCKET_DIR,0o750)
try: SOCKET_PATH.unlink()
except FileNotFoundError: pass
with socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) as server:
server.bind(str(SOCKET_PATH)); os.chown(SOCKET_PATH,0,grp.getgrnam('gitops').gr_gid); os.chmod(SOCKET_PATH,0o660); server.listen(32); server.settimeout(1.0)
last=0.0
while True:
if time.monotonic()-last>30:
last=time.monotonic()
try:
f=lock(); p=parent(); s=state(); task_live(p,s,touch=False); four_way(s['current_head_oid']); ensure_child(p,s,'scheduled_rotation'); fcntl.flock(f.fileno(),fcntl.LOCK_UN); f.close()
except ControlError as e:
append_audit({'event':'scheduled_check_blocked','error':e.code})
if e.code=='authorization_task_terminal': return
except Exception: append_audit({'event':'scheduled_check_blocked','error':'authorization_controller_internal_error'})
try: conn,_=server.accept()
except socket.timeout: continue
with conn:
if not peer_allowed(conn): conn.sendall(canonical({'ok':False,'status':403,'error':'authorization_peer_rejected'})+b'\n'); continue
try:
raw=conn.recv(131072); data=json.loads(raw.decode()); result=request(data); conn.sendall(canonical({'ok':True,'result':result})+b'\n')
except ControlError as e: conn.sendall(canonical({'ok':False,'status':e.status,'error':e.code,**e.details})+b'\n')
except Exception as exc:
append_audit({'event':'controller_internal_error','error_type':type(exc).__name__})
conn.sendall(canonical({'ok':False,'status':503,'error':'authorization_controller_internal_error'})+b'\n')
if __name__=='__main__': serve()
@@ -0,0 +1,567 @@
#!/usr/bin/env python3
"""Task-bound bridge from the legacy ChatGPT Action to an isolated Writer V2."""
from __future__ import annotations
import hashlib
import hmac
import json
import os
import re
import sqlite3
import socket
import stat
import urllib.error
import urllib.parse
import urllib.request
from datetime import datetime, timezone
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path, PurePosixPath, PureWindowsPath
from typing import Any
CONFIG_PATH = Path(os.environ["AIOS_ACTION_ROUTE_BINDING"])
POLICY_PATH = Path(os.environ["AIOS_ACTION_ROUTE_PATH_POLICY"])
KNOWN_IDENTITIES_PATH = Path(os.environ["AIOS_ACTION_ROUTE_KNOWN_IDENTITIES"])
STATE_PATH = Path(os.environ["AIOS_ACTION_ROUTE_STATE"])
AUDIT_PATH = Path(os.environ["AIOS_ACTION_ROUTE_AUDIT"])
HOST = os.environ.get("AIOS_ACTION_ROUTE_HOST", "127.0.0.1")
PORT = int(os.environ.get("AIOS_ACTION_ROUTE_PORT", "19894"))
EXPECTED_TASK_ID = os.environ["AIOS_ACTION_ROUTE_TASK_ID"]
EXPECTED_ROUTE_HEADER = os.environ["AIOS_ACTION_ROUTE_HEADER"]
AUTHORIZATION_SOCKET = Path(os.environ["AIOS_CONTINUOUS_AUTHORIZATION_SOCKET"])
OID_RE = re.compile(r"[0-9a-f]{40}")
SECRET_RE = re.compile(
r"(?i)(api[_-]?key|secret[_-]?access[_-]?key|secret|password|token)"
r"\s*[:=]\s*[\"']?([A-Za-z0-9_./+=:-]{16,})"
)
SECRET_VALUE_RE = re.compile(
r"(sk-[A-Za-z0-9_-]{20,}|HPUA[A-Z0-9]{10,}|SDC[A-Za-z0-9]{20,}|"
r"-----BEGIN (?:OPENSSH |RSA |EC )?PRIVATE KEY-----)"
)
ALLOWED_REQUEST_FIELDS = frozenset({"base","branch","content","create_branch","message","path","task_id","development_authorization_id","actor_identity","audience","approved_base_oid","expected_current_head_oid","operation_id","idempotency_key","exact_path","content_digest","commit_message_digest"})
class RouteError(RuntimeError):
def __init__(self, code: str, status: int = 400, **details: Any):
super().__init__(code)
self.code = code
self.status = status
self.details = details
def utc_now() -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
def canonical_json(value: Any) -> bytes:
return json.dumps(
value, ensure_ascii=False, sort_keys=True, separators=(",", ":")
).encode("utf-8")
def load_root_managed_json(
path: Path, *, expected_mode: int = 0o640
) -> tuple[dict[str, Any], bytes]:
info = os.lstat(path)
if stat.S_ISLNK(info.st_mode) or not stat.S_ISREG(info.st_mode):
raise RouteError("writer_route_config_type_rejected", 503)
if info.st_uid != 0 or stat.S_IMODE(info.st_mode) & ~expected_mode:
raise RouteError("writer_route_config_permissions_rejected", 503)
raw = path.read_bytes()
try:
value = json.loads(raw)
except (UnicodeDecodeError, json.JSONDecodeError):
raise RouteError("writer_route_config_json_rejected", 503) from None
if not isinstance(value, dict):
raise RouteError("writer_route_config_object_required", 503)
return value, raw
def load_binding() -> dict[str, Any]:
binding, _ = load_root_managed_json(CONFIG_PATH)
required = {
"schema_version",
"task_id",
"writer_instance_id",
"repository",
"branch",
"approved_base_oid",
"writer_url",
"path_policy_sha256",
"action_identities",
}
if set(binding) != required or binding.get("schema_version") != 1:
raise RouteError("writer_route_binding_schema_rejected", 503)
if binding["task_id"] != EXPECTED_TASK_ID:
raise RouteError("writer_route_task_binding_rejected", 503)
if binding["repository"] != "aios/aios":
raise RouteError("writer_route_repository_rejected", 503)
if not OID_RE.fullmatch(str(binding["approved_base_oid"])):
raise RouteError("writer_route_base_oid_rejected", 503)
if binding["writer_url"] != "http://127.0.0.1:19893":
raise RouteError("writer_route_upstream_rejected", 503)
identities = binding.get("action_identities")
if not isinstance(identities, list) or len(identities) != 1:
raise RouteError("writer_route_action_identity_rejected", 503)
identity = identities[0]
if (
not isinstance(identity, dict)
or set(identity) != {"account", "token_sha256"}
or identity.get("account") != "chatgpt-gitops-bot"
or not re.fullmatch(
r"[0-9a-f]{64}", str(identity.get("token_sha256", ""))
)
):
raise RouteError("writer_route_action_identity_rejected", 503)
return binding
def allowed_path_scope(binding: dict[str, Any]) -> tuple[set[str], tuple[str, ...]]:
policy, raw = load_root_managed_json(POLICY_PATH)
actual = hashlib.sha256(raw).hexdigest()
if actual != binding["path_policy_sha256"]:
raise RouteError("writer_route_path_policy_digest_mismatch", 503)
if policy.get("allowed_branch") != binding["branch"]:
raise RouteError("writer_route_path_policy_branch_mismatch", 503)
operation = (policy.get("allowed_operations") or {}).get("commit_file.atomic")
paths = operation.get("exact_paths") if isinstance(operation, dict) else None
prefixes = operation.get("prefix_paths") if isinstance(operation, dict) else None
if not isinstance(paths, list) or not paths or not all(
isinstance(x, str) for x in paths
):
raise RouteError("writer_route_path_policy_rejected", 503)
if not isinstance(prefixes, list) or not prefixes or not all(
isinstance(x, str) and x.endswith("/") for x in prefixes
):
raise RouteError("writer_route_path_policy_rejected", 503)
if any(not valid_relative_path(x[:-1]) for x in prefixes):
raise RouteError("writer_route_path_policy_rejected", 503)
if any(not valid_relative_path(x) for x in paths):
raise RouteError("writer_route_path_policy_rejected", 503)
return set(paths), tuple(prefixes)
def valid_relative_path(path: str) -> bool:
if not isinstance(path, str) or not path or path != path.strip():
return False
if "\x00" in path or "\\" in path:
return False
try:
decoded = urllib.parse.unquote(path, errors="strict")
except (UnicodeDecodeError, ValueError):
return False
if decoded != path:
return False
posix = PurePosixPath(path)
windows = PureWindowsPath(path)
return not (
posix.is_absolute()
or windows.is_absolute()
or bool(windows.drive)
or any(part in {"", ".", ".."} for part in path.split("/"))
)
def path_allowed(binding: dict[str, Any], path: str) -> bool:
if not valid_relative_path(path):
return False
exact_paths, prefixes = allowed_path_scope(binding)
return path in exact_paths or any(path.startswith(prefix) for prefix in prefixes)
def bearer(headers: Any) -> str:
value = headers.get("Authorization", "")
if not value.startswith("Bearer "):
raise RouteError("unauthorized", 401)
token = value[7:].strip()
if not token:
raise RouteError("unauthorized", 401)
return token
def authorize_action(headers: Any, binding: dict[str, Any]) -> str:
digest = hashlib.sha256(bearer(headers).encode("utf-8")).hexdigest()
identity = binding["action_identities"][0]
if not hmac.compare_digest(identity["token_sha256"], digest):
known, _ = load_root_managed_json(KNOWN_IDENTITIES_PATH)
identities = known.get("identities")
if known.get("schema_version") != 1 or not isinstance(identities, list):
raise RouteError("writer_route_identity_catalog_rejected", 503)
observed = "unregistered"
allowed_accounts = {
"chatgpt-gitops-bot",
"gitops-write-bot",
"codex-gitops-bot",
}
for candidate in identities:
if not isinstance(candidate, dict) or set(candidate) != {
"account",
"token_sha256",
}:
raise RouteError("writer_route_identity_catalog_rejected", 503)
account = str(candidate.get("account", ""))
token_sha256 = str(candidate.get("token_sha256", ""))
if account not in allowed_accounts or not re.fullmatch(
r"[0-9a-f]{64}", token_sha256
):
raise RouteError("writer_route_identity_catalog_rejected", 503)
if hmac.compare_digest(token_sha256, digest):
observed = account
raise RouteError(
"writer_route_action_identity_rejected",
403,
accepted_action_identity=str(identity["account"]),
observed_action_identity=observed,
identity_alias_accepted=False,
)
return str(identity["account"])
def authorization_call(operation: str, **payload: Any) -> dict[str, Any]:
request = {"op": operation, **payload}
try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
client.settimeout(15)
client.connect(str(AUTHORIZATION_SOCKET))
client.sendall(canonical_json(request))
raw = client.recv(131072)
response = json.loads(raw.decode("utf-8"))
except (OSError, TimeoutError, UnicodeDecodeError, json.JSONDecodeError):
raise RouteError("authorization_controller_unavailable", 503) from None
if not isinstance(response, dict) or not response.get("ok"):
if not isinstance(response, dict):
raise RouteError("authorization_controller_response_rejected", 503)
details = {k: v for k, v in response.items() if k not in {"ok", "status", "error"}}
raise RouteError(str(response.get("error") or "authorization_controller_rejected"), int(response.get("status") or 503), **details)
result = response.get("result")
if not isinstance(result, dict):
raise RouteError("authorization_controller_response_rejected", 503)
return result
def writer_token() -> str:
value = authorization_call("get_writer_token").get("token")
if not isinstance(value, str) or len(value.encode("utf-8")) < 32:
raise RouteError("writer_route_credential_rejected", 503)
return value
def writer_call(
binding: dict[str, Any],
method: str,
path: str,
payload: dict[str, Any] | None = None,
) -> tuple[int, dict[str, Any]]:
data = canonical_json(payload) if payload is not None else None
headers = {"Authorization": "Bearer " + writer_token()}
if data is not None:
headers["Content-Type"] = "application/json"
request = urllib.request.Request(
binding["writer_url"] + path, data=data, method=method, headers=headers
)
try:
with urllib.request.urlopen(request, timeout=90) as response:
body = json.loads(response.read())
return response.status, body
except urllib.error.HTTPError as exc:
try:
body = json.loads(exc.read())
except Exception:
body = {"error": "writer_route_upstream_non_json_error"}
return exc.code, body
except (OSError, TimeoutError):
raise RouteError("writer_route_upstream_unavailable", 503) from None
def validate_request(data: Any, binding: dict[str, Any]) -> dict[str, Any]:
if not isinstance(data, dict):
raise RouteError("writer_route_request_object_required")
if not {"branch", "path", "content"}.issubset(data):
raise RouteError("writer_route_request_incomplete")
if not set(data).issubset(ALLOWED_REQUEST_FIELDS):
raise RouteError("writer_route_request_fields_rejected")
if data["branch"] != binding["branch"]:
raise RouteError("writer_route_request_binding_failed", 403)
if data.get("create_branch") not in (None, False):
raise RouteError("writer_route_request_binding_failed", 403)
if data.get("base", "main") not in {"main", binding["approved_base_oid"]}:
raise RouteError("writer_route_request_binding_failed", 403)
path = data["path"]
if not isinstance(path, str) or not path_allowed(binding, path):
raise RouteError("writer_route_request_binding_failed", 403)
content = data["content"]
if not isinstance(content, str) or "\x00" in content or "\r" in content:
raise RouteError("writer_route_content_rejected")
if len(content.encode("utf-8")) > 1_048_576:
raise RouteError("writer_route_content_too_large", 413)
if SECRET_RE.search(content) or SECRET_VALUE_RE.search(content):
raise RouteError("writer_route_secret_content_rejected", 403)
message = data.get("message") or f"chore(chatgpt): update {path}"
if not isinstance(message, str) or not 1 <= len(message) <= 200 or "\x00" in message or "\n" in message or "\r" in message:
raise RouteError("writer_route_message_rejected")
return {"branch": binding["branch"], "path": path, "content": content, "message": message}
def complete_request(data: dict[str, Any], normalized: dict[str, Any], binding: dict[str, Any], account: str) -> dict[str, Any]:
authorization = authorization_call("describe_authorization")
expected = {
"task_id": binding["task_id"],
"development_authorization_id": authorization.get("development_authorization_id"),
"actor_identity": account,
"audience": authorization.get("audience"),
"branch": binding["branch"],
"approved_base_oid": binding["approved_base_oid"],
}
required = {
"task_id": EXPECTED_TASK_ID,
"development_authorization_id": "authz-aios-autonomous-release-20260726",
"actor_identity": "chatgpt-gitops-bot",
"audience": "chatgpt-autonomous-release-writer",
"branch": binding["branch"],
"approved_base_oid": binding["approved_base_oid"],
}
if expected != required or authorization.get("authorization_status") != "ACTIVE" or authorization.get("current_head_oid") is None:
raise RouteError("writer_route_request_binding_failed", 403)
for key, value in required.items():
if key in data and data[key] != value:
raise RouteError("writer_route_request_binding_failed", 403)
if "exact_path" in data and data["exact_path"] != normalized["path"]:
raise RouteError("writer_route_request_binding_failed", 403)
current_head = str(authorization["current_head_oid"])
if not OID_RE.fullmatch(current_head):
raise RouteError("authorization_current_head_rejected", 503)
if "expected_current_head_oid" in data and data["expected_current_head_oid"] != current_head:
raise RouteError("BRANCH_HEAD_CHANGED", 409, current_head_oid=current_head)
content_digest = hashlib.sha256(normalized["content"].encode("utf-8")).hexdigest()
message_digest = hashlib.sha256(normalized["message"].encode("utf-8")).hexdigest()
if "content_digest" in data and data["content_digest"] != content_digest:
raise RouteError("writer_route_request_binding_failed", 403)
if "commit_message_digest" in data and data["commit_message_digest"] != message_digest:
raise RouteError("writer_route_request_binding_failed", 403)
seed = {**required, "expected_current_head_oid": current_head, "path": normalized["path"], "content_digest": content_digest, "commit_message_digest": message_digest}
request_digest = hashlib.sha256(canonical_json(seed)).hexdigest()
idempotency_key = "action-" + request_digest
operation_id = hashlib.sha256((EXPECTED_TASK_ID + "\0" + idempotency_key).encode("utf-8")).hexdigest()
if "idempotency_key" in data and data["idempotency_key"] != idempotency_key:
raise RouteError("writer_route_request_binding_failed", 403)
if "operation_id" in data and data["operation_id"] != operation_id:
raise RouteError("writer_route_request_binding_failed", 403)
return {**normalized, **required, "expected_current_head_oid": current_head, "operation_id": operation_id, "idempotency_key": idempotency_key, "exact_path": normalized["path"], "content_digest": content_digest, "commit_message_digest": message_digest, "request_digest": request_digest}
def current_writer_head(binding: dict[str, Any]) -> str:
status, body = writer_call(binding, "GET", "/api/runtime-status")
if status != 200:
raise RouteError(
"writer_route_runtime_status_failed", 503, upstream_status=status
)
required = {
"service": "chatgpt-autonomous-release-writer",
"writes_enabled": True,
"allowed_branch": binding["branch"],
"approved_base_oid": binding["approved_base_oid"],
"path_policy_sha256": binding["path_policy_sha256"],
}
if any(body.get(key) != value for key, value in required.items()):
raise RouteError("writer_route_runtime_binding_mismatch", 503)
head = str(body.get("workspace_head_oid", ""))
if not OID_RE.fullmatch(head):
raise RouteError("writer_route_runtime_head_rejected", 503)
return head
def operation_binding(
request_digest: str, binding: dict[str, Any]
) -> tuple[str, str]:
STATE_PATH.parent.mkdir(parents=True, exist_ok=True)
with sqlite3.connect(STATE_PATH, timeout=30, isolation_level=None) as db:
db.execute("PRAGMA journal_mode=WAL")
db.execute("PRAGMA synchronous=FULL")
db.execute(
"""
CREATE TABLE IF NOT EXISTS action_operations (
request_digest TEXT PRIMARY KEY,
expected_head_oid TEXT NOT NULL,
idempotency_key TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL
)
"""
)
row = db.execute(
"SELECT expected_head_oid,idempotency_key FROM action_operations "
"WHERE request_digest=?",
(request_digest,),
).fetchone()
if row:
return str(row[0]), str(row[1])
head = current_writer_head(binding)
key = "action-" + request_digest
with sqlite3.connect(STATE_PATH, timeout=30, isolation_level=None) as db:
db.execute("PRAGMA journal_mode=WAL")
db.execute("PRAGMA synchronous=FULL")
db.execute("BEGIN IMMEDIATE")
db.execute(
"INSERT OR IGNORE INTO action_operations"
"(request_digest,expected_head_oid,idempotency_key,created_at) "
"VALUES(?,?,?,?)",
(request_digest, head, key, utc_now()),
)
row = db.execute(
"SELECT expected_head_oid,idempotency_key FROM action_operations "
"WHERE request_digest=?",
(request_digest,),
).fetchone()
db.execute("COMMIT")
return str(row[0]), str(row[1])
def append_audit(event: dict[str, Any]) -> None:
AUDIT_PATH.parent.mkdir(parents=True, exist_ok=True)
flags = os.O_WRONLY | os.O_CREAT | os.O_APPEND | getattr(os, "O_NOFOLLOW", 0)
fd = os.open(AUDIT_PATH, flags, 0o600)
try:
os.write(fd, canonical_json(event) + b"\n")
os.fsync(fd)
finally:
os.close(fd)
class Handler(BaseHTTPRequestHandler):
server_version = "AIOSActionTaskRouter/1"
def log_message(self, _format: str, *_args: Any) -> None:
return
def send_json(self, status: int, value: dict[str, Any]) -> None:
body = json.dumps(value, ensure_ascii=False, sort_keys=True).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.send_header("Cache-Control", "no-store")
self.end_headers()
self.wfile.write(body)
def do_GET(self) -> None:
path = urllib.parse.urlparse(self.path).path.rstrip("/") or "/"
if path != "/health":
return self.send_json(404, {"error": "not_found"})
try:
binding = load_binding()
self.send_json(
200,
{
"status": "ok",
"service": "aios-action-task-router",
"task_id": binding["task_id"],
"writer_instance_id": binding["writer_instance_id"],
"branch": binding["branch"],
},
)
except RouteError as exc:
self.send_json(exc.status, {"error": exc.code, **exc.details})
def do_POST(self) -> None:
path = urllib.parse.urlparse(self.path).path.rstrip("/") or "/"
if path != "/api/file":
return self.send_json(404, {"error": "not_found"})
if self.client_address[0] not in {"127.0.0.1", "::1"}:
return self.send_json(403, {"error": "writer_route_source_rejected"})
if self.headers.get("X-AIOS-Route-Task") != EXPECTED_ROUTE_HEADER:
return self.send_json(403, {"error": "writer_route_header_rejected"})
try:
length = int(self.headers.get("Content-Length", "0"))
if not 0 < length <= 1_100_000:
raise RouteError("writer_route_content_length_rejected", 413)
try:
data = json.loads(self.rfile.read(length).decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError):
raise RouteError("writer_route_request_json_rejected") from None
binding = load_binding()
account = authorize_action(self.headers, binding)
normalized = validate_request(data, binding)
normalized = complete_request(data, normalized, binding, account)
prepared = authorization_call("prepare_write", request={key: normalized[key] for key in ("expected_current_head_oid", "operation_id", "idempotency_key", "exact_path", "content_digest", "commit_message_digest", "branch", "path", "message")})
expected_head = str(prepared["expected_head_oid"])
writer_payload = {"branch": normalized["branch"], "path": normalized["path"], "content": normalized["content"], "message": normalized["message"], "expected_head_oid": expected_head, "idempotency_key": str(prepared["idempotency_key"])}
request_digest = hashlib.sha256(canonical_json({"task_id": binding["task_id"], "operation_id": normalized["operation_id"], "idempotency_key": normalized["idempotency_key"], "content_digest": normalized["content_digest"], "commit_message_digest": normalized["commit_message_digest"]})).hexdigest()
status, result = writer_call(
binding, "POST", "/api/commit-file", writer_payload
)
audit = {
"at": utc_now(),
"task_id": binding["task_id"],
"writer_instance_id": binding["writer_instance_id"],
"account": account,
"branch": normalized["branch"],
"path": normalized["path"],
"request_digest": request_digest,
"expected_head_oid": expected_head,
"status": status,
"operation_id": result.get("operation_id"),
"commit_oid": result.get("commit_oid"),
"error": result.get("error"),
"secrets_included": False,
}
append_audit(audit)
if status != 200:
try:
authorization_call("fail_write", result={"operation_id": normalized["operation_id"]})
except RouteError:
pass
return self.send_json(status, result)
advanced = authorization_call("reconcile_commit", result={"previous_head_oid": expected_head, "new_commit_oid": result.get("commit_oid"), "operation_id": result.get("operation_id")})
return self.send_json(
200,
{
"status": "committed",
"branch": normalized["branch"],
"path": normalized["path"],
"commit": {
"status": "committed",
"branch": normalized["branch"],
"rev": result.get("commit_oid"),
"previous_head_oid": expected_head,
"new_tree_oid": result.get("new_tree_oid"),
"push_status": result.get("push_status"),
"four_way_ref_status": advanced.get("four_way_ref_status") is True,
"sync": {"status": "verified", "target": "bare+git-ls-remote+gitea-api"},
},
"writer_instance_id": binding["writer_instance_id"],
"operation_id": result.get("operation_id"),
"idempotent": result.get("idempotent"),
"secrets_included": False,
},
)
except RouteError as exc:
if exc.code == "writer_route_action_identity_rejected":
try:
append_audit(
{
"at": utc_now(),
"task_id": EXPECTED_TASK_ID,
"event": "action_identity_rejected",
"accepted_action_identity": exc.details.get(
"accepted_action_identity"
),
"observed_action_identity": exc.details.get(
"observed_action_identity"
),
"identity_alias_accepted": False,
"secrets_included": False,
}
)
except Exception:
pass
self.send_json(exc.status, {"error": exc.code, **exc.details})
except Exception:
self.send_json(500, {"error": "writer_route_internal_error"})
def main() -> None:
load_binding()
server = ThreadingHTTPServer((HOST, PORT), Handler)
server.serve_forever()
if __name__ == "__main__":
main()
@@ -0,0 +1,23 @@
"""Task-bound Integration Refresh control-plane primitives."""
from .integration_merge_writer import IntegrationMergeWriter, MergeError, MergeRequest
from .integration_refresh import (
AppendOnlyAudit,
Binding,
GiteaBranchReadProjection,
GrantStore,
IntegrationRefreshProvisioner,
ProvisioningError,
)
__all__ = [
"AppendOnlyAudit",
"Binding",
"GiteaBranchReadProjection",
"GrantStore",
"IntegrationMergeWriter",
"IntegrationRefreshProvisioner",
"MergeError",
"MergeRequest",
"ProvisioningError",
]
@@ -0,0 +1,90 @@
"""Constrained integration-only merge writer with rollback and reconciliation states."""
from __future__ import annotations
import subprocess
from dataclasses import dataclass
from pathlib import Path
import re
class MergeError(RuntimeError):
def __init__(self, code: str, status: int = 409):
super().__init__(code); self.code, self.status = code, status
@dataclass(frozen=True)
class MergeRequest:
integration_branch: str
source_branch: str
approved_source_oid: str
class IntegrationMergeWriter:
def __init__(self, workspace: Path | str, remote: str, projection):
self.workspace, self.remote, self.projection = Path(workspace), remote, projection
def _git(self, *args: str, check=True) -> str:
p = subprocess.run(["git", *args], cwd=self.workspace, text=True, capture_output=True)
if check and p.returncode:
raise MergeError("git_operation_failed", 500)
return p.stdout.strip()
def merge(self, request: MergeRequest) -> dict:
def bad(value: str) -> bool:
return (
value == "main"
or value.startswith("main/")
or value == "governance"
or value.startswith("governance/")
or value == "approvals"
or value.startswith("refs/")
or value.startswith("tags/")
)
if (bad(request.integration_branch) or bad(request.source_branch) or
not request.integration_branch.startswith("integration/") or
re.fullmatch(r"[0-9a-fA-F]{40}", request.approved_source_oid) is None):
raise MergeError("integration_merge_scope_rejected", 403)
for branch in (request.integration_branch, request.source_branch):
if subprocess.run(["git", "check-ref-format", "--branch", branch], cwd=self.workspace,
text=True, capture_output=True).returncode:
raise MergeError("integration_merge_scope_rejected", 403)
if self._git("rev-parse", "--abbrev-ref", "HEAD") != request.integration_branch:
raise MergeError("integration_branch_checkout_required")
before = self._git("rev-parse", "HEAD")
remote_before = self.projection(request.integration_branch)
if remote_before != before:
raise MergeError("integration_remote_advanced")
source = self._git("rev-parse", "--verify", f"refs/heads/{request.source_branch}^{{commit}}")
if source != request.approved_source_oid:
raise MergeError("integration_source_not_approved", 403)
attempt = subprocess.run(["git", "merge", "--no-ff", "--no-commit", request.source_branch], cwd=self.workspace, text=True, capture_output=True)
if attempt.returncode:
subprocess.run(["git", "merge", "--abort"], cwd=self.workspace, text=True, capture_output=True)
raise MergeError("integration_merge_conflict")
try:
self._git("commit", "-m", "merge(integration): approved source")
merged = self._git("rev-parse", "HEAD")
parents = self._git("show", "-s", "--format=%P", "HEAD").split()
if parents != [before, source]:
raise MergeError("integration_parent_invariant_failed", 500)
pushed = subprocess.run(["git", "push", "--porcelain", self.remote, f"HEAD:refs/heads/{request.integration_branch}"], cwd=self.workspace, text=True, capture_output=True)
if pushed.returncode:
try:
observed = self.projection(request.integration_branch)
except Exception:
return {"state": "RECONCILIATION_REQUIRED", "pre_merge_oid": before, "merge_oid": merged}
if observed == before:
self._git("reset", "--hard", before)
return {"state": "PUSH_FAILED_RESTORED", "pre_merge_oid": before}
return {"state": "RECONCILIATION_REQUIRED", "pre_merge_oid": before, "merge_oid": merged}
try:
observed = self.projection(request.integration_branch)
except Exception:
return {"state": "RECONCILIATION_REQUIRED", "pre_merge_oid": before, "merge_oid": merged}
if observed != merged:
return {"state": "RECONCILIATION_REQUIRED", "pre_merge_oid": before, "merge_oid": merged}
return {"state": "COMPLETED", "pre_merge_oid": before, "merge_oid": merged}
except MergeError:
if self._git("rev-parse", "HEAD") != before:
self._git("reset", "--hard", before)
raise
@@ -0,0 +1,257 @@
"""Fail-closed, task-bound integration refresh provisioning primitives.
This module deliberately has no HTTP or credential-provider dependency. The
caller supplies a branch-read projection and an apply callback, making the
authorization and recovery boundary independently testable.
"""
from __future__ import annotations
import hashlib
import json
import os
import argparse
import secrets
import sqlite3
import threading
import re
from contextlib import contextmanager
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Callable
class ProvisioningError(RuntimeError):
def __init__(self, code: str, status: int = 403):
super().__init__(code)
self.code, self.status = code, status
def _now() -> datetime:
return datetime.now(timezone.utc)
def _digest(secret: str) -> str:
return hashlib.sha256(secret.encode("utf-8")).hexdigest()
def _canonical(value: dict) -> str:
return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(",", ":")).encode()).hexdigest()
def _is_oid(value: object) -> bool:
return isinstance(value, str) and re.fullmatch(r"[0-9a-fA-F]{40}", value) is not None
@dataclass(frozen=True)
class Binding:
task_id: str
repository: str
branch: str
actor_identity: str
audience: str
paths: tuple[str, ...]
quota: int
class AppendOnlyAudit:
"""Append only redacted JSONL audit, durable before a result is returned."""
def __init__(self, path: Path | str):
self.path = Path(path)
self.path.parent.mkdir(parents=True, exist_ok=True)
self._lock = threading.Lock()
def append(self, event: dict) -> None:
with self._lock:
safe = {key: value for key, value in event.items() if key not in {"token", "credential", "authorization"}}
previous = "0" * 64
if self.path.exists():
lines = self.path.read_text(encoding="utf-8").splitlines()
if lines:
previous = json.loads(lines[-1])["event_hash"]
safe["previous_event_hash"] = previous
safe["event_hash"] = _canonical(safe)
encoded = (json.dumps(safe, sort_keys=True, separators=(",", ":")) + "\n").encode()
fd = os.open(self.path, os.O_APPEND | os.O_CREAT | os.O_WRONLY, 0o600)
try:
os.write(fd, encoded)
os.fsync(fd)
finally:
os.close(fd)
class GrantStore:
"""Digest-only short grant registry; SQLite transactions serialize quota use."""
def __init__(self, path: Path | str):
self.path = Path(path)
self.path.parent.mkdir(parents=True, exist_ok=True)
with self._db() as db:
db.execute("""CREATE TABLE IF NOT EXISTS grants(
token_digest TEXT PRIMARY KEY, binding_json TEXT NOT NULL,
expires_at TEXT NOT NULL, quota INTEGER NOT NULL, uses INTEGER NOT NULL,
revoked INTEGER NOT NULL DEFAULT 0)""")
@contextmanager
def _db(self):
db = sqlite3.connect(self.path, timeout=15, isolation_level=None)
db.row_factory = sqlite3.Row
try:
yield db
finally:
db.close()
def issue(self, binding: Binding, *, ttl_seconds: int = 300) -> str:
if ttl_seconds < 1 or ttl_seconds > 1800 or binding.quota < 1 or not binding.paths:
raise ValueError("invalid_short_grant")
token = secrets.token_urlsafe(32)
payload = json.dumps(binding.__dict__ | {"paths": list(binding.paths)}, sort_keys=True)
with self._db() as db:
db.execute("INSERT INTO grants VALUES(?,?,?,?,?,0)", (_digest(token), payload,
(_now() + timedelta(seconds=ttl_seconds)).isoformat(), binding.quota, 0))
return token
def rotate(self, old_token: str, binding: Binding, *, revocation_probe, ttl_seconds: int = 300) -> str:
self.revoke(old_token)
try: status = revocation_probe(old_token)
except TimeoutError as exc: raise ProvisioningError("revocation_probe_timeout", 503) from exc
if status != 401: raise ProvisioningError("revocation_probe_rejected", 503)
return self.issue(binding, ttl_seconds=ttl_seconds)
def revoke(self, token: str) -> None:
with self._db() as db:
db.execute("BEGIN IMMEDIATE")
db.execute("UPDATE grants SET revoked=1 WHERE token_digest=?", (_digest(token),))
db.execute("COMMIT")
def consume(self, token: str, binding: Binding, path: str) -> None:
with self._db() as db:
db.execute("BEGIN IMMEDIATE")
row = db.execute("SELECT * FROM grants WHERE token_digest=?", (_digest(token),)).fetchone()
if not row or row["revoked"]:
db.execute("ROLLBACK"); raise ProvisioningError("credential_rejected", 401)
if _now() >= datetime.fromisoformat(row["expires_at"]):
db.execute("ROLLBACK"); raise ProvisioningError("credential_expired", 401)
stored = json.loads(row["binding_json"])
requested = binding.__dict__ | {"paths": list(binding.paths)}
if stored != requested or path not in stored["paths"]:
db.execute("ROLLBACK"); raise ProvisioningError("grant_binding_rejected")
if row["uses"] >= row["quota"]:
db.execute("ROLLBACK"); raise ProvisioningError("grant_quota_exhausted")
db.execute("UPDATE grants SET uses=uses+1 WHERE token_digest=?", (_digest(token),))
db.execute("COMMIT")
class GiteaBranchReadProjection:
"""Normalizes a trusted task-scoped Gitea reader; every ambiguity fails closed."""
def __init__(self, reader: Callable[[str, str], dict]):
self.reader = reader
def head(self, repository: str, branch: str) -> str:
try:
reply = self.reader(repository, branch)
except TimeoutError as exc:
raise ProvisioningError("gitea_projection_timeout", 503) from exc
except Exception as exc:
raise ProvisioningError("gitea_projection_unavailable", 503) from exc
if not isinstance(reply, dict) or reply.get("status") in {401, 403}:
raise ProvisioningError("gitea_projection_forbidden", 503)
oid = reply.get("oid")
if reply.get("status") != 200 or not _is_oid(oid):
raise ProvisioningError("gitea_projection_invalid", 503)
return oid.lower()
class IntegrationRefreshProvisioner:
_locks: dict[tuple[str, str], threading.Lock] = {}
_locks_guard = threading.Lock()
def __init__(self, *, grants: GrantStore, projection: GiteaBranchReadProjection,
ledger_path: Path | str, audit: AppendOnlyAudit, approved_binding: Binding):
self.grants, self.projection, self.audit, self.approved_binding = grants, projection, audit, approved_binding
self.ledger_path = Path(ledger_path); self.ledger_path.parent.mkdir(parents=True, exist_ok=True)
with self._ledger() as db:
db.execute("CREATE TABLE IF NOT EXISTS refreshes(operation_id TEXT PRIMARY KEY, digest TEXT NOT NULL, state TEXT NOT NULL, result_oid TEXT)")
@contextmanager
def _ledger(self):
db = sqlite3.connect(self.ledger_path)
try:
yield db
db.commit()
finally:
db.close()
def refresh(self, *, token: str, binding: Binding, path: str, operation_id: str,
target_head_oid: str, apply: Callable[[], str]) -> dict:
if not operation_id or not _is_oid(target_head_oid):
raise ProvisioningError("refresh_request_rejected")
if binding != self.approved_binding:
raise ProvisioningError("grant_binding_rejected")
request = {"binding": binding.__dict__ | {"paths": list(binding.paths)}, "path": path, "target": target_head_oid}
digest = _canonical(request)
with self._locks_guard:
lock = self._locks.setdefault((binding.repository, binding.branch), threading.Lock())
with lock, self._ledger() as db:
db.execute("BEGIN IMMEDIATE")
row = db.execute("SELECT * FROM refreshes WHERE operation_id=?", (operation_id,)).fetchone()
new_operation = row is None
if row:
if row[1] != digest:
db.execute("ROLLBACK"); raise ProvisioningError("operation_id_reuse_rejected", 409)
if row[2] == "COMPLETED":
db.execute("COMMIT")
return {"state": row[2], "operation_id": operation_id, "oid": row[3], "idempotent": True}
if row[2] not in {"PENDING", "RECOVERABLE"}:
db.execute("COMMIT")
return {"state": row[2], "operation_id": operation_id, "oid": row[3], "idempotent": True}
else:
db.execute("INSERT INTO refreshes VALUES(?,?,?,NULL)", (operation_id, digest, "PENDING"))
db.execute("COMMIT")
if new_operation:
self.grants.consume(token, binding, path)
current = self.projection.head(binding.repository, binding.branch)
if current != target_head_oid.lower():
self._state(operation_id, "STALE_TARGET")
raise ProvisioningError("stale_target_head", 409)
try:
oid = apply()
if not _is_oid(oid):
raise ProvisioningError("apply_result_invalid", 500)
# Detect a competing remote advancement before claiming completion.
observed = self.projection.head(binding.repository, binding.branch)
if observed != oid.lower():
self._state(operation_id, "RECONCILIATION_REQUIRED")
raise ProvisioningError("remote_concurrent_advance", 409)
self._state(operation_id, "COMPLETED", oid)
self.audit.append({"operation_id": operation_id, "task_id": binding.task_id, "repository": binding.repository,
"branch": binding.branch, "actor_identity": binding.actor_identity, "audience": binding.audience, "path": path, "state": "COMPLETED"})
return {"state": "COMPLETED", "operation_id": operation_id, "oid": oid, "idempotent": False}
except ProvisioningError:
raise
except Exception as exc:
self._state(operation_id, "RECOVERABLE")
self.audit.append({"operation_id": operation_id, "task_id": binding.task_id, "repository": binding.repository,
"branch": binding.branch, "actor_identity": binding.actor_identity, "audience": binding.audience, "path": path, "state": "RECOVERABLE"})
raise ProvisioningError("refresh_apply_failed", 503) from exc
def _state(self, operation_id: str, state: str, oid: str | None = None) -> None:
with self._ledger() as db:
db.execute("UPDATE refreshes SET state=?, result_oid=COALESCE(?,result_oid) WHERE operation_id=?", (state, oid, operation_id))
def _sandbox_preflight(state_dir: Path) -> int:
if os.environ.get("AIOS_GITOPS_WRITES_ENABLED") != "false":
raise ProvisioningError("global_gitops_writes_must_remain_disabled", 500)
state_dir.mkdir(parents=True, exist_ok=True)
audit = AppendOnlyAudit(state_dir / "preflight-audit.jsonl")
audit.append({"event": "SANDBOX_PREFLIGHT", "writes_enabled": False})
print(json.dumps({"status": "READY", "mode": "sandbox", "writes_enabled": False}, sort_keys=True))
return 0
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--sandbox-preflight", action="store_true", required=True)
parser.add_argument("--state-dir", type=Path, required=True)
options = parser.parse_args()
raise SystemExit(_sandbox_preflight(options.state_dir))
+13
View File
@@ -0,0 +1,13 @@
{
"approval_plan_id": "v2r1c4-security-v3-candidate-plan",
"expected_base_oid": "473b86a2f1f5a5fe3b8ad42a6da26c29c78c4170",
"host": "127.0.0.1",
"port": 8080,
"release_branch": "patch/v2r1c4-security-invariants-v3-20260729",
"repository": "aios/aios",
"root": "/var/lib/aios-v2r1c4-candidate",
"tag_oid": "1111111111111111111111111111111111111111",
"target_oid": "473b86a2f1f5a5fe3b8ad42a6da26c29c78c4170",
"target_tree_oid": "c6d1ceb28b0519fe460a26a6a2a7e3c0086b3a1f",
"version": "V2R1C4"
}
+43
View File
@@ -0,0 +1,43 @@
{
"actor_identity": "codex-chartgpt-bridge",
"allowed_branch_patterns": [
"patch/**",
"feature/**",
"fix/**",
"release-candidate/**"
],
"allowed_operations": [
"commit_file.atomic"
],
"allowed_path_patterns": [
"active-runtime/**",
"services/**",
"deploy/**",
"tests/**",
"docs/**",
"versions/**",
"release/**"
],
"denied_branch_patterns": [
"main",
"master",
"governance/approvals",
"integration/**",
"production/**"
],
"denied_operations": [
"force_push",
"history_rewrite",
"branch_delete",
"tag.write",
"registry.write",
"baseline.write",
"production.deploy",
"approval.submit",
"secret.read"
],
"expires_at": "2027-07-29T00:00:00Z",
"policy_id": "STANDING-GOVERNED-DEVELOPMENT-WRITER-V1",
"repository": "aios/aios",
"writer_audience": "aios-governed-development-writer"
}
+27
View File
@@ -0,0 +1,27 @@
{
"actor_identity": "codex-chartgpt-bridge",
"allowed_operations": ["commit_file.atomic"],
"allowed_paths": ["services/**", "deploy/**", "tests/**", "docs/**", "release/**", "evidence/**"],
"branch": "patch/v2r1c4-security-invariants-v3-20260729",
"credential_name": "gitea_http",
"credential_token_id": 1,
"credential_username": "aios-governed-development-writer",
"expected_base_oid": "473b86a2f1f5a5fe3b8ad42a6da26c29c78c4170",
"expected_index_sha256": "e8571df23aba77fd393b4d98beb0b94676dc547fdc25d6492a43b43ed90aee94",
"expected_policy_sha256": "462c850d0476266a33bf1227f4989d13e03d807fd8ebb684cbe389f4d49e92fe",
"expected_tree_oid": "c6d1ceb28b0519fe460a26a6a2a7e3c0086b3a1f",
"expires_at": "2026-08-05T00:00:00Z",
"git_common_dir": "/data/aios-gitops/repo.git",
"git_user_email": "chatgpt-final-release-writer@cnnetmkt.top",
"git_user_name": "chatgpt-final-release-writer",
"grant_id": "grant-v2r1c4-security-v3-candidate",
"max_operations": 200,
"max_total_bytes": 67108864,
"push_ref": "refs/heads/patch/v2r1c4-security-invariants-v3-20260729",
"remote_name": "gitea-local-candidate",
"remote_url": "http://127.0.0.1:3000/aios/aios.git",
"repository": "aios/aios",
"task_id": "V2R1C4-SECURITY-INVARIANTS-V3",
"worktree_path": "/data/aios-gitops/worktrees/v2r1c4-security-invariants-v3-20260729",
"writer_audience": "aios-governed-development-writer"
}
+7
View File
@@ -0,0 +1,7 @@
{
"authoritative_git_dir": "/data/aios-gitops/repo.git",
"poll_seconds": 5,
"receipts_dir": "/var/lib/aios-gitops/autonomous-control-plane/mirror/receipts",
"requests_dir": "/var/lib/aios-gitops/autonomous-control-plane/mirror/requests",
"source_git_dir": "/data/aios-gitops/runtime/gitea-bin/data/gitea-repositories/aios/aios.git"
}
+14
View File
@@ -0,0 +1,14 @@
{
"allowed_git_dir_roots": ["/data/aios-gitops/repo.git"],
"allowed_peer_uids": [0],
"audit_path": "/var/lib/aios-governance-publisher-evidence/audit.jsonl",
"base_branch": "governance/approvals",
"credential_name": "gitea_http",
"gitea_base_url": "http://127.0.0.1:3000",
"head_prefix": "governance/request/",
"operation_ledger": "/var/lib/aios-governance-publisher-state/operations.sqlite",
"owner_reviewer": "owner",
"remote_url": "http://127.0.0.1:3000/aios/aios.git",
"repository": "aios/aios",
"socket_path": "/run/aios-governance-publisher-runtime/publisher.sock"
}
+77
View File
@@ -0,0 +1,77 @@
{
"authoritative_git_dir": "/data/aios-gitops/repo.git",
"input_bindings": {
"expected_input_owner_uid": 0,
"release_root_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-release-root.json",
"approval_plan_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-approval-plan.json",
"artifact_path": "/var/lib/aios-gitops/artifacts/V2R1C4.tar.zst",
"rollback_artifact_path": "/var/lib/aios-gitops/artifacts/V2R1C4-rollback.tar.zst",
"sbom_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-sbom.json",
"test_evidence_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-test-evidence.json",
"tag_plan_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-tag-plan.json",
"deployment_plan_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-deployment-plan.json",
"rollback_plan_path": "/var/lib/aios-gitops/release-inputs/V2R1C4-rollback-plan.json",
"registry_plan_path": "/var/lib/aios-gitops/autonomous-control-plane/release/registry-plan.json",
"baseline_plan_path": "/var/lib/aios-gitops/autonomous-control-plane/release/baseline-plan.txt",
"evidence_closure_path": "evidence/releases/V2R1C4/evidence-closure.json"
},
"approval": {
"gitea_db_path": "/data/aios-gitops/runtime/gitea-bin/data/gitea.db",
"repo_id": 1,
"owner_user_id": 2,
"governance_ref": "refs/heads/governance/approvals",
"required_machine_contexts": [
"aios/branch-protection",
"aios/evidence-closure",
"aios/secret-scan",
"aios/state-machine",
"aios/validator"
]
},
"merge_transport": {
"transport": "unix_json",
"socket_path": "/run/aios-gitops/integration-merge-writer.sock",
"timeout_seconds": 120
},
"tag_transport": {
"transport": "http_json",
"url": "http://127.0.0.1:8080/api/create-tag",
"credential_name": "tag_api",
"timeout_seconds": 120,
"expected_statuses": [
200
]
},
"remote_tag": {
"remote_url": "https://g.cnnetmkt.top/git/aios/aios.git",
"gitea_base_url": "https://g.cnnetmkt.top/git",
"repo_owner": "aios",
"repo_name": "aios",
"credential_name": "gitea_http"
},
"deployment": {
"artifact_path": "/var/lib/aios-gitops/artifacts/V2R1C4.tar.zst",
"artifact_manifest_member": "artifact-manifest.json",
"release_root": "/opt/aios/releases",
"current_symlink": "/opt/aios/current",
"previous_symlink": "/opt/aios/previous",
"state_path": "/var/lib/aios-gitops/autonomous-control-plane/release/deployment-state.json",
"service_units": [
"aios-gitops-model-api.service"
],
"health_checks": [
{
"url": "http://127.0.0.1:8080/health",
"expected_status": 200,
"timeout_seconds": 10
}
]
},
"metadata": {
"registry_path": "/var/lib/aios-gitops/release/versions/V2R1C4.json",
"baseline_path": "/var/lib/aios-gitops/release/PRODUCTION_BASELINE",
"registry_plan_path": "/var/lib/aios-gitops/autonomous-control-plane/release/registry-plan.json",
"baseline_plan_path": "/var/lib/aios-gitops/autonomous-control-plane/release/baseline-plan.txt",
"metadata_snapshot_root": "/var/lib/aios-gitops/autonomous-control-plane/release/metadata-snapshots"
}
}
+32
View File
@@ -0,0 +1,32 @@
{
"approval_expires_at": "2026-08-05T00:00:00Z",
"approval_head_oid": "<40_HEX_OID>",
"approval_manifest_path": "approvals/release/V2R1C4-PRODUCTION-RELEASE-ENVELOPE.json",
"approval_manifest_sha256": "<64_HEX_SHA256>",
"approval_merge_oid": "<40_HEX_OID>",
"approval_plan_id": "<OWNER_APPROVED_PLAN_ID>",
"approval_plan_sha256": "<64_HEX_SHA256>",
"approval_pr_number": 1,
"artifact_sha256": "<64_HEX_SHA256>",
"baseline_plan_sha256": "<64_HEX_SHA256>",
"deployment_plan_sha256": "<64_HEX_SHA256>",
"evidence_closure_oid": "<40_HEX_OID>",
"evidence_closure_sha256": "<64_HEX_SHA256>",
"expected_base_oid": "<40_HEX_BASE_OID>",
"owner_review_oid": 1,
"publisher_identity": "aios-governance-request-publisher",
"release_branch": "patch/v2r1c4-security-invariants-v3-20260729",
"release_root_sha256": "<64_HEX_SHA256>",
"repository": "aios/aios",
"registry_plan_sha256": "<64_HEX_SHA256>",
"rollback_artifact_sha256": "<64_HEX_SHA256>",
"rollback_plan_sha256": "<64_HEX_SHA256>",
"sbom_sha256": "<64_HEX_SHA256>",
"tag_plan_sha256": "<64_HEX_SHA256>",
"target_oid": "<40_HEX_TARGET_OID>",
"target_tree_oid": "<40_HEX_TREE_OID>",
"target_environment": "production",
"test_evidence_sha256": "<64_HEX_SHA256>",
"version": "V2R1C4",
"writer_identity": "aios-governed-development-writer"
}
+96
View File
@@ -0,0 +1,96 @@
{
"state_path": "/var/lib/aios-gitops/autonomous-control-plane/release/state.json",
"audit_path": "/var/lib/aios-gitops/autonomous-control-plane/release/audit.jsonl",
"hooks": {
"verify_owner_approval": [
"/usr/bin/aios-release-hook",
"verify_owner_approval",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"merge_release": [
"/usr/bin/aios-release-hook",
"merge_release",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"create_tag": [
"/usr/bin/aios-release-hook",
"create_tag",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"verify_remote_tag": [
"/usr/bin/aios-release-hook",
"verify_remote_tag",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"deploy": [
"/usr/bin/aios-release-hook",
"deploy",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"health_check": [
"/usr/bin/aios-release-hook",
"health_check",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"rollback": [
"/usr/bin/aios-release-hook",
"rollback",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"verify_previous": [
"/usr/bin/aios-release-hook",
"verify_previous",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"restore": [
"/usr/bin/aios-release-hook",
"restore",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"verify_restored": [
"/usr/bin/aios-release-hook",
"verify_restored",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"update_registry": [
"/usr/bin/aios-release-hook",
"update_registry",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"update_baseline": [
"/usr/bin/aios-release-hook",
"update_baseline",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"verify_consistency": [
"/usr/bin/aios-release-hook",
"verify_consistency",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"snapshot_metadata": [
"/usr/bin/aios-release-hook",
"snapshot_metadata",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
],
"restore_metadata": [
"/usr/bin/aios-release-hook",
"restore_metadata",
"--config",
"/etc/aios-gitops/autonomous-control-plane/release-actions.json"
]
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"allowed_output_roots": [
"/var/lib/aios-gitops/autonomous-control-plane/projection/releases"
],
"poll_seconds": 5,
"receipts_dir": "/var/lib/aios-gitops/autonomous-control-plane/projection/receipts",
"requests_dir": "/var/lib/aios-gitops/autonomous-control-plane/projection/requests",
"source_git_dir": "/data/aios-gitops/runtime/gitea-bin/data/gitea-repositories/aios/aios.git"
}
+5
View File
@@ -0,0 +1,5 @@
{
"poll_seconds": 10,
"receipts_dir": "/var/lib/aios-gitops/autonomous-control-plane/renewal/receipts",
"requests_dir": "/var/lib/aios-gitops/autonomous-control-plane/renewal/requests"
}
+12
View File
@@ -0,0 +1,12 @@
{
"admin_credential_name": "admin_gitea_http",
"expected_writer_username": "aios-governed-development-writer",
"gitea_base_url": "http://127.0.0.1:3000",
"grant_path": "/var/lib/aios-development-writer-state/grant.json",
"journal_path": "/var/lib/aios-development-writer-state/revocation-journal.json",
"receipt_path": "/var/lib/aios-development-writer-evidence/revocation-receipt.json",
"revoked_grant_path": "/var/lib/aios-development-writer-state/grant.revoked.json",
"terminal_trigger_path": "/var/lib/aios-development-writer-state/terminal-revocation.json",
"writer_credential_name": "writer_gitea_http",
"writer_unit": "aios-governed-development-writer.service"
}
+8
View File
@@ -0,0 +1,8 @@
{
"exact_paths": [
"/usr/libexec/aios-autonomous-release-authorization/controller.py",
"/usr/libexec/aios-chatgpt-action-task-router-continuous-20260726/action_task_router.py"
],
"output_path": "/var/lib/aios-gitops/autonomous-control-plane/projection/runtime-source-evidence.json",
"task_id": "V2R1C4-RELEASE-COMPLETION"
}
+8
View File
@@ -0,0 +1,8 @@
{
"gitea_db_path": "/data/aios-gitops/runtime/gitea-bin/data/gitea.db",
"output_dir": "/var/lib/aios-gitops/autonomous-control-plane/watcher/status",
"owner_user_id": 2,
"poll_seconds": 5,
"repo_id": 1,
"requests_dir": "/var/lib/aios-gitops/autonomous-control-plane/watcher/requests"
}
+11
View File
@@ -0,0 +1,11 @@
{
"allowed_peer_uids": [0],
"audit_path": "/var/lib/aios-development-writer-evidence/audit.jsonl",
"grant_path": "/var/lib/aios-development-writer-state/grant.json",
"grant_quota_ledger": "/var/lib/aios-development-writer-state/grant-quota.sqlite",
"max_request_bytes": 4194304,
"operation_ledger": "/var/lib/aios-development-writer-state/operations.sqlite",
"policy_path": "/etc/aios-gitops/autonomous-control-plane/development-policy.json",
"socket_path": "/run/aios-development-writer-runtime/writer.sock",
"worktree_lock_path": "/var/lib/aios-development-writer-locks/worktree.lock"
}
@@ -0,0 +1,42 @@
[Unit]
Description=AIOS Autonomous Release Candidate (dormant shadow only)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=aiman
Group=gitops
WorkingDirectory=/data/aios-gitops/worktrees/chatgpt-autonomous-completion-contract-20260726/services/aios-autonomous-release-candidate
Environment=AIOS_GITOPS_WRITES_ENABLED=false
Environment=AIOS_TASK_PLANE_EXECUTION_ENABLED=false
Environment=AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
Environment=AIOS_PRODUCTION_DEPLOYMENT_ENABLED=false
Environment=AIOS_CANDIDATE_LOOPBACK_HOST=127.0.0.1
Environment=PYTHONDONTWRITEBYTECODE=1
ExecStart=/usr/bin/python3 -m aios_autonomous_release_candidate.service --host 127.0.0.1 --port 19951 --state /var/lib/aios-autonomous-release-candidate/state.sqlite3
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
LockPersonality=true
RestrictSUIDSGID=true
RestrictRealtime=true
MemoryDenyWriteExecute=true
RuntimeDirectory=aios-autonomous-release-candidate
StateDirectory=aios-autonomous-release-candidate
CacheDirectory=aios-autonomous-release-candidate
ReadOnlyPaths=/data/aios-gitops/worktrees/chatgpt-autonomous-completion-contract-20260726/services/aios-autonomous-release-candidate
ReadWritePaths=/run/aios-autonomous-release-candidate
ReadWritePaths=/var/lib/aios-autonomous-release-candidate
ReadWritePaths=/var/cache/aios-autonomous-release-candidate
UMask=0077
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,51 @@
[Unit]
Description=AIOS Autonomous Release Candidate Worker (Dormant/Shadow Only)
After=network.target
ConditionPathExists=/opt/aios-autonomous-release-candidate/aios_autonomous_release_candidate
[Service]
Type=simple
User=aiman
Group=gitops
UMask=0077
WorkingDirectory=/opt/aios-autonomous-release-candidate
Environment=PYTHONDONTWRITEBYTECODE=1
Environment=PYTHONPATH=/opt/aios-autonomous-release-candidate
Environment=AIOS_TASK_PLANE_EXECUTION_ENABLED=false
Environment=AIOS_GITOPS_WRITES_ENABLED=false
Environment=AIOS_PRODUCTION_DEPLOYMENT_ENABLED=false
Environment=AIOS_CANDIDATE_CONTROL_ENDPOINT=127.0.0.1:19951
Environment=AIOS_OPENCLAW_CREDENTIAL_REFERENCE=systemd-credential:openclaw-gateway-candidate
Environment=AIOS_CODEX_CREDENTIAL_REFERENCE=systemd-credential:codex-app-server-candidate
Environment=AIOS_NATIVE_CONTROL_CREDENTIAL_REFERENCE=systemd-credential:session-native-adapter-control-candidate
Environment=AIOS_GITEA_CREDENTIAL_REFERENCE=systemd-credential:gitea-admin-api-candidate
ImportCredential=openclaw-gateway-candidate
ImportCredential=codex-app-server-candidate
ImportCredential=session-native-adapter-control-candidate
ImportCredential=gitea-admin-api-candidate
ExecStart=/usr/bin/python3 -m aios_autonomous_release_candidate.worker_service --state-directory /var/lib/aios-autonomous-release-worker-candidate
StateDirectory=aios-autonomous-release-worker-candidate
RuntimeDirectory=aios-autonomous-release-worker-candidate
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
ProtectClock=true
ProtectHostname=true
LockPersonality=true
RestrictSUIDSGID=true
RestrictRealtime=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
IPAddressDeny=any
IPAddressAllow=localhost
ReadOnlyPaths=/opt/aios-autonomous-release-candidate
ReadWritePaths=/var/lib/aios-autonomous-release-worker-candidate
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,31 @@
[Unit]
Description=AIOS autonomous execution renewal controller
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/renewal.json
[Service]
Type=simple
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-autonomous-renewal-controller --config /etc/aios-gitops/autonomous-control-plane/renewal.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
UMask=0027
ReadWritePaths=/var/lib/aios-gitops/autonomous-control-plane/renewal /run/aios-gitops/autonomous-control-plane
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,24 @@
[Unit]
Description=AIOS governance approval watcher
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/watcher.json
[Service]
Type=simple
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-governance-approval-watcher --config /etc/aios-gitops/autonomous-control-plane/watcher.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ReadOnlyPaths=/data/aios-gitops/runtime/gitea-bin/data/gitea.db
ReadWritePaths=/var/lib/aios-gitops/autonomous-control-plane /run/aios-gitops/autonomous-control-plane
RestrictAddressFamilies=AF_UNIX
IPAddressDeny=any
UMask=0027
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,26 @@
[Unit]
Description=AIOS dormant single-owner machine-status prerequisite
RefuseManualStop=no
[Service]
Type=oneshot
User=aiman
Group=gitops
Environment=AIOS_SINGLE_OWNER_GOVERNANCE_ENABLED=false
Environment=AIOS_SINGLE_OWNER_ACTIVATION_ACTIVE=false
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/python3 -m aios_single_owner_governance.service --component machine-status-producer --self-check --checkpoint-dir /var/lib/aios-gitops/runtime/single-owner-governance
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX
ReadOnlyPaths=/data/aios-gitops/repo.git
ReadWritePaths=/var/lib/aios-gitops/runtime/single-owner-governance
@@ -0,0 +1,31 @@
[Unit]
Description=AIOS governance approval mirror worker
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/mirror.json
[Service]
Type=simple
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-governance-mirror-worker --config /etc/aios-gitops/autonomous-control-plane/mirror.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
UMask=0027
ReadWritePaths=/data/aios-gitops/repo.git /var/lib/aios-gitops/autonomous-control-plane/mirror /run/aios-gitops/autonomous-control-plane
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,26 @@
[Unit]
Description=AIOS dormant single-owner review adapter prerequisite
RefuseManualStop=no
[Service]
Type=oneshot
User=aiman
Group=gitops
Environment=AIOS_SINGLE_OWNER_GOVERNANCE_ENABLED=false
Environment=AIOS_SINGLE_OWNER_ACTIVATION_ACTIVE=false
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/python3 -m aios_single_owner_governance.service --component owner-review-adapter --self-check --checkpoint-dir /var/lib/aios-gitops/runtime/single-owner-governance
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX
ReadOnlyPaths=/data/aios-gitops/repo.git
ReadWritePaths=/var/lib/aios-gitops/runtime/single-owner-governance
@@ -0,0 +1,30 @@
[Unit]
Description=AIOS governance request publisher
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/publisher.json
[Service]
Type=simple
User=aios-governance-request-publisher
Group=gitops
StateDirectory=aios-governance-publisher-state aios-governance-publisher-evidence aios-governance-publisher-locks
StateDirectoryMode=0750
RuntimeDirectory=aios-governance-publisher-runtime
RuntimeDirectoryMode=0750
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-governance-request-publisher --config /etc/aios-gitops/autonomous-control-plane/publisher.json
LoadCredentialEncrypted=gitea_http:/etc/credstore.encrypted/aios-governance-request-publisher.gitea_http
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
RestrictSUIDSGID=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
IPAddressAllow=127.0.0.1
IPAddressDeny=any
UMask=0027
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,20 @@
[Unit]
Description=AIOS single-owner governance activation verifier
ConditionPathExists=/etc/aios-gitops/single-owner-activation-bindings.json
[Service]
Type=oneshot
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-single-owner-governance --verify --bindings /etc/aios-gitops/single-owner-activation-bindings.json --state-root /var/lib/aios-gitops/governance-activation --lock-path /run/aios-gitops/governance-activation.lock
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/aios-gitops/governance-activation /run/aios-gitops
RestrictSUIDSGID=true
UMask=0027
# Deliberately not installable. Deployment remains disabled/inactive;
# activation is an explicit approved CLI transaction, never an always-on unit.
@@ -0,0 +1,28 @@
[Unit]
Description=AIOS governed development writer credential revoker
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/development-policy.json
[Service]
Type=oneshot
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-development-writer-revoker --config /etc/aios-gitops/autonomous-control-plane/revoker.json
LoadCredentialEncrypted=writer_gitea_http:/etc/credstore.encrypted/aios-governed-development-writer.gitea_http
LoadCredentialEncrypted=admin_gitea_http:/etc/credstore.encrypted/aios-governance-admin.gitea_http
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
UMask=0027
ReadWritePaths=/var/lib/aios-development-writer-state /var/lib/aios-development-writer-evidence /var/lib/aios-development-writer-locks /run/aios-development-writer-runtime
@@ -0,0 +1,11 @@
[Unit]
Description=AIOS governed development writer revocation timer
[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
AccuracySec=30s
Unit=aios-governed-development-writer-revoker.service
[Install]
WantedBy=timers.target
@@ -0,0 +1,37 @@
[Unit]
Description=AIOS governed development writer
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/development-policy.json
[Service]
Type=simple
User=aios-governed-development-writer
Group=gitops
StateDirectory=aios-development-writer-state aios-development-writer-evidence aios-development-writer-locks
StateDirectoryMode=0750
RuntimeDirectory=aios-development-writer-runtime
RuntimeDirectoryMode=0750
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-development-writer-server --config /etc/aios-gitops/autonomous-control-plane/writer-server.json
LoadCredentialEncrypted=gitea_http:/etc/credstore.encrypted/aios-governed-development-writer.gitea_http
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX AF_INET
IPAddressAllow=127.0.0.1
IPAddressDeny=any
ReadWritePaths=/data/aios-gitops/worktrees/v2r1c4-security-invariants-v3-20260729
UMask=0027
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,23 @@
[Unit]
Description=AIOS Integration Refresh Provisioner (sandbox control plane)
After=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
User=aios
Group=aios
Environment=AIOS_GITOPS_WRITES_ENABLED=false
Environment=AIOS_INTEGRATION_REFRESH_MODE=sandbox
Environment=AIOS_CREDENTIAL_PROVIDER=disabled
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/aios/integration-refresh
RestrictAddressFamilies=AF_UNIX
IPAddressDeny=any
ExecStart=/usr/bin/python3 /opt/aios/active-runtime/app/aios_isolated_writer_api/integration_refresh.py --sandbox-preflight --state-dir /var/lib/aios/integration-refresh
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,31 @@
[Unit]
Description=AIOS exact release object projection
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/release-projection.json
[Service]
Type=simple
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-release-object-projector --config /etc/aios-gitops/autonomous-control-plane/release-projection.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
UMask=0027
ReadWritePaths=/var/lib/aios-gitops/autonomous-control-plane/projection /run/aios-gitops/autonomous-control-plane
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,28 @@
[Unit]
Description=AIOS exact runtime source read projection
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/runtime-projection.json
[Service]
Type=oneshot
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-runtime-source-projector --config /etc/aios-gitops/autonomous-control-plane/runtime-projection.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
UMask=0027
ReadWritePaths=/var/lib/aios-gitops/autonomous-control-plane/projection /run/aios-gitops/autonomous-control-plane
PrivateNetwork=true
@@ -0,0 +1,29 @@
[Unit]
Description=AIOS V2R1C4 isolated candidate tag and health fixture
After=network.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/candidate-fixture.json
[Service]
Type=simple
User=aios-v2r1c4-candidate
Group=gitops
StateDirectory=aios-v2r1c4-candidate
StateDirectoryMode=0750
RuntimeDirectory=aios-v2r1c4-candidate
RuntimeDirectoryMode=0750
ExecStart=/usr/bin/aios-v2r1c4-candidate-fixture --config /etc/aios-gitops/autonomous-control-plane/candidate-fixture.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_INET AF_UNIX
IPAddressAllow=127.0.0.1
IPAddressDeny=any
UMask=0027
@@ -0,0 +1,12 @@
[Unit]
Description=AIOS V2R1C4 isolated candidate integration merge socket
[Socket]
ListenStream=/run/aios-v2r1c4-candidate/integration-merge.sock
SocketMode=0600
DirectoryMode=0750
Accept=yes
RemoveOnStop=yes
[Install]
WantedBy=sockets.target
@@ -0,0 +1,28 @@
[Unit]
Description=AIOS V2R1C4 isolated candidate merge request
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/candidate-fixture.json
[Service]
Type=oneshot
User=aios-v2r1c4-candidate
Group=gitops
StateDirectory=aios-v2r1c4-candidate
StateDirectoryMode=0750
StandardInput=socket
StandardOutput=socket
StandardError=journal
ExecStart=/usr/bin/aios-v2r1c4-candidate-fixture --merge-stdio --config /etc/aios-gitops/autonomous-control-plane/candidate-fixture.json
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_UNIX
UMask=0027
@@ -0,0 +1,29 @@
[Unit]
Description=AIOS V2R1C4 unified governed release envelope executor
After=network-online.target
ConditionPathExists=/etc/aios-gitops/autonomous-control-plane/release-hooks.json
ConditionPathExists=/var/lib/aios-gitops/autonomous-control-plane/release/envelope.json
[Service]
Type=oneshot
User=root
Group=gitops
Environment=AIOS_GITOPS_WRITES_ENABLED=false
ExecStart=/usr/bin/aios-v2r1c4-release-executor --config /etc/aios-gitops/autonomous-control-plane/release-hooks.json --envelope /var/lib/aios-gitops/autonomous-control-plane/release/envelope.json --operation-id v2r1c4-production-release
LoadCredentialEncrypted=gitea_http:/etc/credstore.encrypted/aios-release-executor.gitea_http
LoadCredentialEncrypted=tag_api:/etc/credstore.encrypted/aios-release-executor.tag_api
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelLogs=true
RestrictSUIDSGID=true
RestrictRealtime=true
LockPersonality=true
MemoryDenyWriteExecute=true
UMask=0027
ReadWritePaths=/var/lib/aios-gitops/autonomous-control-plane/release /var/lib/aios-gitops/release /opt/aios /run/aios-gitops/autonomous-control-plane
@@ -0,0 +1,16 @@
d /var/lib/aios-gitops/autonomous-control-plane 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/mirror 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/projection 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/renewal 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/release 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/watcher 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/watcher/requests 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/watcher/status 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/mirror/requests 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/mirror/receipts 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/projection/requests 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/projection/receipts 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/projection/releases 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/renewal/requests 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/renewal/receipts 0750 root gitops -
d /var/lib/aios-gitops/autonomous-control-plane/release/metadata-snapshots 0750 root gitops -
@@ -0,0 +1,4 @@
d /var/lib/aios-gitops/governance-activation 0750 root gitops -
d /var/lib/aios-gitops/governance-activation/wal 0750 root gitops -
d /var/lib/aios-gitops/governance-activation/receipts 0750 root gitops -
d /run/aios-gitops 0750 root gitops -
@@ -0,0 +1,71 @@
# AIOS Autonomous Release Agent Deployment Instructions
## Objective
Deploy only candidate/shadow environments first. Production activation requires a separate owner release approval.
## Agent execution order
1. Verify git references:
- local
- authoritative bare
- remote
- Gitea API
2. Build candidate artifact.
3. Run:
- unit tests
- security scans
- secret scans
- artifact verification
4. Start candidate workers:
- OpenClaw native adapter
- Codex native adapter
- dedicated writer
5. Execute shadow task:
```
TaskPlan
-> Planner
-> Worker Router
-> Session lifecycle
-> Evidence chain
-> Artifact verification
-> ReleasePlan
```
## Hard restrictions
Never:
- write main directly
- force push
- rewrite tags
- export secrets
- bypass owner approval
- modify production flags during candidate validation
## Production release gate
Require:
```
owner_approval=true
artifact_verified=true
evidence_closure=true
rollback_ready=true
remote_tag_verified=true
baseline_verified=true
registry_verified=true
```
Until then keep:
```
AIOS_GITOPS_WRITES_ENABLED=false
AIOS_TASK_PLANE_EXECUTION_ENABLED=false
AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
```
+34
View File
@@ -0,0 +1,34 @@
# AIOS Autonomous Release Candidate 架构
本 Candidate 把规划、工作流、凭据引用、原生会话、证据和发布控制拆成独立边界。它只负责验证约束,不拥有生产授权。
## 信任边界
- Owner Approval 的签名和撤销状态来自外部 HSM/KMS 或可信 Approval Plane。Candidate 只有 verifier,没有 signer。
- Secret Manager V2 只返回 `systemd-credential:*` 或受控的 Candidate reference,不返回认证正文。
- OpenClaw、Codex 和 Gitea provider 身份由管理面供应;模拟 provider 永远不能把原生 canary 标成已验证。
- Writer 只写任务绑定分支和允许路径。生产 main、tag、baseline、registry 和部署不属于 Candidate 权限。
## 核心模块
- `models.py`:TaskPlan、Approval、Credential、Result 和 ReleasePlan 强类型约束。
- `store.py`:私有 SQLite、WAL、全同步、schema 检查、事务和原子 step transition。
- `workflow.py`:依赖、claim、lease、retry、timeout recovery 和终态。
- `credential.py` / `secret_manager.py`:reference-only 生命周期、补偿撤销、跨任务拒绝和 post-revocation 验证。
- `native_adapters.py`:OpenClaw/Codex 原生 provider ID、parent/child tree、status、interrupt、close 和纯文本回执。
- `gitea_canary.py`:仅通过 deploy-key provider 的 list/create/delete 操作完成 canary 与撤销验证。
- `evidence.py`:落库的哈希链、重启回放、篡改检测和 required-event closure。
- `artifact.py`:确定性 tar、逐文件哈希、package closure、链接/特殊文件/敏感标记拒绝。
- `release.py` / `release_gate.py`:部署审批与回滚审批分离,tag object 与 peeled target 分离验证。
## 会话真实性
以下状态必须分别记录,不能互相替代:
```text
broker_session_verified
openclaw_native_child_session_verified
codex_child_session_verified
```
Shadow provider 只能证明 Broker 合同和清理路径,不能证明 OpenClaw 或 Codex 原生会话。
@@ -0,0 +1,133 @@
# AIOS V2R1C4 Dormant Shadow-Only Release Execution
## Purpose
Deploy verified V2R1C4 code while keeping autonomous execution capabilities disabled.
This release separates code deployment from capability activation. Capability activation requires a later, independently approved release.
## Deployment mode
```text
deployment_mode=dormant_shadow_only
```
Required production flags:
```text
AIOS_GITOPS_WRITES_ENABLED=false
AIOS_TASK_PLANE_EXECUTION_ENABLED=false
AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
```
Required dispatch transport:
```text
protectedDispatchTransport=sandbox
```
Disabled capabilities:
```text
native_openclaw_enabled=false
native_codex_enabled=false
automatic_release_enabled=false
production_side_effects=false
activation_deferred=true
```
## Release flow
```text
Integration verification
|
v
Owner dormant release approval
|
v
Merge PR
|
v
Read final main merge OID
|
v
Rebuild production artifact
|
v
Deploy dormant runtime
|
v
Create V2R1C4 tag
|
v
Verify Registry and Baseline consistency
```
## Two-stage approval model
### Pre-merge approval
The pre-merge approval binds:
- version
- PR number
- integration OID and tree OID
- candidate artifact and evidence hashes
- deployment mode
- all production execution flags remaining false
It authorizes the governed merge and production artifact rebuild. It does not predeclare the final production target OID.
### Final release approval
After the governed merge, the final approval binds:
- final main merge OID
- final main tree OID
- production artifact, manifest, package closure, and evidence closure
- rollback artifact and production configuration hashes
- V2R1C4 tag target
The integration OID must never be used as the final production target OID.
## Deferred activation
The following are separate activation gates and must not block dormant code deployment:
- OpenClaw native session provider
- Codex app-server provider
- Gitea Admin API automation
- Secret Manager V2
- autonomous production execution
They require a later activation release with separate evidence and approval.
## Hard restrictions
Never:
- write main directly
- force push
- rewrite tags
- export secrets
- enable autonomous production execution without approval
- treat integration OID as production target OID
- update Registry or Baseline before remote and Gitea tag verification
## Dormant production acceptance
A dormant deployment is acceptable only when:
```text
deployment_mode=dormant_shadow_only
production_side_effects=false
protectedDispatchTransport=sandbox
native_openclaw_enabled=false
native_codex_enabled=false
automatic_release_enabled=false
AIOS_GITOPS_WRITES_ENABLED=false
AIOS_TASK_PLANE_EXECUTION_ENABLED=false
AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
```
The release report must preserve deferred activation blockers rather than falsely marking native-agent or automatic-release capabilities as enabled.
@@ -0,0 +1,82 @@
# AIOS Autonomous Release Execution Package
## Release Strategy
V2R1C4 uses a two-stage model:
1. Dormant code deployment.
2. Capability activation through a separate approved release.
## Dormant Deployment
The first production release must keep autonomous execution disabled:
```text
AIOS_GITOPS_WRITES_ENABLED=false
AIOS_TASK_PLANE_EXECUTION_ENABLED=false
AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
```
Required mode:
```text
deployment_mode=dormant_shadow_only
```
Required properties:
```text
production_side_effects=false
native_openclaw_enabled=false
native_codex_enabled=false
automatic_release_enabled=false
```
## Deployment Sequence
```text
Verify Integration
|
v
Owner Dormant Release Approval
|
v
Merge Pull Request
|
v
Read final main merge OID
|
v
Build Production Artifact
|
v
Deploy Dormant Runtime
|
v
Create Version Tag
|
v
Verify Registry and Baseline
```
## Capability Activation (Separate)
The following require separate approval and evidence:
- OpenClaw native provider
- Codex app-server provider
- Gitea Admin API lifecycle
- Secret Manager V2
- Autonomous production execution
## Hard Governance Rules
Never:
- direct write main
- force push
- rewrite tags
- export credentials
- enable autonomous production execution without approval
- use integration OID as production target OID
- update Baseline before remote tag verification
@@ -0,0 +1,35 @@
{
"execution_renewal_manifest_blob_oid": "417f78abb3d795f7b0c04a0894069bd166bb15df",
"execution_renewal_manifest_sha256": "069091eff9c7c46bceccde365da6d07a8538e76bee9e288a57211f3114b94ab3",
"execution_renewal_merge_oid": "3a22c3c7d86930efd4bd93ac05d80ad322050cb9",
"observed_at": "2026-07-28T09:09:27.841968Z",
"runtime_source_evidence_sha256": "23f03d9c6abe6f11e1acda5210b8708696e3b77caa0083b6bfaef30a44b2a35f",
"runtime_source_observed_at": "2026-07-28T05:53:01.253909Z",
"schema": "aios.integration-refresh-source-map/v1",
"source_mapping_approval_merge_oid": "9514062cf33e45941abe4a8c98377e0713b0b3f6",
"source_mapping_manifest_blob_oid": "00c5e90e529cb98c7750a5761b0a0d6ccf507174",
"source_mapping_manifest_sha256": "17af8ebc43673c0e46bb9ab1bf44497e8c147f1b4a9d7a8a404edd5c0abd6f21",
"sources": [
{
"byte_for_byte_equal": true,
"canonical_blob_oid": "9c68be36e0b6a18260e3099e3d7b0dcab6d814aa",
"canonical_commit_oid": "85426f4f570e4d40b212318d47e52e4aed5cb06a",
"canonical_git_path": "active-runtime/app/aios_autonomous_release_authorization/controller.py",
"canonical_tree_oid": "cdbd9bb845b18d4b5224d91aace2656a51eb7c14",
"runtime_blob_oid": "9c68be36e0b6a18260e3099e3d7b0dcab6d814aa",
"runtime_path": "/usr/libexec/aios-autonomous-release-authorization/controller.py",
"runtime_sha256": "39b532c3058c4ae49ed691d7c66c3b7745a25111fa61039f388c8335fd262c50"
},
{
"byte_for_byte_equal": true,
"canonical_blob_oid": "ee0595ca61a0598f8cb3dc10865a255e21679b2a",
"canonical_commit_oid": "85426f4f570e4d40b212318d47e52e4aed5cb06a",
"canonical_git_path": "active-runtime/app/aios_chatgpt_action_task_router/action_task_router.py",
"canonical_tree_oid": "cdbd9bb845b18d4b5224d91aace2656a51eb7c14",
"runtime_blob_oid": "ee0595ca61a0598f8cb3dc10865a255e21679b2a",
"runtime_path": "/usr/libexec/aios-chatgpt-action-task-router-continuous-20260726/action_task_router.py",
"runtime_sha256": "738fb7035a6b792115d6467b4d1e4ffd47a8c5d5646f7032ebc68ea587cbd554"
}
],
"task_id": "AIOS-INTEGRATION-REFRESH-PROVISIONER-IMPLEMENTATION-20260726"
}
+48
View File
@@ -0,0 +1,48 @@
# Candidate 运维与验收
## 安全默认值
两个 systemd 模板均为 Dormant/Shadow-only,绑定 loopback,默认关闭 Task Plane 执行、GitOps 写入和生产部署。模板进入仓库不等于安装或启动服务。
外部信任根缺失时必须保留以下阻断:
```text
BLOCKED_OWNER_APPROVAL_VERIFIER_UNAVAILABLE
BLOCKED_GITEA_ADMIN_CREDENTIAL_REQUIRED
BLOCKED_EXTERNAL_OWNER_SIGNATURE
```
不得用模拟身份、个人账户或生产 provider 身份替代这些根。
## 独立验收
从仓库根目录运行:
```text
PYTHONPATH=services/aios-autonomous-release-candidate \
python3 -m pytest -p no:cacheprovider -q tests/autonomous_release
PYTHONPATH=services/aios-autonomous-release-candidate \
python3 scripts/autonomous-release/run_acceptance.py \
--repo-root . \
--output /task-evidence/candidate-acceptance.json
```
Acceptance report 必须满足:
```text
all_passed=true
skipped=0
direct_gitea_database_access=false
production_path_hits=[]
secret_hits=[]
production_side_effects=false
```
## Artifact
Artifact builder 拒绝覆盖现有文件、链接、硬链接、特殊文件、仓库元数据和敏感内容标记。输出 tar 和 manifest 后必须再次执行 `ArtifactBuilder.verify`。
## 外部 canary
真实 native session 与 Gitea canary 只能在任务绑定的 runtime credential 投影存在时运行。每次 canary 完成后必须关闭 provider session、撤销上游对象、删除 projection,并保留非敏感回执。
+26
View File
@@ -0,0 +1,26 @@
# Governed ReleasePlan 关闭条件
ReleasePlan 必须绑定 task、repository、integration branch、完整 target/tree OID、artifact/manifest/evidence/rollback digest、生产配置 digest,以及互不相同的部署和回滚 ApprovalPlan ID。
## Candidate 与 Integration
1. Candidate 分支先完成测试、扫描、Shadow、Artifact 和外部门禁盘点。
2. 重新读取 authoritative `main` 完整 OID。
3. 从该 OID 创建 integration 分支。
4. 使用普通 `merge --no-ff` 合入 Candidate;禁止 squash、rebase、amend 和 force push。
5. 在 integration 上重新执行全部测试、扫描和 artifact closure。
## 生产停止线
下列项目任一为 false,流程必须停止在 `READY_FOR_OWNER_RELEASE_APPROVAL`,不得部署或创建生产 tag:
```text
openclaw_native_child_session_verified
codex_child_session_verified
gitea_admin_api_lifecycle_canary
owner_signer_separation_verified
credential_incident_closed
external_owner_release_approval_verified
```
聊天文本、Candidate 自签记录或模拟 canary 不能改变这条停止线。
@@ -0,0 +1,414 @@
# AIOS V2R1C4 Dormant Release — Final Agent Execution Contract
## 1. Purpose
This document is the machine/operator execution contract for completing the governed V2R1C4 dormant release after Candidate development is frozen.
It does not grant production authority. Every consequential action remains subject to the exact approval, Git reference, artifact, tag, Registry and Baseline gates defined below.
## 2. Release mode
The only permitted deployment mode for V2R1C4 is:
```text
deployment_mode=dormant_shadow_only
```
The following values are mandatory before, during and after deployment:
```text
AIOS_GITOPS_WRITES_ENABLED=false
AIOS_TASK_PLANE_EXECUTION_ENABLED=false
AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
AIOS_PRODUCTION_DEPLOYMENT_ENABLED=false
production_side_effects=false
native_openclaw_enabled=false
native_codex_enabled=false
automatic_release_enabled=false
activation_deferred=true
protectedDispatchTransport=sandbox
```
Any deviation is a hard stop.
## 3. Authoritative branches
```text
candidate_branch=patch/chatgpt-autonomous-completion-contract-20260726
integration_branch=integration/chatgpt-autonomous-completion-20260726
production_branch=main
version=V2R1C4
pull_request=20
```
Never infer a target OID from workspace HEAD. Always read and record full 40-character OIDs.
## 4. Phase A — Candidate freeze and verification
1. Read the current Candidate OID and tree OID.
2. Verify the Candidate worktree is clean.
3. Verify four-way Candidate reference closure:
- local branch ref;
- authoritative bare ref;
- `git ls-remote` ref;
- Gitea API branch ref.
4. Run the complete test and static validation suite defined in `V2R1C4_TEST_AND_RELEASE_CHECKLIST.md`.
5. Build the deterministic Candidate artifact and manifest from the exact Candidate OID.
6. Record:
- artifact SHA-256;
- manifest SHA-256;
- package closure SHA-256;
- test evidence SHA-256;
- rollback artifact SHA-256;
- production configuration SHA-256.
7. Do not reuse any digest generated from an older Candidate OID.
Failure state:
```text
CANDIDATE_ACCEPTANCE_BLOCKED
```
## 5. Phase B — Integration refresh
1. Refresh the Integration branch from the latest Candidate using a governed non-fast-forward merge.
2. Use:
```text
merge --no-ff
```
3. Do not squash, rebase, force push or rewrite Candidate history.
4. Verify the Candidate OID is reachable from the new Integration OID.
5. Verify four-way Integration reference closure.
6. Run the full Candidate test suite again from the Integration worktree.
7. Rebuild Integration evidence and Candidate package metadata if any tracked file changed during the merge.
Failure state:
```text
INTEGRATION_ACCEPTANCE_BLOCKED
```
## 6. Phase C — Candidate acceptance
Create Candidate acceptance evidence and execute:
```text
python scripts/autonomous-release/run_acceptance.py \
--phase candidate \
--input <candidate-evidence.json> \
--output <candidate-acceptance.json>
```
The result must contain:
```text
phase=candidate
status=READY
production_action_authorized=false
```
The Candidate gate must verify:
```text
candidate_four_way_ref_closure=true
integration_four_way_ref_closure=true
candidate_reachable_from_integration=true
worktree_clean=true
tests_failed=0
tests_passed>0
```
It must also verify all dormant runtime flags remain disabled.
`READY` authorizes review only. It does not authorize merge, deployment, tagging, Registry writes or Baseline writes.
## 7. Phase D — Pre-merge owner approval
Obtain a governed Owner approval plan for the exact Integration package.
The approval subject must bind at least:
```text
version
pull_request
candidate_oid
candidate_tree_oid
integration_oid
integration_tree_oid
candidate_acceptance_digest
candidate_release_digest
artifact_sha256
manifest_sha256
package_closure_sha256
evidence_closure_oid
rollback_artifact_sha256
production_config_sha256
deployment_mode=dormant_shadow_only
all execution flags=false
```
The approval must not predeclare the final production target OID.
Without an Owner-approved plan, stop with:
```text
BLOCKED_EXTERNAL_OWNER_SIGNATURE
```
## 8. Phase E — Governed merge
1. Merge PR #20 only through the governed merge path.
2. Do not push directly to `main`.
3. After merge, read the exact resulting `main` merge OID and tree OID.
4. Verify four-way `main` reference closure.
5. Verify the merged Integration OID is reachable from the final `main` merge OID.
6. Never use the Integration OID as the production target OID.
Failure state:
```text
MAIN_RECONCILIATION_REQUIRED
```
## 9. Phase F — Production artifact rebuild
Rebuild all production artifacts from the exact final `main` merge OID.
Record new values for:
```text
artifact_sha256
manifest_sha256
package_closure_sha256
evidence_closure_oid
rollback_artifact_sha256
production_config_sha256
```
Candidate or Integration artifacts may not be promoted by renaming or metadata substitution. The final artifact must be demonstrably rebuilt from the final production target.
## 10. Phase G — Final release digest and Owner approval
1. Construct the `FinalDormantRelease` object using the final `main` target and rebuilt artifact evidence.
2. Compute its exact `release_digest`.
3. Obtain an Owner approval receipt bound to that exact digest.
4. Record:
```text
approval_plan_id
approval_receipt_sha256
approved_release_digest
owner_approval_verified=true
```
Required equality:
```text
approved_release_digest == FinalDormantRelease.digest()
```
A generic approval, previous approval, Candidate approval or Integration approval is insufficient.
## 11. Phase H — Final acceptance
Execute:
```text
python scripts/autonomous-release/run_acceptance.py \
--phase final \
--input <final-evidence.json> \
--output <final-acceptance.json>
```
The result must contain:
```text
phase=final
status=READY
production_action_authorized=false
```
Required final evidence:
```text
main_four_way_ref_closure=true
target_is_main_head=true
worktree_clean=true
artifact_rebuilt_from_target=true
rollback_verified=true
runtime_boundary_verified=true
owner_approval_verified=true
approved_release_digest=<exact final release digest>
```
The acceptance report is evidence, not an execution credential.
## 12. Phase I — Dormant deployment
Deployment requires a separate production execution approval referencing:
```text
version=V2R1C4
target_oid=<final main merge OID>
evidence_closure_oid=<final evidence closure OID>
approval_plan_id=<approved plan>
final_acceptance_digest=<final acceptance digest>
```
Deploy only the dormant runtime. Before starting services, verify all disabled flags and the sandbox transport in the rendered production configuration.
After start, verify:
```text
services_active=true
loopback_bindings_only=true
production_side_effects=false
write_endpoints_disabled=true
task_plane_execution_disabled=true
silent_release_execution_disabled=true
native_agent_execution_disabled=true
```
If any side-effect-capable path is active, stop services and mark:
```text
DORMANT_RUNTIME_BOUNDARY_VIOLATION
```
## 13. Phase J — Tag governance
Tagging is permitted only after dormant deployment verification and exact Owner approval.
Every tag request must carry:
```text
version=V2R1C4
target_oid=<full final main merge OID>
evidence_closure_oid=<full final evidence closure OID>
approval_plan_id=<approved plan ID>
```
When an existing same-name tag is found:
- identical tag OID and peeled target: treat as idempotent and reverify;
- different tag OID or peeled target: stop with `MANUAL_OWNER_REVIEW_REQUIRED`.
Never force push, delete, move or rewrite a formal tag.
## 14. Phase K — Remote and Gitea tag acceptance
Before any Registry or Baseline update, verify:
```text
local_tag_exists=true
remote_tag_exists=true
gitea_api_tag_exists=true
local_tag_oid == remote_tag_oid
remote_peeled_target_oid == target_oid
gitea_peeled_target_oid == target_oid
repository_identity=aios/aios
```
For annotated tags, verify both the tag object and peeled commit.
Failure state:
```text
REMOTE_PUSH_PENDING
```
or:
```text
RECONCILIATION_REQUIRED
```
## 15. Phase L — Registry and Baseline
Only after remote and Gitea tag acceptance:
1. register or update the V2R1C4 Registry entry;
2. reread the Registry and verify the exact target OID;
3. update the Production Baseline to V2R1C4;
4. reread the Baseline;
5. run final release consistency acceptance.
Required equality:
```text
Registry version
= Production Baseline
= local refs/tags/V2R1C4
= remote refs/tags/V2R1C4
= Gitea API tag
= expected final main target
```
Do not write `PRODUCTION_DEPLOYED` before this equality is proven.
## 16. Rollback
If deployment verification fails:
1. disable the V2R1C4 Candidate services;
2. preserve evidence and logs;
3. submit a governed rollback request with the target version and reason;
4. distinguish `requested`, `approved`, `executed` and `verified` states.
Do not delete tags, rewrite history or independently perform a production rollback.
## 17. Mandatory stop conditions
Stop without consequential execution when any of the following is missing or false:
```text
four_way_ref_closure
clean_worktree
full_test_closure
artifact_digest_verification
rollback_evidence
runtime_boundary_verification
exact_owner_approval
exact_target_oid
exact_evidence_closure_oid
exact_approval_plan_id
remote_tag_verification
gitea_tag_verification
```
## 18. Final report schema
Return:
```text
execution_status=COMPLETED|PARTIALLY_COMPLETED|BLOCKED|FAILED
candidate_oid=<full OID>
integration_oid=<full OID>
main_target_oid=<full OID>
artifact_sha256=<digest>
manifest_sha256=<digest>
package_closure_sha256=<digest>
evidence_closure_oid=<full OID>
candidate_acceptance_status=<status>
final_acceptance_status=<status>
owner_approval_verified=<bool>
dormant_deployment_verified=<bool>
local_tag_verified=<bool>
remote_tag_verified=<bool>
gitea_tag_verified=<bool>
registry_verified=<bool>
baseline_verified=<bool>
release_consistency=<status>
```
Always include:
```text
force_push_used: false
tag_rewritten: false
direct_main_push: false
secrets_committed: false
owner_approval_respected: true
```
@@ -0,0 +1,30 @@
# AIOS V2R1C4 Dormant Release Agent Execution
## Scope
This package is a dormant, shadow-only Candidate release. It does not authorize a production deployment, tag, baseline update, registry update, or a write to main.
## Required runtime boundary
deployment_mode=dormant_shadow_only
AIOS_GITOPS_WRITES_ENABLED=false
AIOS_TASK_PLANE_EXECUTION_ENABLED=false
AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
production_side_effects=false
## Governed sequence
1. Verify the Integration branch with the Candidate test suite and four-way Git reference closure.
2. Obtain Owner approval for dormant review only.
3. Merge only after a separate production release approval; this document does not grant that approval.
4. Read the resulting main merge OID before building an artifact.
5. Deploy only the dormant Candidate runtime after explicit production approval.
6. Create a tag and update Registry or Baseline only under their separate governed approvals.
## Evidence requirements
The execution agent must retain task ID, commit OID, artifact and manifest digests, test evidence, rollback package reference, and approval receipt metadata. It must not include plaintext credentials or private keys.
## Stop conditions
Stop with NOT_EXECUTED if any approval, four-way reference closure, artifact verification, or deployment gate is absent. Do not infer production authorization from Candidate authorization.
@@ -0,0 +1,65 @@
{
"evidence_type": "FULL_PACKAGE_FILE_MANIFEST_DRIFT_CLOSURE",
"release": "V2R1C4",
"entries": [
{
"path": "VERSION",
"old_sha256": "1095953d5764d9c72f02e84b1d525e265d3a67a5bdb451ab9ef51a8e8b3032b8",
"new_sha256": "b090062a92aeb14211bbfc1fcd43b5ee4f315d30054b437f3bcdac657210ee95",
"source_commit": "9917145a643c7938a1a4f4f72690674f13f4c3dd",
"reason": "V2R1C4 release completion froze the candidate package version",
"resolution": "accept the V2R1C4 candidate content and update only this manifest entry"
},
{
"path": "active-runtime/app/aios_gitops_model_api.py",
"old_sha256": "ee6e4fc6bc98a590fbc3585b62707e2562115e5a3f722e69a7c464d966bdc458",
"new_sha256": "a664714bc1e13160cdd0dc32de460c65a83a3a95aa5cdad1833b1b650ab90e9d",
"source_commit": "45dd78ec796faf9fdfba397e5bab73176aeef3f6",
"reason": "tracked GitOps API gained the governed short-link and webhook endpoint",
"resolution": "accept current tracked content and update only this manifest entry"
},
{
"path": "config/domains.env",
"old_sha256": "a3872f24e4cd64288758846ecd0b374db4aa41111feec3b17c41438136d6d5d0",
"new_sha256": "5a27d48db343dcb723bcc1d9d8222aa3f72094c57cc43640aebe6558963bd20f",
"source_commit": "e7d36ad706473c95a4d4b9ec791120271ed856cd",
"reason": "tracked authentication routing made cnnetmkt Casdoor the primary endpoint",
"resolution": "accept current tracked content and update only this manifest entry"
},
{
"path": "scripts/install_v1r1c0_gitops_model_overlay.sh",
"old_sha256": "4d54a4ed6d35bbb6e9fe2924f3cfceeea9c3eed898017788f6c5ab8041394a47",
"new_sha256": "e76cd986d2387b76439e4a7fe503e48a2de8fc70fb52c45a13641c9d943f108f",
"source_commit": "a2481421589e167680e7d801433758c6a01db832",
"reason": "tracked installer added online Codex patch-branch synchronization",
"resolution": "accept current tracked content and update only this manifest entry"
},
{
"path": "scripts/package_contract_check_v1r1c0.sh",
"old_sha256": "e0abd8ad44d4f088108f2046fd9d7bbd4465af50f79bd3b9fcbb72a8c61bee65",
"new_sha256": "f537c58fc08685601f47fac5c0a3a2856e3ce9806c1918848c87a194a49c28a0",
"source_commit": "9917145a643c7938a1a4f4f72690674f13f4c3dd",
"reason": "release completion generalized the legacy version check without weakening required files or compilation checks",
"resolution": "accept the generalized semantic version check and update only this manifest entry"
},
{
"path": "scripts/release_version.sh",
"old_sha256": "abef8df642c6d233af4a03c512876b02b326e19c924020b8dd8cc74236d18817",
"new_sha256": "14ab40a7c342e21e8315def14d552dcff4b214d23f1f4be493e9d3fc2cee1a2f",
"source_commit": "27a0ae126b96d63c40544174e7a3859e30eba056",
"reason": "tracked release helper closed tag-publication governance gaps",
"resolution": "accept current tracked content and update only this manifest entry"
}
],
"verifier_change": {
"path": "package_verify_full.sh",
"old_sha256": "b77bce1ca78cede27de6594e25f6ce5bb0c4990c0953eeb79f7e2608d2515c32",
"new_sha256": "ca49f4165b50171968485ffa5535bc33d2158237ea55af10a3888a5fa0f7a535",
"source_commit": "V2R1C4 release completion candidate",
"reason": "remove the checksum failure suppression and fail closed when the manifest is absent or mismatched",
"resolution": "update only the verifier self-entry after the six historical drifts were closed"
},
"entry_count": 6,
"whole_manifest_regenerated": false,
"verifier_fail_closed": true
}
@@ -0,0 +1,14 @@
# Agent Integration Plan
1. Verify package SHA-256 and FILE_SHA256.json.
2. Apply added/modified source files to patch/v2r1c4-release-completion-20260729.
3. Do not copy __pycache__, .pytest_cache, TEST_RECEIPT.json, or local package metadata into runtime paths.
4. Preserve existing approved WeChat and single-owner activation Git objects.
5. Install the Python package and verify every pyproject console entrypoint.
6. Render environment-specific JSON configs from config/examples.
7. Use systemd encrypted credentials only; never persist plaintext tokens.
8. Run compileall, all repository tests, systemd unit verification, secret scan, and online copied-Gitea acceptance.
9. Build one autonomous-control-plane Artifact and rollback Artifact.
10. Create one Owner approval for AIOS_AUTONOMOUS_RELEASE_CONTROL_PLANE_BOOTSTRAP.
11. After deployment, complete V2R1C4 code freeze and create one V2R1C4_PRODUCTION_RELEASE_ENVELOPE.
12. Do not split unchanged code/artifact/permission scope into additional approvals.
@@ -0,0 +1,78 @@
{
"capabilities": {
"approval_mirror_worker": "DELIVERED",
"approval_watcher": "DELIVERED",
"artifact_atomic_deployment": "DELIVERED",
"automatic_renewal_controller": "DELIVERED",
"credential_revoker_with_old_token_401": "DELIVERED",
"governance_request_publisher": "DELIVERED",
"governed_development_writer_server": "DELIVERED",
"governed_merge_transport": "DELIVERED",
"governed_tag_transport": "DELIVERED",
"grant_quota_idempotency": "DELIVERED",
"grant_revocation_evidence": "DELIVERED",
"health_rollback_restore": "DELIVERED",
"owner_exact_head_release_approval_verification": "DELIVERED",
"registry_baseline_snapshot_compensation": "DELIVERED",
"release_object_projection": "DELIVERED",
"remote_tag_and_final_consistency": "DELIVERED",
"runtime_source_projection": "DELIVERED",
"task_bound_writer_grant": "DELIVERED",
"unified_release_envelope_executor": "DELIVERED"
},
"delivery_status": "CODE_COMPLETE_OFFLINE_VALIDATED",
"direct_main_push": false,
"entrypoints": {
"aios-autonomous-control-plane": "aios_autonomous_control_plane.cli:main",
"aios-autonomous-renewal-controller": "aios_autonomous_control_plane.renewal_service:main",
"aios-development-writer-revoker": "aios_autonomous_control_plane.revoker:main",
"aios-development-writer-server": "aios_autonomous_control_plane.writer_server:main",
"aios-governance-approval-watcher": "aios_autonomous_control_plane.watcher_service:main",
"aios-governance-mirror-worker": "aios_autonomous_control_plane.mirror_service:main",
"aios-governance-request-publisher": "aios_autonomous_control_plane.publisher:main",
"aios-release-hook": "aios_autonomous_control_plane.release_action:main",
"aios-release-object-projector": "aios_autonomous_control_plane.projection_service:release_main",
"aios-runtime-source-projector": "aios_autonomous_control_plane.projection_service:runtime_main",
"aios-v2r1c4-release-executor": "aios_autonomous_control_plane.release_service:main"
},
"force_push": false,
"global_writes_must_remain_false": true,
"package_version": "0.2.0",
"schema": "aios.code-handoff/v2",
"source": "codex-chartgpt-bridge",
"systemd_units": [
"deploy/systemd/aios-autonomous-renewal-controller.service",
"deploy/systemd/aios-governance-approval-watcher.service",
"deploy/systemd/aios-governance-mirror-worker.service",
"deploy/systemd/aios-governance-request-publisher.service",
"deploy/systemd/aios-governed-development-writer-revoker.service",
"deploy/systemd/aios-governed-development-writer-revoker.timer",
"deploy/systemd/aios-governed-development-writer.service",
"deploy/systemd/aios-release-object-projection.service",
"deploy/systemd/aios-runtime-source-read-projection.service",
"deploy/systemd/aios-v2r1c4-release-envelope.service"
],
"tag_rewrite": false,
"target_branch": "patch/v2r1c4-release-completion-20260729",
"tests": {
"collection_errors": 0,
"compileall": "PASS",
"pytest_failed": 0,
"pytest_passed": 21,
"secret_findings": [
{
"path": "tests/autonomous_control_plane/test_policy_and_writer.py",
"rule": "literal-credential-assignment"
}
],
"secret_findings_classification": {
"tests/autonomous_control_plane/test_policy_and_writer.py": "Deliberate fake api_key assignment used by the negative secret-rejection test."
},
"secret_scan": "PASS_TEST_FIXTURE_ONLY"
},
"wechat_backend": {
"new_code_generated": false,
"reason": "The controlled PR #20 full diff remains too large for this interface; existing exact Git objects must be retained and validated, not re-invented.",
"required_agent_action": "Preserve already integrated approved WeChat code, run its online acceptance suite, and include its exact object IDs in the final release envelope."
}
}
@@ -0,0 +1,84 @@
{
"added_files": [
"AGENT_INTEGRATION_PLAN.md",
"config/examples/grant.json",
"config/examples/mirror.json",
"config/examples/publisher.json",
"config/examples/release-actions.json",
"config/examples/release-envelope.json",
"config/examples/release-hooks.json",
"config/examples/release-projection.json",
"config/examples/renewal.json",
"config/examples/revoker.json",
"config/examples/runtime-projection.json",
"config/examples/watcher.json",
"config/examples/writer-server.json",
"deploy/systemd/aios-v2r1c4-release-envelope.service",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/credentials.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/gitea_api.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/grant.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/mirror_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/publisher.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_action.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_deploy.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_hooks.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_transport.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/renewal_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/revoker.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/socket_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/watcher_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer_server.py",
"tests/autonomous_control_plane/test_deployment_and_contracts.py",
"tests/autonomous_control_plane/test_services_and_hooks.py"
],
"base_package_sha256": "795feb406541af86f30c1fb31f85e6d7485ee72a9d3ac93351f9a63fe4ad3e8f",
"deleted_files": [
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/__init__.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/cli.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/common.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/ledger.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/mirror.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/policy.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/projection.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/release.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/renewal.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/watcher.cpython-313.pyc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/writer.cpython-313.pyc",
"tests/.pytest_cache/.gitignore",
"tests/.pytest_cache/CACHEDIR.TAG",
"tests/.pytest_cache/README.md",
"tests/.pytest_cache/v/cache/lastfailed",
"tests/.pytest_cache/v/cache/nodeids",
"tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc",
"tests/autonomous_control_plane/__pycache__/test_mirror_projection.cpython-313-pytest-9.0.2.pyc",
"tests/autonomous_control_plane/__pycache__/test_policy_and_writer.cpython-313-pytest-9.0.2.pyc",
"tests/autonomous_control_plane/__pycache__/test_renewal_release.cpython-313-pytest-9.0.2.pyc",
"tests/autonomous_control_plane/__pycache__/test_watcher.cpython-313-pytest-9.0.2.pyc"
],
"deletion_policy": "Only generated caches listed here may be removed. Do not delete repository source files.",
"integration_strategy": "Apply additions and replacements on patch/v2r1c4-release-completion-20260729; preserve existing approved Git objects and user code.",
"modified_files": [
"CODE_HANDOFF_MANIFEST.json",
"INTEGRATION_NOTES.md",
"TEST_RECEIPT.json",
"deploy/systemd/aios-autonomous-renewal-controller.service",
"deploy/systemd/aios-governance-approval-watcher.service",
"deploy/systemd/aios-governance-mirror-worker.service",
"deploy/systemd/aios-governance-request-publisher.service",
"deploy/systemd/aios-governed-development-writer-revoker.service",
"deploy/systemd/aios-governed-development-writer.service",
"deploy/systemd/aios-release-object-projection.service",
"deploy/systemd/aios-runtime-source-read-projection.service",
"deploy/tmpfiles.d/aios-autonomous-control-plane.conf",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py",
"services/aios-autonomous-control-plane/pyproject.toml",
"tests/autonomous_control_plane/test_mirror_projection.py",
"tests/autonomous_control_plane/test_renewal_release.py"
],
"schema": "aios.code-handoff-delta/v1",
"target_package_name": "aios_v2r1c4_autonomy_patch_v2_20260729.zip"
}
@@ -0,0 +1,66 @@
{
"AGENT_INTEGRATION_PLAN.md": "0af0bb6c3ed22d30c48e1e9af74540a0f4571dabe5dcf97bc67077d5cca6ea1d",
"CODE_HANDOFF_MANIFEST.json": "b1e3fde19a864671b28945ff21fd6c4f1fe2fd4bb7d78048ba1430d3de286cf9",
"DELTA_FROM_V1.json": "296571cac8fe3117443ad04c045a02203f1bb9eef5284f1704dda9c04e75e9ae",
"INTEGRATION_NOTES.md": "e70df9ca86ed136d193b1773596f7187d6c1f8751f40c133d3e93f017233d05c",
"TEST_RECEIPT.json": "e1e3cd8934d8b79a88bf740575e37c1407ab2a6dbad099a2730476e3b073564a",
"config/examples/development-policy.json": "51ab926a733c9a5173df43a3bf23d25ee3bd2b4743f2005cc458dcef232f62e4",
"config/examples/grant.json": "2dbece7418377880c63108e07155a3e97859f8b24d087ad353749cddf2572ffd",
"config/examples/mirror.json": "41b3948ad34a0a58b5af389d93f9a51241544449b08b90daa93b74ab5d22d292",
"config/examples/publisher.json": "d5198ba71dc87e9863b1fa1fcce0fabcc5d347e508fa2736041772fa68c083ea",
"config/examples/release-actions.json": "08d08fe97f3fdd336cd8f0dbc1c358bb5c9a9b2c7b1f66d5ab0682ea6aa0572e",
"config/examples/release-envelope.json": "6b3f31e75a9ec0d820e304932487c8a7961488d65b98c59a45320c52b3ca7a0f",
"config/examples/release-hooks.json": "6bb755673fee080e968395478cbf3d4697b8afc47d1f791890b528693cfcdbf2",
"config/examples/release-projection.json": "fa898f3fdb877f1c449999a827a9afb8797e026fd574ca7375b386069cf60e3d",
"config/examples/renewal.json": "59c27809e4f066e7b12cd0b57fecf46dedf28640be1c92c6906c1b1c19e7b25a",
"config/examples/revoker.json": "e4eaf3255e444c50ed29e9ee78b5d3284d26d74b55e17d0060b7e285b88b5845",
"config/examples/runtime-projection.json": "4f11d1d15d8daf26b2c6dc7e01d5626315fa7f2ca3c32923f029728a67b86534",
"config/examples/watcher.json": "95d83d7eedc3cbaf43901e9ec313f3cf08d9f5832c02910837187a2e32b9a465",
"config/examples/writer-server.json": "f0b5648f3f8e4e37ad934aaff8c55480a25139b731f676e49adf9ae1a0ebe0e1",
"deploy/systemd/aios-autonomous-renewal-controller.service": "38cf3269cac8e73cc004de50e051f26ea2e1f1a1427682e129b47960210e3c31",
"deploy/systemd/aios-governance-approval-watcher.service": "e48174384113644771eaf893c68e49432fc7b5e8ab4b4fa301d191f079b4e30f",
"deploy/systemd/aios-governance-mirror-worker.service": "1ef26557563b93d411b7a116800ca960dcde69051fd222c64555bf274ec15ca8",
"deploy/systemd/aios-governance-request-publisher.service": "c4a69bea0fc23849aa3307d8939e08c3925c9df445d0e43ef7fb689e285e5f89",
"deploy/systemd/aios-governed-development-writer-revoker.service": "f9128b9a2a4f77bde98f7e8a735babc67e14186860e8cb34eb94f6126dd6f7b5",
"deploy/systemd/aios-governed-development-writer-revoker.timer": "0bf2bc416012b5009ccb9c7b8f76d546fa6485295a926829fd3b26e0c1f071ce",
"deploy/systemd/aios-governed-development-writer.service": "b5d052b9f3cf81bc5587dd0545ac25ae55d29e37c32c760fb9725dced351598e",
"deploy/systemd/aios-release-object-projection.service": "91acf73dcab189aebe7900237f25a3accaa804624c1b4f52a2b477128142ed46",
"deploy/systemd/aios-runtime-source-read-projection.service": "45cf8a5c17fcd6960970ed8f26b02a1d3fdc53874d39c14b4a1d1d89d543679e",
"deploy/systemd/aios-v2r1c4-release-envelope.service": "b9b4ffb3a41cf90256cb970fb300a8e633e91527f19c8a8b8ee1e3cabdda4492",
"deploy/tmpfiles.d/aios-autonomous-control-plane.conf": "d5f3aefe63515b5699fbb81421480015bfa3bc1794ec02b8214a3c21f9cea8f2",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__init__.py": "52a7864b6a4ac94be8f67100c825813b19ccf889283bbb7dbecbd342b9ec29dc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/cli.py": "cd42b70c35b2d810433db0df013a439dc7993c45c68ea930a9efd5b5faced84c",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/common.py": "395c669df606ed366774663d4ac229225469c77ab3ff72f6a9efcbcef8031f9e",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/credentials.py": "61322d9f494a63764f1148550853d7ca7bcd9be74451bd3c3cf3cbe6388d2136",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/gitea_api.py": "9b0a7d9db9a4497078d8f4b0bf7622b292b40282204a1e1855e11f1edc93b6de",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/grant.py": "5b1cb302a1365f4a6f03df73f8c5f8a1595304d65e9d7ac129178d51b38dde59",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/ledger.py": "a51eea543d4e44c2faab6b59c7850600908f36090f0a1ddf448c1ca7c21acdbd",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/mirror.py": "20093cf68c0b4db4940d1092b0f09d7638ed210e2739973b1a558a4016208e01",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/mirror_service.py": "a46549c4c8b29006ed2b1aec201e470e88e2f9b347ef2fa81839ac7d8093320b",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/policy.py": "5fc5b50e781cfa47e99164635155a9559d168f1f556d8ca2f1694b57b1b57195",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection.py": "6ee91b9b6482d4f10c98aa7e78bd23dc5f9f759c875db2e0a3207cfe27714c4c",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection_service.py": "2019ca8e51affcebe6c776c2c3b51a54e1d6134874e3a9b12fc774393023172a",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/publisher.py": "fd65490c1b384b2725315a066715c9822255bbef3c213ab343495c6c96a7e90f",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py": "2579fc38834d77c6370dcdc4269134fe42cf85540efcebf9e4f769ab6cbde200",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_action.py": "26254215e032f361737584e2b8eb8367fe9f6930b946511e16f57d8e7f50cee9",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_deploy.py": "bfb46b6dfacd88c69cee14c9f482a99a95a7b12f1de4b8778fdcdf1b66cfdbd3",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_hooks.py": "10e485d39a4fcfba4323297101f4281e6a0a94a60f6ee64a8e22a5d171d79965",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_service.py": "8d67a4b1562879b500120f65fb8f030183b0fb70acee646656dd235f00d0b618",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_transport.py": "822257f2c48c1fe861d8766aad2d61302e8b4e223a15b26f3c75c993c30140e2",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/renewal.py": "2272c428999a769218142b27b0a80e938c96b7cf1e553fdfd94873123dd9ad86",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/renewal_service.py": "c7fc5e307bd6eaef35844868cecc530b463088b4f320e531800d8683f3a3733a",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/revoker.py": "6953ec6442635a495ec602fbf6b2815aee40e43ad3790bf972a887bbb2de537d",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/socket_service.py": "a42c80002e8fcea7000ee0f4fd2a437b44b18773edbdbb9dfc088d385d2782e7",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/watcher.py": "eed557d5f6acfe44881bee44dd92fea6e04ac19f33e2dea874c2a4662b04c824",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/watcher_service.py": "db502f08bafad752935180477894bb78d5b36f6261f8af13d8db2d9ecce184bb",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py": "59b8f8d5c96a455e280de5a12280aca05070f86deb443e8f6fd842d7872dc60f",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer_server.py": "1680ca5a053da5b9a7430a616904f474cf27833496f50ead2803227598fd901f",
"services/aios-autonomous-control-plane/pyproject.toml": "4dae4bf9a88d033511a8de6d2871583d36cff868c3e0c6287c78d584933816df",
"tests/autonomous_control_plane/test_deployment_and_contracts.py": "2606242519f4cdf5783dd36708357c6ec9520d66f8f8ec18ef28529e3bd240d4",
"tests/autonomous_control_plane/test_mirror_projection.py": "5dc56cc0b5910d4b83afa4354f0375a2668ed5a328823357dc3ef2819235f26e",
"tests/autonomous_control_plane/test_policy_and_writer.py": "723a6fafcc542de7da028d2a2f76a6eb2b7975d4e6e9d1a23c17973019f74b7c",
"tests/autonomous_control_plane/test_renewal_release.py": "3199b9e87995d43ee97e8e62ebe85ef4f242afb16912bd1551d7570cb7d7474c",
"tests/autonomous_control_plane/test_services_and_hooks.py": "e58bde487ed38dfbb123a37ae43733c28a519d294a7729d01823adf7d2e48dd5",
"tests/autonomous_control_plane/test_watcher.py": "025ab4432522478ab7094751edf8da702b0e7be25d93876115cf9f416b7188b1",
"tests/conftest.py": "32a3df0734d253b070594fce0327b929c8ee0bbb136ea6fa83a2abecb826415b"
}
@@ -0,0 +1,41 @@
# AIOS V2R1C4 Autonomy Patch v2
This package completes the capabilities that were missing from the first handoff.
## Newly delivered
- Idempotent, credential-isolated governance request publisher.
- Authenticated Unix-socket development writer server with SO_PEERCRED checks.
- Root-owned task/branch/repository/path-bound Writer Grant and idempotent quota ledger.
- Writer credential revocation, old-token HTTP 401 proof, encrypted credential removal,
and read-only revoked Grant evidence.
- Persistent watcher, mirror, projection, and renewal service entrypoints.
- Complete release hook implementation:
- Owner exact-head and machine-status validation.
- Approved governance Manifest verification.
- Governed merge and tag transports.
- Remote/Gitea tag verification.
- Safe Artifact extraction and atomic release symlink deployment.
- systemd health checks.
- rollback and restore.
- Registry/Baseline snapshots, compensation, and final consistency.
- Unified V2R1C4 release executor with automatic failure rollback.
- 11 installed console entrypoints and 10 systemd/timer contracts.
## Offline verification
- compileall: PASS
- pytest: 21 passed
- Secret scan: REVIEW
- Path traversal archive test: PASS
- Metadata compensation test: PASS
- Publisher idempotency test: PASS
- Grant replay/quota test: PASS
- Old credential 401 test: PASS
## Integration rule
Apply this package to `patch/v2r1c4-release-completion-20260729`.
Agent should only supply environment configuration, existing governed endpoint
addresses, encrypted credentials, exact Git object IDs, and online acceptance.
Do not redesign or replace the delivered control-plane logic.
@@ -0,0 +1,77 @@
{
"compatibility_adaptations": [
{
"binding": "resolved active Python executable; release hook rejects symlink executables",
"new_sha256": "bd5c90b12f5f128cb3151f83e27748e8c382d1f07672dc67e3a97f5cb7ef5b03",
"old_sha256": "e58bde487ed38dfbb123a37ae43733c28a519d294a7729d01823adf7d2e48dd5",
"path": "tests/autonomous_control_plane/test_services_and_hooks.py",
"product_runtime_modified": false,
"reason": "host Python is 3.12 and package declares requires-python >=3.11; remove fixture-only /usr/bin/python3.13 binding"
}
],
"compiled_cache_files_integrated": false,
"delta_added_count": 32,
"delta_deleted_cache_count": 21,
"delta_modified_count": 18,
"direct_main_push": false,
"force_push_used": false,
"gitea_api_bootstrap_token_status": 401,
"gitea_api_preapply_oid": "e5dc9185dd153efdfb007f9b674197f613c10796",
"gitea_api_reader_token_status": 401,
"global_gitops_writes_enabled": false,
"handoff_metadata_location": "evidence/releases/V2R1C4-code-handoff-v2",
"integrated_runtime_and_test_paths": [
"config/examples/grant.json",
"config/examples/mirror.json",
"config/examples/publisher.json",
"config/examples/release-actions.json",
"config/examples/release-envelope.json",
"config/examples/release-hooks.json",
"config/examples/release-projection.json",
"config/examples/renewal.json",
"config/examples/revoker.json",
"config/examples/runtime-projection.json",
"config/examples/watcher.json",
"config/examples/writer-server.json",
"deploy/systemd/aios-v2r1c4-release-envelope.service",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/credentials.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/gitea_api.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/grant.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/mirror_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/publisher.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_action.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_deploy.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_hooks.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_transport.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/renewal_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/revoker.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/socket_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/watcher_service.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer_server.py",
"tests/autonomous_control_plane/test_deployment_and_contracts.py",
"tests/autonomous_control_plane/test_services_and_hooks.py",
"deploy/systemd/aios-autonomous-renewal-controller.service",
"deploy/systemd/aios-governance-approval-watcher.service",
"deploy/systemd/aios-governance-mirror-worker.service",
"deploy/systemd/aios-governance-request-publisher.service",
"deploy/systemd/aios-governed-development-writer-revoker.service",
"deploy/systemd/aios-governed-development-writer.service",
"deploy/systemd/aios-release-object-projection.service",
"deploy/systemd/aios-runtime-source-read-projection.service",
"deploy/tmpfiles.d/aios-autonomous-control-plane.conf",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py",
"services/aios-autonomous-control-plane/pyproject.toml",
"tests/autonomous_control_plane/test_mirror_projection.py",
"tests/autonomous_control_plane/test_renewal_release.py"
],
"schema": "aios.code-handoff-integration/v2",
"source_file_hash_entries": 64,
"source_file_hashes_verified": true,
"source_zip_sha256": "7afbcfae0ff692d2b859cd1e7e96536b8e80188667554803da438dcddc292d69",
"tag_rewritten": false,
"v1_modified_base_files_verified": 15
}
@@ -0,0 +1,20 @@
{
"collection_errors": 0,
"compileall_returncode": 0,
"delta_added_files": 32,
"delta_deleted_files": 21,
"delta_modified_files": 18,
"entrypoint_count": 11,
"generated_at": "2026-07-29T08:11:08.888275Z",
"pytest_failed": 0,
"pytest_passed": 21,
"pytest_returncode": 0,
"secret_findings": [
{
"path": "tests/autonomous_control_plane/test_policy_and_writer.py",
"rule": "literal-credential-assignment"
}
],
"secret_scan": "PASS_TEST_FIXTURE_ONLY",
"systemd_contract_count": 10
}
@@ -0,0 +1,104 @@
{
"actions": {
"artifact_built": false,
"baseline_modified": false,
"control_plane_deployed": false,
"core_redesigned_by_agent": false,
"main_modified": false,
"online_write_acceptance_executed": false,
"owner_approval_pr_created": false,
"production_modified": false,
"registry_modified": false,
"tag_created": false
},
"blocking_layer": "CODE_HANDOFF_SECURITY_INVARIANTS",
"candidate_base_oid": "e5dc9185dd153efdfb007f9b674197f613c10796",
"confirmed_security_findings": [
{
"evidence": "release_action.py:53-98",
"id": "P0-OWNER-ENVELOPE-BINDING",
"summary": "approved manifest digest is checked but manifest fields are not parsed and made equal to the release envelope"
},
{
"evidence": "release.py:20-30,52-59",
"id": "P0-UNCONSUMED-RELEASE-DIGESTS",
"summary": "rollback, SBOM, test, evidence and tag/deployment/rollback plan digests are format checked but not verified against objects before side effects"
},
{
"evidence": "release_deploy.py:173-188; release.py:168-170,210-214",
"id": "P0-PARTIAL-DEPLOY-NO-COMPENSATION",
"summary": "deployment side effects occur while phase is TAG_VERIFIED, which is excluded from automatic rollback"
},
{
"evidence": "release_deploy.py:191-212",
"id": "P0-ROLLBACK-TARGET-UNBOUND",
"summary": "previous and restored directories are not constrained to release_root and are not bound to the approved rollback digest"
},
{
"evidence": "policy.py:72-76; grant.py:10-25,62-71; writer.py:94-107; writer_server.py:28-38,64-68",
"id": "P0-WRITER-GRANT-BOUNDARY",
"summary": "expected base ancestry, exact task worktree/common-dir/remote and task credential identity are not closed"
},
{
"evidence": "revoker.py:36-64; aios-governed-development-writer-revoker.timer:4-8",
"id": "P0-REVOKER-EXPIRY-RECOVERY",
"summary": "fixed five-minute timer ignores grant expiry and credential deletion precedes recoverable grant and receipt closure"
},
{
"evidence": "deploy/tmpfiles.d/aios-autonomous-control-plane.conf:1-19",
"id": "P1-SERVICE-DIRECTORY-PERMISSIONS",
"summary": "0750 root:gitops directories are not writable by non-root writer and publisher users"
},
{
"evidence": "release_transport.py:65-76; release_deploy.py:221-228",
"id": "P1-LOOPBACK-URL-PREFIX",
"summary": "string prefix checks accept non-loopback hosts and can forward credentials"
}
],
"deployment_decision": "BLOCKED_PRODUCTION_DEPLOYMENT",
"execution_status": "PARTIALLY_COMPLETED",
"governance": {
"AIOS_GITOPS_WRITES_ENABLED": false,
"direct_main_push": false,
"force_push_used": false,
"owner_approval_respected": true,
"secrets_committed": false,
"tag_rewritten": false
},
"integrity": {
"file_sha256": "64/64 PASS",
"hardcoded_credentials": 0,
"path_traversal_entries": 0,
"secret_scan": "PASS",
"v1_modified_base_files": "15/15 PASS",
"zip_sha256": "7afbcfae0ff692d2b859cd1e7e96536b8e80188667554803da438dcddc292d69"
},
"live_binding_inventory": {
"authoritative_bare": "/data/aios-gitops/repo.git",
"candidate_health_endpoint_127_0_0_1_18890": "PRESENT_HTTP_200_NOT_APPROVED_AS_RELEASE_BINDING",
"configured_health_endpoint_127_0_0_1_8080": "ABSENT",
"configured_tag_endpoint_127_0_0_1_8080": "ABSENT",
"gitea_bare": "/data/aios-gitops/runtime/gitea-bin/data/repositories/aios/aios.git",
"gitea_db": "/data/aios-gitops/runtime/gitea-bin/data/gitea.db",
"gitea_repo_id": 1,
"integration_merge_writer_socket": "ABSENT",
"owner_user_id": 2,
"production_baseline_path": "ABSENT",
"release_root_current_previous": "ABSENT",
"v2r1c4_artifact": "ABSENT",
"v2r1c4_registry": "ABSENT"
},
"observed_at": "2026-07-29T09:11:19.725943+00:00",
"schema": "aios.code-handoff-validation/v2",
"verification": {
"collection_errors": 0,
"compileall": "PASS",
"console_entrypoints": "11/11 load PASS",
"package_tests_after_fixture_adapter": "21 passed",
"package_tests_original_host": "20 passed, 1 failed due fixture-only /usr/bin/python3.13 binding",
"package_version": "0.2.0",
"repository_tests": "660 passed, 1 skipped, 180 subtests passed",
"runtime_dependencies": "0",
"systemd_units": "10/10 staged-root syntax PASS"
}
}
@@ -0,0 +1,5 @@
{
"raw_evidence": "wheel-repro.json",
"sha256": "a0415df8e4d131a32a3ce39a6e997b0304657224642bf47d73adddb684a7d4ca",
"status": "PASS"
}
@@ -0,0 +1,42 @@
{
"files": [
"config/examples/candidate-fixture.json",
"config/examples/grant.json",
"config/examples/publisher.json",
"config/examples/release-actions.json",
"config/examples/release-envelope.json",
"config/examples/revoker.json",
"config/examples/writer-server.json",
"deploy/systemd/aios-governance-request-publisher.service",
"deploy/systemd/aios-governed-development-writer-revoker.service",
"deploy/systemd/aios-governed-development-writer.service",
"deploy/systemd/aios-v2r1c4-candidate-api.service",
"deploy/systemd/aios-v2r1c4-candidate-merge.socket",
"deploy/systemd/aios-v2r1c4-candidate-merge@.service",
"deploy/tmpfiles.d/aios-autonomous-control-plane.conf",
"scripts/generate_v2r1c4_v3_evidence.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/approval_binding.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/candidate_fixture.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/gitea_api.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/grant.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_action.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_deploy.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_hooks.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_inputs.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release_transport.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/revoker.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer_server.py",
"services/aios-autonomous-control-plane/pyproject.toml",
"tests/autonomous_control_plane/test_candidate_integration_v3.py",
"tests/autonomous_control_plane/test_evidence_generator_v3.py",
"tests/autonomous_control_plane/test_non_root_execution_v3.py",
"tests/autonomous_control_plane/test_policy_and_writer.py",
"tests/autonomous_control_plane/test_release_security_v3.py",
"tests/autonomous_control_plane/test_renewal_release.py",
"tests/autonomous_control_plane/test_services_and_hooks.py",
"tests/autonomous_control_plane/test_systemd_security_v3.py",
"tests/autonomous_control_plane/test_writer_revoker_security_v3.py"
]
}
@@ -0,0 +1,5 @@
{
"hardcoded_credentials": 0,
"raw_evidence": "scans.json",
"status": "PASS"
}
@@ -0,0 +1,5 @@
{
"declared_runtime_dependencies": 0,
"raw_evidence": "scans.json",
"status": "PASS"
}
@@ -0,0 +1,44 @@
{
"changed_file_count": 38,
"numstat": [
"13\t0\tconfig/examples/candidate-fixture.json",
"19\t15\tconfig/examples/grant.json",
"8\t13\tconfig/examples/publisher.json",
"15\t0\tconfig/examples/release-actions.json",
"9\t1\tconfig/examples/release-envelope.json",
"5\t4\tconfig/examples/revoker.json",
"8\t14\tconfig/examples/writer-server.json",
"4\t1\tdeploy/systemd/aios-governance-request-publisher.service",
"1\t1\tdeploy/systemd/aios-governed-development-writer-revoker.service",
"5\t1\tdeploy/systemd/aios-governed-development-writer.service",
"29\t0\tdeploy/systemd/aios-v2r1c4-candidate-api.service",
"12\t0\tdeploy/systemd/aios-v2r1c4-candidate-merge.socket",
"28\t0\tdeploy/systemd/aios-v2r1c4-candidate-merge@.service",
"0\t3\tdeploy/tmpfiles.d/aios-autonomous-control-plane.conf",
"356\t0\tscripts/generate_v2r1c4_v3_evidence.py",
"83\t0\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/approval_binding.py",
"253\t0\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/candidate_fixture.py",
"29\t3\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/gitea_api.py",
"45\t2\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/grant.py",
"162\t69\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py",
"59\t13\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/release_action.py",
"211\t28\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/release_deploy.py",
"29\t24\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/release_hooks.py",
"95\t0\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/release_inputs.py",
"50\t5\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/release_transport.py",
"229\t38\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/revoker.py",
"90\t18\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py",
"13\t8\tservices/aios-autonomous-control-plane/aios_autonomous_control_plane/writer_server.py",
"2\t1\tservices/aios-autonomous-control-plane/pyproject.toml",
"161\t0\ttests/autonomous_control_plane/test_candidate_integration_v3.py",
"205\t0\ttests/autonomous_control_plane/test_evidence_generator_v3.py",
"9\t0\ttests/autonomous_control_plane/test_non_root_execution_v3.py",
"140\t5\ttests/autonomous_control_plane/test_policy_and_writer.py",
"384\t0\ttests/autonomous_control_plane/test_release_security_v3.py",
"8\t0\ttests/autonomous_control_plane/test_renewal_release.py",
"8\t0\ttests/autonomous_control_plane/test_services_and_hooks.py",
"82\t0\ttests/autonomous_control_plane/test_systemd_security_v3.py",
"155\t0\ttests/autonomous_control_plane/test_writer_revoker_security_v3.py"
],
"range": "473b86a2f1f5a5fe3b8ad42a6da26c29c78c4170..56bb00cd134f4d545935416256bdb018d5c8d58b"
}
@@ -0,0 +1,43 @@
{
"executed_at": "2026-07-29T12:31:16Z",
"files": {
"ARTIFACT_REPRODUCIBILITY.json": "4ee6f688a0e5b43c3de0b757d768f99ea7603b186c0605e263ca7bf598432d24",
"CHANGED_FILES.json": "8344ba734fdb2663e3386d40ab2c6f7093843feb72a2db35695361ee8597f343",
"CREDENTIAL_LEAK_SCAN.json": "b300a5dac4ad08444f979cbc7e6e48fd10dd51f774fe31b6d1bcf1c35e30a2fc",
"DEPENDENCY_SCAN.json": "32d7568a291719983158ade57116bfeaa92a34977d64d6a2261b1305d7b0b55d",
"DIFF_SUMMARY.json": "568b44f156494f9c9dd92bc449f312538056d9b54d226e213358b5bb8991e358",
"FAILURE_INJECTION_RESULTS.json": "98ff60bdf055be342865ff101f9b6655bd39b93f0ef10af984dce3b16e76682e",
"FILE_SHA256.json": "26c1b6829312864ad799d7db184e9344bb951d07ea5d2f28e70f80b0ad44ff60",
"NON_ROOT_PERMISSION_RESULTS.json": "922c629666f9e965b7570ab84b430403597473cc6df01414c1bf1c1541347575",
"PATH_TRAVERSAL_SCAN.json": "b0d4f4754de0acff8bd0251a3a55cc89fa0ea24953aaa9c9b0fd23dbc30f99a8",
"RELEASE_IDENTIFIERS.json": "48bef9575e55429d39ac6540a8b68b7678d481fbdced187f8d83095f88c6d10f",
"SECRET_SCAN.json": "cb569592255594eafc4c97adcfd181d37cc47240a5ad9f03433d091c13d0c305",
"SECURITY_INVARIANT_MATRIX.json": "97909294c3925af144222bac9ddb861e7f751672d43811a1e61969c10bb9ea25",
"SOURCE_MANIFEST.json": "fb0ed7cfb94f08aa6f6c601e680b4e11c0304b7d9b2ece10230b869391695977",
"SYSTEMD_VALIDATION.json": "a9831840ee384886ce8d5141db991487308a44d8ca2b39cd2c4e98c8df7f548c",
"TEST_COMMANDS.json": "b62f32ad541c1b6277b3085dc6731a6aa9e5085eeb3624962f9bd43fbc6bc1d1",
"TEST_RESULTS.json": "ca4fff6020d1a67e044b2afd47256964753ffac8df801f3ac0cd9f8f88c35ecf",
"THREAT_MODEL.md": "cbfec5ee4b781ad5214a852b74dd9ab977c9e7c4332f01cc76d01cfdb0b65d95",
"UNRESOLVED_ISSUES.json": "572e1bbe502a080d86f416d60b9eb204470806b3f2867095dbf0b2f04b20a37f",
"VALIDATOR_REPORT.json": "d49cc1e6b8a64eec02df1149e674a9a0a39be72c0c9e67503d3bd153be4faab1",
"candidate-live.json": "883b22ded27242311a30c3c24885910cfbdbd78df523b0be3aa849e9a5d1325e",
"compileall.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"gitleaks.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570",
"nonroot-focused.xml": "c1df7f399b07c3e58bed510b66f0e2eb16884e9bc0e67397f8f8567e0ceb2218",
"pytest-legacy.xml": "200bbd033d29dc5037eeccda2fd00fcee55ff8f55619d04fe931dc72e52fdc35",
"pytest-main.xml": "bb0b715c612fdf6c02480f6f74a0a4aa9a9b2d2acd0b6328798b4423b793fa78",
"scans.json": "8ac15b04eb58e59d91653eb484b025e28ac771254e91052cb7a8ba826a2ecb0f",
"systemd-verify.log": "5a6c2f127505660e2fd40b4d0cf79752ab3871a9e6df0ce1ff59f5d801256da0",
"validator.json": "4caa6f58e27afad059bb3ca8ff0a6c6ac8e9549d9b61f82a644bc2fa7f6eaaba",
"wheel-repro.json": "b235ad7318886f26752021444933d5acc71a9f1ab5f05a79a9e79d509244ef63"
},
"generator": "scripts/generate_v2r1c4_v3_evidence.py",
"generator_schema": "aios.v2r1c4-security-evidence/v3",
"git_version": "git version 2.43.0",
"platform": "Linux-6.8.0-124-generic-x86_64-with-glibc2.39",
"python_executable": "/usr/bin/python3.12",
"python_version": "3.12.3",
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"source_tree_oid": "20adf8d65858131ce29bc979b8d1c7c0444d52d3",
"status": "CANDIDATE_READY_FOR_INDEPENDENT_VALIDATION"
}
@@ -0,0 +1,16 @@
{
"failed": 0,
"passed": 6,
"raw_evidence": [
"pytest-main.xml"
],
"scenarios": [
"deploy_mid_restart_resume",
"deploy_compensation",
"rollback_binding_mismatch",
"revoker_receipt_checkpoint_crash",
"loopback_parser_bypass",
"writer_binding_mismatch"
],
"status": "PASS"
}
@@ -0,0 +1,32 @@
{
"files": {
"ARTIFACT_REPRODUCIBILITY.json": "4ee6f688a0e5b43c3de0b757d768f99ea7603b186c0605e263ca7bf598432d24",
"CHANGED_FILES.json": "8344ba734fdb2663e3386d40ab2c6f7093843feb72a2db35695361ee8597f343",
"CREDENTIAL_LEAK_SCAN.json": "b300a5dac4ad08444f979cbc7e6e48fd10dd51f774fe31b6d1bcf1c35e30a2fc",
"DEPENDENCY_SCAN.json": "32d7568a291719983158ade57116bfeaa92a34977d64d6a2261b1305d7b0b55d",
"DIFF_SUMMARY.json": "568b44f156494f9c9dd92bc449f312538056d9b54d226e213358b5bb8991e358",
"FAILURE_INJECTION_RESULTS.json": "98ff60bdf055be342865ff101f9b6655bd39b93f0ef10af984dce3b16e76682e",
"NON_ROOT_PERMISSION_RESULTS.json": "922c629666f9e965b7570ab84b430403597473cc6df01414c1bf1c1541347575",
"PATH_TRAVERSAL_SCAN.json": "b0d4f4754de0acff8bd0251a3a55cc89fa0ea24953aaa9c9b0fd23dbc30f99a8",
"RELEASE_IDENTIFIERS.json": "48bef9575e55429d39ac6540a8b68b7678d481fbdced187f8d83095f88c6d10f",
"SECRET_SCAN.json": "cb569592255594eafc4c97adcfd181d37cc47240a5ad9f03433d091c13d0c305",
"SECURITY_INVARIANT_MATRIX.json": "97909294c3925af144222bac9ddb861e7f751672d43811a1e61969c10bb9ea25",
"SOURCE_MANIFEST.json": "fb0ed7cfb94f08aa6f6c601e680b4e11c0304b7d9b2ece10230b869391695977",
"SYSTEMD_VALIDATION.json": "a9831840ee384886ce8d5141db991487308a44d8ca2b39cd2c4e98c8df7f548c",
"TEST_COMMANDS.json": "b62f32ad541c1b6277b3085dc6731a6aa9e5085eeb3624962f9bd43fbc6bc1d1",
"TEST_RESULTS.json": "ca4fff6020d1a67e044b2afd47256964753ffac8df801f3ac0cd9f8f88c35ecf",
"THREAT_MODEL.md": "cbfec5ee4b781ad5214a852b74dd9ab977c9e7c4332f01cc76d01cfdb0b65d95",
"UNRESOLVED_ISSUES.json": "572e1bbe502a080d86f416d60b9eb204470806b3f2867095dbf0b2f04b20a37f",
"VALIDATOR_REPORT.json": "d49cc1e6b8a64eec02df1149e674a9a0a39be72c0c9e67503d3bd153be4faab1",
"candidate-live.json": "883b22ded27242311a30c3c24885910cfbdbd78df523b0be3aa849e9a5d1325e",
"compileall.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"gitleaks.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570",
"nonroot-focused.xml": "c1df7f399b07c3e58bed510b66f0e2eb16884e9bc0e67397f8f8567e0ceb2218",
"pytest-legacy.xml": "200bbd033d29dc5037eeccda2fd00fcee55ff8f55619d04fe931dc72e52fdc35",
"pytest-main.xml": "bb0b715c612fdf6c02480f6f74a0a4aa9a9b2d2acd0b6328798b4423b793fa78",
"scans.json": "8ac15b04eb58e59d91653eb484b025e28ac771254e91052cb7a8ba826a2ecb0f",
"systemd-verify.log": "5a6c2f127505660e2fd40b4d0cf79752ab3871a9e6df0ce1ff59f5d801256da0",
"validator.json": "4caa6f58e27afad059bb3ca8ff0a6c6ac8e9549d9b61f82a644bc2fa7f6eaaba",
"wheel-repro.json": "b235ad7318886f26752021444933d5acc71a9f1ab5f05a79a9e79d509244ef63"
}
}
@@ -0,0 +1,6 @@
{
"raw_evidence": "nonroot-focused.xml",
"status": "PASS",
"tests_passed": 20,
"uid": 1000
}
@@ -0,0 +1,6 @@
{
"entries": 0,
"raw_evidence": "scans.json",
"status": "PASS",
"symlinks": 0
}
@@ -0,0 +1,10 @@
{
"artifact_sha256": "NOT_BUILT",
"expected_base_oid": "473b86a2f1f5a5fe3b8ad42a6da26c29c78c4170",
"production_baseline": "V2R1C3_UNCHANGED",
"registry_version": "V2R1C3_UNCHANGED",
"release_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"release_tag": "NOT_CREATED",
"release_tree_oid": "20adf8d65858131ce29bc979b8d1c7c0444d52d3",
"rollback_sha256": "NOT_BUILT"
}
@@ -0,0 +1,5 @@
{
"leaks": 0,
"raw_evidence": "gitleaks.json",
"status": "PASS"
}
@@ -0,0 +1,120 @@
{
"fixed": 9,
"invariants": [
{
"id": 1,
"locations": [
"approval_binding.py",
"release.py",
"release_action.py"
],
"name": "owner_manifest_release_envelope_full_binding",
"raw_evidence": [
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 2,
"locations": [
"release_inputs.py",
"release_action.py"
],
"name": "all_digests_recomputed_before_side_effects",
"raw_evidence": [
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 3,
"locations": [
"release.py",
"release_deploy.py"
],
"name": "transactional_deploy_compensation_and_resume",
"raw_evidence": [
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 4,
"locations": [
"release_deploy.py"
],
"name": "rollback_restore_approved_release_root_binding",
"raw_evidence": [
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 5,
"locations": [
"grant.py",
"writer.py",
"writer_server.py"
],
"name": "writer_repo_base_worktree_remote_credential_closure",
"raw_evidence": [
"nonroot-focused.xml",
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 6,
"locations": [
"revoker.py"
],
"name": "expiry_aware_crash_recoverable_revoker",
"raw_evidence": [
"nonroot-focused.xml",
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 7,
"locations": [
"deploy/systemd",
"deploy/tmpfiles.d"
],
"name": "non_root_writer_publisher_directory_ownership",
"raw_evidence": [
"nonroot-focused.xml",
"pytest-main.xml",
"systemd-verify.log"
],
"status": "PASS"
},
{
"id": 8,
"locations": [
"release_transport.py",
"gitea_api.py"
],
"name": "structured_loopback_and_redirect_denial",
"raw_evidence": [
"pytest-main.xml"
],
"status": "PASS"
},
{
"id": 9,
"locations": [
"candidate_fixture.py",
"candidate systemd units"
],
"name": "candidate_only_live_integration_fixtures",
"raw_evidence": [
"candidate-live.json",
"nonroot-focused.xml",
"pytest-main.xml"
],
"status": "PASS"
}
],
"total": 9
}
@@ -0,0 +1,14 @@
{
"authority_main_oid": "875d41c3101093149414292067fd700dc214d4d3",
"executed_at": "2026-07-29T12:31:16Z",
"expected_base_oid": "473b86a2f1f5a5fe3b8ad42a6da26c29c78c4170",
"generator": "scripts/generate_v2r1c4_v3_evidence.py",
"generator_schema": "aios.v2r1c4-security-evidence/v3",
"git_version": "git version 2.43.0",
"platform": "Linux-6.8.0-124-generic-x86_64-with-glibc2.39",
"python_executable": "/usr/bin/python3.12",
"python_version": "3.12.3",
"release_branch": "patch/v2r1c4-security-invariants-v3-20260729",
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"source_tree_oid": "20adf8d65858131ce29bc979b8d1c7c0444d52d3"
}
@@ -0,0 +1,9 @@
{
"raw_evidence": "systemd-verify.log",
"status": "PASS",
"units_verified": 6,
"warnings": [
"Accepting user/group name 'aios-governed-development-writer', which does not match strict user/group name rules.",
"Accepting user/group name 'aios-governance-request-publisher', which does not match strict user/group name rules."
]
}
@@ -0,0 +1,84 @@
{
"commands": [
{
"command": "python3 -m compileall -q active-runtime services scripts tests",
"id": "compileall",
"raw_evidence": [
"compileall.log"
],
"returncode": 0
},
{
"command": "python3 -m pytest -q tests --ignore=tests/autonomous-release --junitxml=pytest-main.xml",
"id": "pytest_main",
"raw_evidence": [
"pytest-main.xml"
],
"returncode": 0
},
{
"command": "python3 -m pytest -q tests/autonomous-release --junitxml=pytest-legacy.xml",
"id": "pytest_legacy",
"raw_evidence": [
"pytest-legacy.xml"
],
"returncode": 0
},
{
"command": "python3 -m pytest -q test_non_root_execution_v3.py test_writer_revoker_security_v3.py test_systemd_security_v3.py test_candidate_integration_v3.py --junitxml=nonroot-focused.xml",
"id": "non_root_focused",
"raw_evidence": [
"nonroot-focused.xml"
],
"returncode": 0
},
{
"command": "systemd-analyze --root=STAGED_ROOT verify SIX_CANDIDATE_UNITS",
"id": "systemd_verify",
"raw_evidence": [
"systemd-verify.log"
],
"returncode": 0
},
{
"command": "gitleaks detect --redact --log-opts=EXPECTED_BASE..SOURCE_COMMIT --report-format=json",
"id": "secret_scan",
"raw_evidence": [
"gitleaks.json"
],
"returncode": 0
},
{
"command": "scan tracked paths and changed source for traversal symlinks credentials and dependencies",
"id": "structural_scans",
"raw_evidence": [
"scans.json"
],
"returncode": 0
},
{
"command": "SOURCE_DATE_EPOCH=SOURCE_COMMIT python3 -m build --wheel --no-isolation twice",
"id": "artifact_reproducibility",
"raw_evidence": [
"wheel-repro.json"
],
"returncode": 0
},
{
"command": "run UID1000 candidate health tag-plan and systemd-socket-activate merge probes",
"id": "candidate_live",
"raw_evidence": [
"candidate-live.json"
],
"returncode": 0
},
{
"command": "independent read-only validator audit SOURCE_COMMIT",
"id": "independent_validator",
"raw_evidence": [
"validator.json"
],
"returncode": 0
}
]
}
@@ -0,0 +1,7 @@
{
"collection_errors": 0,
"junit_tests": 899,
"tests_failed": 0,
"tests_passed": 898,
"tests_skipped": 1
}
@@ -0,0 +1,9 @@
# V2R1C4 v3 threat model
Assets: Owner approval provenance, release objects, rollback root, Writer credentials, candidate-only state.
Trust boundaries: Gitea/Git authority, non-root Writer and Publisher, local loopback HTTP, Unix socket activation, systemd state directories.
Closed threats: manifest substitution, digest-only declaration, partial activation, rollback target substitution, worktree/remote/credential confusion, early or partial revocation, root-owned directory denial, loopback parser bypass/redirect leak, and candidate state escaping into production.
Residual boundary: the real live-tag test remains intentionally disabled because this task forbids formal tag creation.
@@ -0,0 +1,12 @@
[
{
"description": "Formal live tag validation is disabled because this task forbids tag creation.",
"id": "formal-live-tag",
"status": "ACCEPTED_BOUNDARY"
},
{
"description": "Raw local validation logs are digest-bound but not externally signed.",
"id": "unsigned-local-raw-evidence",
"status": "ACCEPTED_BOUNDARY"
}
]
@@ -0,0 +1,7 @@
{
"blocking_layer": "NONE",
"product_invariants_passed": 9,
"raw_evidence": "validator.json",
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"status": "PASS"
}
@@ -0,0 +1,10 @@
{
"candidate_only": true,
"health": "PASS",
"merge_socket": "PASS",
"process_uid": 1000,
"production_modified": false,
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"status": "PASS",
"tag_execute": false
}
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="20" time="0.798" timestamp="2026-07-29T20:28:16.382718+08:00" hostname="cn-network-mkt"><properties><property name="process_uid" value="1000" /></properties><testcase classname="tests.autonomous_control_plane.test_non_root_execution_v3" name="test_non_root_execution_identity" time="0.004" /><testcase classname="tests.autonomous_control_plane.test_writer_revoker_security_v3" name="test_revoker_does_not_revoke_before_expiry" time="0.007" /><testcase classname="tests.autonomous_control_plane.test_writer_revoker_security_v3" name="test_revoker_revokes_at_clock_boundary_and_is_idempotent" time="0.021" /><testcase classname="tests.autonomous_control_plane.test_writer_revoker_security_v3" name="test_revoker_resumes_after_partial_api_failure" time="0.021" /><testcase classname="tests.autonomous_control_plane.test_writer_revoker_security_v3" name="test_revoker_preserves_token_revoked_checkpoint_on_401_failure" time="0.019" /><testcase classname="tests.autonomous_control_plane.test_writer_revoker_security_v3" name="test_revoker_recovers_across_receipt_checkpoint_crash" time="0.023" /><testcase classname="tests.autonomous_control_plane.test_writer_revoker_security_v3" name="test_terminal_trigger_allows_early_idempotent_revocation" time="0.022" /><testcase classname="tests.autonomous_control_plane.test_systemd_security_v3" name="test_non_root_writer_has_service_owned_private_directories" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_systemd_security_v3" name="test_non_root_publisher_has_no_shared_root_owned_write_directory" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_systemd_security_v3" name="test_revoker_recovery_entrypoint_keeps_revoked_credential_source_loadable" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_systemd_security_v3" name="test_candidate_systemd_contract_is_socket_and_loopback_only" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_systemd_security_v3" name="test_candidate_entrypoint_and_configuration_are_explicit" time="0.001" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_initialization_isolated_and_bound" time="0.008" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_rejects_production_roots[/var/lib/aios-gitops/release/v2r1c4]" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_rejects_production_roots[/var/lib/aios-gitops/artifacts/v2r1c4]" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_rejects_production_roots[/opt/aios/v2r1c4]" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_rejects_production_roots[/data/aios-gitops/runtime/releases/v2r1c4]" time="0.000" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_merge_and_tag_fail_closed" time="0.001" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_merge_stdio_uses_resolved_absolute_interpreter" time="0.082" /><testcase classname="tests.autonomous_control_plane.test_candidate_integration_v3" name="test_candidate_live_port_8080_health_and_tag_no_write" time="0.529" /></testsuite></testsuites>
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="2" time="0.045" timestamp="2026-07-29T20:28:16.185613+08:00" hostname="cn-network-mkt"><testcase classname="tests.autonomous-release.test_core_contracts" name="test_plan_policy_accepts_candidate_plan" time="0.000" /><testcase classname="tests.autonomous-release.test_core_contracts" name="test_evidence_chain_detects_valid_closure" time="0.000" /></testsuite></testsuites>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,17 @@
{
"credential_pattern_hits": {
"authorization_header": [],
"credential_url": [],
"hardcoded_token": [],
"private_key": []
},
"dependency_scan": {
"declared_runtime_dependencies": 0,
"status": "PASS"
},
"hardcoded_credentials": 0,
"path_traversal_entries": [],
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"symlink_entries": [],
"tracked_path_count": 765
}
@@ -0,0 +1,6 @@
{
"blocking_layer": "NONE",
"product_invariants_passed": 9,
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"status": "PASS"
}
@@ -0,0 +1,6 @@
{
"first_sha256": "a0415df8e4d131a32a3ce39a6e997b0304657224642bf47d73adddb684a7d4ca",
"second_sha256": "a0415df8e4d131a32a3ce39a6e997b0304657224642bf47d73adddb684a7d4ca",
"source_commit_oid": "56bb00cd134f4d545935416256bdb018d5c8d58b",
"status": "PASS"
}
@@ -0,0 +1,23 @@
{
"components": [
"governed-development-writer",
"approval-mirror-worker",
"approval-watcher",
"release-object-projection",
"runtime-source-projection",
"automatic-renewal-controller",
"v2r1c4-release-envelope"
],
"direct_main_push": false,
"force_push": false,
"global_writes_must_remain_false": true,
"schema": "aios.code-handoff/v1",
"source": "codex-chartgpt-bridge",
"tag_rewrite": false,
"target_branch": "patch/v2r1c4-release-completion-20260729",
"wechat_backend": {
"code_generated": false,
"reason": "PR #20 source diff exceeded the available controlled diff interface; do not invent API contracts.",
"required_action": "Import the exact approved PR #20 objects, then apply the release-envelope tests and hardening checks."
}
}
@@ -0,0 +1,54 @@
{
"CODE_HANDOFF_MANIFEST.json": "5723d17bee218d5fac627b439b898fe57506f3a153feab4561013b1f37937c26",
"INTEGRATION_NOTES.md": "e058b51d6c0fabb25abcdff44058a56f5d6adcaf9733b29b9cc4fc10de1603b3",
"TEST_RECEIPT.json": "e8699510eca3b805dac879ba3d6955954ebe17de7cd2142e60c205902627b8cf",
"config/examples/development-policy.json": "51ab926a733c9a5173df43a3bf23d25ee3bd2b4743f2005cc458dcef232f62e4",
"deploy/systemd/aios-autonomous-renewal-controller.service": "1e8825341884c428535ed0e56259c5c5919387d7dba130d36812bbb3312d4e29",
"deploy/systemd/aios-governance-approval-watcher.service": "19d5a1e1b5e89405dc8fbe3332daaa4fd652cc903d12e1a81a3e5fb8cf5ad538",
"deploy/systemd/aios-governance-mirror-worker.service": "8d7ed60961ec19fe72ef183d28c5ce8185decff5000f5f884acfb83a4bf21bbd",
"deploy/systemd/aios-governance-request-publisher.service": "037c709d737677257ac3911285768db5549d557cada7f31f3913131873f93c70",
"deploy/systemd/aios-governed-development-writer-revoker.service": "ac566dd3a01d4b83e44a32fcd78d34355a2cf439c91d3e53f554e65c8e480246",
"deploy/systemd/aios-governed-development-writer-revoker.timer": "0bf2bc416012b5009ccb9c7b8f76d546fa6485295a926829fd3b26e0c1f071ce",
"deploy/systemd/aios-governed-development-writer.service": "2f3061c2fe114243b3bb66031bb50175d65ead7448d8c83082faa2135af7b6cc",
"deploy/systemd/aios-release-object-projection.service": "e5341f89ceb4c362b2ed87a6eba7c8bf150aec293788c1aa997d5dfc689dff44",
"deploy/systemd/aios-runtime-source-read-projection.service": "1a83e23203f7edee365d74d8a825f4a3e1dfea6177b84c3faa6c5dda6c1ee78b",
"deploy/tmpfiles.d/aios-autonomous-control-plane.conf": "9e36e522d87f85a13fd03c68f006e63068cf94bec06525eb420344dc734fa162",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__init__.py": "52a7864b6a4ac94be8f67100c825813b19ccf889283bbb7dbecbd342b9ec29dc",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/__init__.cpython-313.pyc": "6704553f751bce9e6a544178580eedf7c3a11f58b6f9eab554e1dc53a027020e",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/cli.cpython-313.pyc": "9d827fb60110c05593916050fcd647708886c12c6e9e784533a56f3525dd8c9b",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/common.cpython-313.pyc": "9e6368b69c75abf46cf708267c7dde591b0a6cdd535f87b6022ea9393ac7c95b",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/ledger.cpython-313.pyc": "abf49a51060c8637eb3aae378a86ea3938177b5d442bd93f1f581434a2c45604",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/mirror.cpython-313.pyc": "0dbdfc445d19227346c75815597476e8dc5bbcba6e08a748624bc5813f49dcb9",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/policy.cpython-313.pyc": "75724693bc0810d8e58fb44389afba62cb6a828e8447e76b61751de83d7c5d60",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/projection.cpython-313.pyc": "a09ae9226e4398fe1b469772b06383832d2266134493fa79f19c62fcd3101da2",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/release.cpython-313.pyc": "dafaafbb1076b5e590b0e25eb103cceb5c6ae336fc2db31e014e8cc3fffc7432",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/renewal.cpython-313.pyc": "9438c81cda1987100cf5f6448186688a58fc01ac59333497afefaeb4c080026a",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/watcher.cpython-313.pyc": "4a729399caf5421c688fd7ab37c98fe796a9b9b5361929185fcb2a1ea3ed3456",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__pycache__/writer.cpython-313.pyc": "75e593baf6864353004edb76abe72f1f566ca77a820c23dcee5703e092c5c621",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/cli.py": "cd42b70c35b2d810433db0df013a439dc7993c45c68ea930a9efd5b5faced84c",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/common.py": "395c669df606ed366774663d4ac229225469c77ab3ff72f6a9efcbcef8031f9e",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/ledger.py": "a51eea543d4e44c2faab6b59c7850600908f36090f0a1ddf448c1ca7c21acdbd",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/mirror.py": "20093cf68c0b4db4940d1092b0f09d7638ed210e2739973b1a558a4016208e01",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/policy.py": "5fc5b50e781cfa47e99164635155a9559d168f1f556d8ca2f1694b57b1b57195",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection.py": "3498affdf02fcb51d8a702ff57046ac6d528480ced808b70de1ad56250f61522",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py": "21f4a93a7121c893aaa52bbb31909215a4f64db32673fb10abc61abfdd94897c",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/renewal.py": "2272c428999a769218142b27b0a80e938c96b7cf1e553fdfd94873123dd9ad86",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/watcher.py": "eed557d5f6acfe44881bee44dd92fea6e04ac19f33e2dea874c2a4662b04c824",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py": "79503f3819469051ffb5f222156891a22981fa62ed37b72ce42da6247ae5792d",
"services/aios-autonomous-control-plane/pyproject.toml": "52200725816a1cdbb5e22b6c477fd80539a11013bcf0d6545d99807b29a0c697",
"tests/.pytest_cache/.gitignore": "3ed731b65d06150c138e2dadb0be0697550888a6b47eb8c45ecc9adba8b8e9bd",
"tests/.pytest_cache/CACHEDIR.TAG": "37dc88ef9a0abeddbe81053a6dd8fdfb13afb613045ea1eb4a5c815a74a3bde4",
"tests/.pytest_cache/README.md": "73fd6fccdd802c419a6b2d983d6c3173b7da97558ac4b589edec2dfe443db9ad",
"tests/.pytest_cache/v/cache/lastfailed": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"tests/.pytest_cache/v/cache/nodeids": "bcee695f0c2c1125930b78eae1badd0ffce72495c63bdbb0a44cd50e4d54be8d",
"tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc": "10fb2a851650254dd15bbfb89011cd8373d6c7a052d3181d8e258110d2a3f961",
"tests/autonomous_control_plane/__pycache__/test_mirror_projection.cpython-313-pytest-9.0.2.pyc": "3cbb8295357bee399ab2d2c33b08d55cccb8e2cd5568accb9eedcb756b3be4d1",
"tests/autonomous_control_plane/__pycache__/test_policy_and_writer.cpython-313-pytest-9.0.2.pyc": "41573389ecbc16ae8c1b9990db12dd2f5994469584388ebc82cd0aeb345ca36f",
"tests/autonomous_control_plane/__pycache__/test_renewal_release.cpython-313-pytest-9.0.2.pyc": "e7b05c53ba735723d27cedb7275b24450310109b1e752178c54122a534b2775b",
"tests/autonomous_control_plane/__pycache__/test_watcher.cpython-313-pytest-9.0.2.pyc": "5e13e650b803412db0105d3e7f3e84cada3187a170173360c6da0304a193cb1e",
"tests/autonomous_control_plane/test_mirror_projection.py": "818410d5571d36cb23df0db0be444a9c08c705325ecfeeebe88fc0d82dbffcd3",
"tests/autonomous_control_plane/test_policy_and_writer.py": "723a6fafcc542de7da028d2a2f76a6eb2b7975d4e6e9d1a23c17973019f74b7c",
"tests/autonomous_control_plane/test_renewal_release.py": "29dd1031e59da0d3b5a96a4f613f1a110e0feb77f983ef2072b53795212e7ea1",
"tests/autonomous_control_plane/test_watcher.py": "025ab4432522478ab7094751edf8da702b0e7be25d93876115cf9f416b7188b1",
"tests/conftest.py": "32a3df0734d253b070594fce0327b929c8ee0bbb136ea6fa83a2abecb826415b"
}
@@ -0,0 +1,35 @@
# AIOS V2R1C4 Autonomy Patch
This package contains code developed for integration into
`patch/v2r1c4-release-completion-20260729`.
It deliberately does not invent WeChat Backend endpoints or schemas. The
business implementation from PR #20 must be imported from its real Git objects,
then tested against the release envelope. The control-plane code in this package
is complete and independently testable without production credentials.
## Components
- Governed Development Writer with branch/path/operation policy, idempotent
ledger, secret scan, expected-head CAS, push verification and reconciliation.
- Approval Mirror Worker using file quarantine, add-only approvals validation,
fast-forward-only authoritative update and connectivity fsck.
- Gitea SQLite Approval Watcher with exact-head Owner review validation.
- Release Object Projection and root-only Runtime Source Projection.
- Automatic Renewal Controller with immutable-field comparison and bounded
renewal windows.
- Unified V2R1C4 Release Envelope executor covering merge, tag, remote
verification, deploy, health, rollback, restore, Registry, Baseline and final
consistency.
- Hardened systemd units and tmpfiles definitions.
## Agent integration constraints
- Keep `AIOS_GITOPS_WRITES_ENABLED=false`.
- Apply on a non-main branch only.
- Do not copy sample credentials or secrets.
- Resolve actual Gitea repository and database paths dynamically.
- Replace server wrapper placeholders under `/usr/libexec` with thin adapters
calling the supplied Python package.
- Run the supplied tests plus existing repository tests before requesting Owner
approval.
@@ -0,0 +1,44 @@
{
"compiled_cache_files_integrated": false,
"credential_scan": "PASS_TEST_REJECTION_FIXTURE_ONLY",
"direct_main_push": false,
"file_sha256_entries": 52,
"file_sha256_verified": true,
"fixture_value_sha256": "653bb1245e828fcda4fa53fcd5a3def5bd7654e651f54b4132b73d74e64435c4",
"force_push_used": false,
"global_gitops_writes_enabled": false,
"path_traversal_entries": 0,
"schema": "aios.code-handoff-integration/v1",
"source_files_integrated": [
"config/examples/development-policy.json",
"deploy/tmpfiles.d/aios-autonomous-control-plane.conf",
"services/aios-autonomous-control-plane/pyproject.toml",
"tests/conftest.py",
"deploy/systemd/aios-autonomous-renewal-controller.service",
"deploy/systemd/aios-governance-approval-watcher.service",
"deploy/systemd/aios-governance-mirror-worker.service",
"deploy/systemd/aios-governance-request-publisher.service",
"deploy/systemd/aios-governed-development-writer-revoker.service",
"deploy/systemd/aios-governed-development-writer-revoker.timer",
"deploy/systemd/aios-governed-development-writer.service",
"deploy/systemd/aios-release-object-projection.service",
"deploy/systemd/aios-runtime-source-read-projection.service",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/__init__.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/cli.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/common.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/ledger.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/mirror.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/policy.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/projection.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/release.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/renewal.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/watcher.py",
"services/aios-autonomous-control-plane/aios_autonomous_control_plane/writer.py",
"tests/autonomous_control_plane/test_mirror_projection.py",
"tests/autonomous_control_plane/test_policy_and_writer.py",
"tests/autonomous_control_plane/test_renewal_release.py",
"tests/autonomous_control_plane/test_watcher.py"
],
"tag_rewritten": false,
"zip_sha256": "795feb406541af86f30c1fb31f85e6d7485ee72a9d3ac93351f9a63fe4ad3e8f"
}
@@ -0,0 +1,6 @@
{
"compileall_returncode": 0,
"pytest_returncode": 0,
"pytest_stderr": "Spreadsheet runtime warmup failed during python startup\nTraceback (most recent call last):\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/patches/warm_spreadsheet_runtime_on_startup.py\", line 26, in warm_spreadsheet_runtime_on_startup\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/spreadsheet_warmup.py\", line 785, in warm_spreadsheet_runtime\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/spreadsheet_warmup.py\", line 720, in _warm_feature_flows\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/spreadsheet_warmup.py\", line 704, in _warm_collaboration_flows\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/generated/interface/models.py\", line 30820, in hydrate_crdt_from_proto\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/rpc/remote.py\", line 749, in __call__\n File \"/tmp/tmp.yTcnQsZYiA/artifact_tool_v2-2.8.4/artifact_tool/rpc/client.py\", line 150, in call\nartifact_tool.rpc.client.RemoteError: hydrateCrdtFromProto requires an empty collaborative document.\n",
"pytest_stdout": "\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m [100%]\u001b[0m\n\u001b[32m\u001b[32m\u001b[1m10 passed\u001b[0m\u001b[32m in 0.45s\u001b[0m\u001b[0m\n"
}
@@ -0,0 +1,25 @@
{
"artifact_path": "/var/lib/aios-gitops/runtime/tasks/AIOS-SINGLE-OWNER-GOVERNANCE-ACTIVATION-20260729/artifacts/hardening-71def340e7cc34f4f19918dcf8d3c847abbe4fbf/live-activation-71def340e7cc34f4f19918dcf8d3c847abbe4fbf.tar.gz",
"artifact_sha256": "32bc49c207ec454b6fd81b0484f5b257bb789481b37175995029a2ec78cc62fa",
"copied_live_db_acceptance": "PASS",
"implementation_commit_oid": "71def340e7cc34f4f19918dcf8d3c847abbe4fbf",
"implementation_tree_oid": "3cc61bfbf69cbe0a24d54a0e53a6c50bcc130066",
"independent_validator": "ALLOW_CANDIDATE",
"production_mutation": false,
"result": "PASS",
"rollback_artifact_path": "/var/lib/aios-gitops/runtime/tasks/AIOS-SINGLE-OWNER-GOVERNANCE-ACTIVATION-20260729/artifacts/hardening-71def340e7cc34f4f19918dcf8d3c847abbe4fbf/live-activation-rollback-71def340e7cc34f4f19918dcf8d3c847abbe4fbf.tar.gz",
"rollback_artifact_sha256": "4efe1ea73d4fd72e5364fc91a16ad5e9d1e6ebe78d8aa466f7b11c4915b08403",
"runtime_source_sha256": {
"services/aios-single-owner-governance/aios_single_owner_governance/activation.py": "48846a58fa3afb2b7c8ffe6e88504a9333863932df867f33ba0321ad3bac6003",
"services/aios-single-owner-governance/aios_single_owner_governance/gitea_protected_branch.py": "00775efe3f3d631d88379eff4ed2dcfaf386a2fa43111abe961e75109e80d768",
"services/aios-single-owner-governance/aios_single_owner_governance/journal.py": "a8f121245e04487d99c99fb03ada83f0c907723f8eb18552872ff46dcf5a7873",
"services/aios-single-owner-governance/aios_single_owner_governance/state_machine.py": "0b08a2c378d143cb9031a25132afc7b7d825bdc03d11efe10610341d4b70167e",
"services/aios-single-owner-governance/aios_single_owner_governance/validator.py": "754639846cb15cb997d612a1fe0ceb0224ddef5bbc3ccac9802a3747f122dac1"
},
"subtests_passed": 17,
"task_id": "AIOS-SINGLE-OWNER-GOVERNANCE-ACTIVATION-20260729",
"test_evidence_path": "/var/lib/aios-gitops/runtime/tasks/AIOS-SINGLE-OWNER-GOVERNANCE-ACTIVATION-20260729/artifacts/hardening-71def340e7cc34f4f19918dcf8d3c847abbe4fbf/test-evidence-71def340e7cc34f4f19918dcf8d3c847abbe4fbf.json",
"test_evidence_sha256": "c1633732767f3f051ffb01404d12d05a6168a4b01b91efdb34a64988d6dee684",
"tests_failed": 0,
"tests_passed": 90
}
+10 -1
View File
@@ -2,6 +2,15 @@
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"
manifest_log="${TMPDIR:-/tmp}/aios_manifest_check.$$.log"
cleanup() {
rm -f -- "$manifest_log"
}
trap cleanup EXIT
bash scripts/package_contract_check_v1r1c0.sh
if [ -f FULL_PACKAGE_FILE_MANIFEST.sha256 ]; then sha256sum -c FULL_PACKAGE_FILE_MANIFEST.sha256 --ignore-missing >/tmp/aios_manifest_check.log || true; fi
if [ ! -f FULL_PACKAGE_FILE_MANIFEST.sha256 ]; then
echo "FULL_PACKAGE_FILE_MANIFEST.sha256 missing" >&2
exit 1
fi
sha256sum -c FULL_PACKAGE_FILE_MANIFEST.sha256 --ignore-missing >"$manifest_log"
echo "AIOS_V1R1C0_PACKAGE_VERIFY_OK"
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""Build deterministic dormant-release candidate artifacts."""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
import tarfile
def sha256(value: bytes) -> str:
return hashlib.sha256(value).hexdigest()
def build(source: Path, output: Path, source_oid: str, tree_oid: str) -> dict[str, str]:
if not source.exists() or not source.is_dir():
raise SystemExit("source directory missing")
files = []
for item in sorted(source.rglob("*")):
if item.is_file() and ".git" not in item.parts:
files.append(item)
artifact = output / "candidate.tar"
manifest = output / "manifest.json"
output.mkdir(parents=True, exist_ok=True)
with tarfile.open(artifact, "w", format=tarfile.PAX_FORMAT) as archive:
for item in files:
info = archive.gettarinfo(str(item), arcname=str(item.relative_to(source)))
info.mtime = 0
info.uid = 0
info.gid = 0
with item.open("rb") as handle:
archive.addfile(info, handle)
payload = {
"source_oid": source_oid,
"tree_oid": tree_oid,
"artifact_sha256": sha256(artifact.read_bytes()),
"files": {
str(item.relative_to(source)): sha256(item.read_bytes())
for item in files
},
}
manifest.write_text(json.dumps(payload, sort_keys=True, indent=2), encoding="utf-8")
return {
"artifact_sha256": payload["artifact_sha256"],
"manifest_sha256": sha256(manifest.read_bytes()),
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("source", type=Path)
parser.add_argument("output", type=Path)
parser.add_argument("source_oid")
parser.add_argument("tree_oid")
args = parser.parse_args()
print(json.dumps(build(args.source, args.output, args.source_oid, args.tree_oid)))
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""Evaluate AIOS V2R1C4 dormant release evidence.
This command performs no Git, network, deployment, tag, Registry or Baseline
write. It evaluates explicit evidence supplied by a governed execution agent
and writes a deterministic JSON decision report.
"""
from __future__ import annotations
import argparse
from dataclasses import dataclass
from datetime import datetime, timezone
import json
from pathlib import Path
import sys
from typing import Any, Mapping
REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
PACKAGE_ROOT = REPOSITORY_ROOT / "services" / "aios-autonomous-release-candidate"
if str(PACKAGE_ROOT) not in sys.path:
sys.path.insert(0, str(PACKAGE_ROOT))
from aios_autonomous_release_candidate.acceptance import ( # noqa: E402
AcceptancePhase,
AcceptanceStatus,
DormantAcceptanceGate,
DormantAcceptanceInput,
FinalDormantAcceptanceGate,
FinalDormantAcceptanceInput,
)
from aios_autonomous_release_candidate.models import sha256_json # noqa: E402
REPORT_SCHEMA = "aios.dormant-release.acceptance/v1"
@dataclass(frozen=True, slots=True)
class RunnerDecision:
phase: str
status: str
report: Mapping[str, Any]
exit_code: int
def read_json_object(path: Path) -> Mapping[str, Any]:
try:
value = json.loads(path.read_text(encoding="utf-8"))
except FileNotFoundError as exc:
raise ValueError(f"input file does not exist: {path}") from exc
except json.JSONDecodeError as exc:
raise ValueError(f"input is not valid JSON: {exc.msg}") from exc
if not isinstance(value, dict):
raise ValueError("input must contain one JSON object")
return value
def atomic_write_json(path: Path, payload: Mapping[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_suffix(path.suffix + ".tmp")
temporary.write_text(
json.dumps(payload, sort_keys=True, indent=2) + "\n",
encoding="utf-8",
)
temporary.chmod(0o600)
temporary.replace(path)
def evaluate(phase: AcceptancePhase, evidence: Mapping[str, Any]) -> RunnerDecision:
if phase is AcceptancePhase.CANDIDATE:
parsed = DormantAcceptanceInput.from_mapping(evidence)
result = DormantAcceptanceGate().evaluate(parsed)
else:
parsed = FinalDormantAcceptanceInput.from_mapping(evidence)
result = FinalDormantAcceptanceGate().evaluate(parsed)
result_payload = dict(result.payload())
report = {
"schema": REPORT_SCHEMA,
"phase": result.phase.value,
"status": result.status.value,
"decision": result_payload,
"input_sha256": sha256_json(evidence),
"production_action_authorized": False,
}
return RunnerDecision(
phase=result.phase.value,
status=result.status.value,
report=report,
exit_code=0 if result.status is AcceptanceStatus.READY else 3,
)
def invalid_report(phase: str, message: str) -> RunnerDecision:
report = {
"schema": REPORT_SCHEMA,
"phase": phase,
"status": AcceptanceStatus.BLOCKED.value,
"decision": {
"blocking_code": "INVALID_ACCEPTANCE_INPUT",
"blocking_message": message,
},
"production_action_authorized": False,
}
return RunnerDecision(
phase=phase,
status=AcceptanceStatus.BLOCKED.value,
report=report,
exit_code=2,
)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="run_acceptance.py")
parser.add_argument(
"--phase",
required=True,
choices=[phase.value for phase in AcceptancePhase],
)
parser.add_argument("--input", required=True, type=Path)
parser.add_argument("--output", required=True, type=Path)
return parser
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
try:
phase = AcceptancePhase(args.phase)
evidence = read_json_object(args.input)
decision = evaluate(phase, evidence)
except (OSError, TypeError, ValueError) as exc:
decision = invalid_report(args.phase, str(exc))
envelope = dict(decision.report)
envelope["generated_at"] = datetime.now(timezone.utc).isoformat()
atomic_write_json(args.output, envelope)
print(json.dumps(envelope, sort_keys=True))
return decision.exit_code
if __name__ == "__main__":
raise SystemExit(main())
+356
View File
@@ -0,0 +1,356 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
import platform
import shutil
import subprocess
import sys
import xml.etree.ElementTree as ET
OBSERVATION_SCHEMA = "aios.v2r1c4-validation-observations/v3"
BRANCH = "patch/v2r1c4-security-invariants-v3-20260729"
REQUIRED_RAW = {
"compileall.log", "pytest-main.xml", "pytest-legacy.xml",
"nonroot-focused.xml", "systemd-verify.log", "gitleaks.json",
"scans.json", "wheel-repro.json", "candidate-live.json", "validator.json",
}
REQUIRED_COMMANDS = {
"compileall": {"compileall.log"},
"pytest_main": {"pytest-main.xml"},
"pytest_legacy": {"pytest-legacy.xml"},
"non_root_focused": {"nonroot-focused.xml"},
"systemd_verify": {"systemd-verify.log"},
"secret_scan": {"gitleaks.json"},
"structural_scans": {"scans.json"},
"artifact_reproducibility": {"wheel-repro.json"},
"candidate_live": {"candidate-live.json"},
"independent_validator": {"validator.json"},
}
COMMAND_TEXT = {
"compileall": "python3 -m compileall -q active-runtime services scripts tests",
"pytest_main": "python3 -m pytest -q tests --ignore=tests/autonomous-release --junitxml=pytest-main.xml",
"pytest_legacy": "python3 -m pytest -q tests/autonomous-release --junitxml=pytest-legacy.xml",
"non_root_focused": "python3 -m pytest -q test_non_root_execution_v3.py test_writer_revoker_security_v3.py test_systemd_security_v3.py test_candidate_integration_v3.py --junitxml=nonroot-focused.xml",
"systemd_verify": "systemd-analyze --root=STAGED_ROOT verify SIX_CANDIDATE_UNITS",
"secret_scan": "gitleaks detect --redact --log-opts=EXPECTED_BASE..SOURCE_COMMIT --report-format=json",
"structural_scans": "scan tracked paths and changed source for traversal symlinks credentials and dependencies",
"artifact_reproducibility": "SOURCE_DATE_EPOCH=SOURCE_COMMIT python3 -m build --wheel --no-isolation twice",
"candidate_live": "run UID1000 candidate health tag-plan and systemd-socket-activate merge probes",
"independent_validator": "independent read-only validator audit SOURCE_COMMIT",
}
INVARIANTS = {
1: ("owner_manifest_release_envelope_full_binding", ["approval_binding.py", "release.py", "release_action.py"]),
2: ("all_digests_recomputed_before_side_effects", ["release_inputs.py", "release_action.py"]),
3: ("transactional_deploy_compensation_and_resume", ["release.py", "release_deploy.py"]),
4: ("rollback_restore_approved_release_root_binding", ["release_deploy.py"]),
5: ("writer_repo_base_worktree_remote_credential_closure", ["grant.py", "writer.py", "writer_server.py"]),
6: ("expiry_aware_crash_recoverable_revoker", ["revoker.py"]),
7: ("non_root_writer_publisher_directory_ownership", ["deploy/systemd", "deploy/tmpfiles.d"]),
8: ("structured_loopback_and_redirect_denial", ["release_transport.py", "gitea_api.py"]),
9: ("candidate_only_live_integration_fixtures", ["candidate_fixture.py", "candidate systemd units"]),
}
INVARIANT_RAW = {
1: ["pytest-main.xml"],
2: ["pytest-main.xml"],
3: ["pytest-main.xml"],
4: ["pytest-main.xml"],
5: ["nonroot-focused.xml", "pytest-main.xml"],
6: ["nonroot-focused.xml", "pytest-main.xml"],
7: ["nonroot-focused.xml", "pytest-main.xml", "systemd-verify.log"],
8: ["pytest-main.xml"],
9: ["candidate-live.json", "nonroot-focused.xml", "pytest-main.xml"],
}
FAILURE_TESTS = {
"deploy_mid_restart_resume": "test_deploy_mid_step_failure_resumes_without_losing_rollback_target",
"deploy_compensation": "test_executor_persists_failed_activation_compensation_and_resumes",
"rollback_binding_mismatch": "test_artifact_rejects_unmanifested_files_and_rollback_escape",
"revoker_receipt_checkpoint_crash": "test_revoker_recovers_across_receipt_checkpoint_crash",
"loopback_parser_bypass": "test_loopback_url_validation_is_structured",
"writer_binding_mismatch": "test_writer_server_rejects_credential_identity_mismatch",
}
def run(root: Path, *args: str) -> str:
return subprocess.check_output(
["git", "-c", f"safe.directory={root}", "-C", str(root), *args], text=True,
).strip()
def write_json(path: Path, value: object) -> None:
path.write_text(json.dumps(value, sort_keys=True, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
def sha256(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def fail(code: str) -> None:
raise SystemExit(code)
def exact_dict(value: object, keys: set[str], code: str) -> dict:
if not isinstance(value, dict) or set(value) != keys:
fail(code)
return value
def junit_totals(paths: list[Path]) -> dict[str, int]:
totals = {"tests": 0, "failures": 0, "errors": 0, "skipped": 0}
for path in paths:
try:
root = ET.parse(path).getroot()
except (ET.ParseError, OSError):
fail("JUNIT_RAW_INVALID")
suites = [root] if root.tag == "testsuite" else list(root.findall("testsuite"))
if not suites:
fail("JUNIT_RAW_INVALID")
for suite in suites:
for key in totals:
try:
totals[key] += int(suite.attrib.get(key, "0"))
except ValueError:
fail("JUNIT_RAW_INVALID")
return totals
def passing_junit_names(path: Path) -> set[str]:
try:
return {
node.attrib.get("name", "") for node in ET.parse(path).getroot().iter("testcase")
if not any(node.find(tag) is not None for tag in ("failure", "error", "skipped"))
}
except (ET.ParseError, OSError):
fail("JUNIT_RAW_INVALID")
def junit_property(path: Path, name: str) -> str:
try:
values = [
node.attrib.get("value", "") for node in ET.parse(path).getroot().iter("property")
if node.attrib.get("name") == name
]
except (ET.ParseError, OSError):
fail("JUNIT_RAW_INVALID")
if len(values) != 1:
fail("JUNIT_PROPERTY_INVALID")
return values[0]
def load_json(path: Path, code: str) -> object:
try:
return json.loads(path.read_text(encoding="utf-8"))
except (OSError, UnicodeError, json.JSONDecodeError):
fail(code)
def validate_observations(observations: object, source: str) -> dict[str, Path]:
required_keys = {
"schema", "source_commit_oid", "commands", "raw_evidence", "security_invariants",
"test_results", "failure_injection_results", "systemd_validation",
"non_root_permission_results", "dependency_scan", "secret_scan",
"path_traversal_scan", "credential_leak_scan", "artifact_reproducibility",
"validator_report", "unresolved_issues",
}
obs = exact_dict(observations, required_keys, "OBSERVATION_SCHEMA_INVALID")
if obs["schema"] != OBSERVATION_SCHEMA:
fail("OBSERVATION_SCHEMA_INVALID")
if obs["source_commit_oid"] != source:
fail("OBSERVATION_SOURCE_COMMIT_MISMATCH")
raw = exact_dict(obs["raw_evidence"], REQUIRED_RAW, "RAW_EVIDENCE_SET_INVALID")
raw_paths: dict[str, Path] = {}
for name, binding in raw.items():
item = exact_dict(binding, {"path", "sha256"}, "RAW_EVIDENCE_SCHEMA_INVALID")
path = Path(item["path"])
if not path.is_absolute() or not path.is_file() or path.is_symlink():
fail("RAW_EVIDENCE_PATH_INVALID")
if sha256(path) != item["sha256"]:
fail("RAW_EVIDENCE_SHA256_MISMATCH")
raw_paths[name] = path
commands = obs["commands"]
if not isinstance(commands, list) or len(commands) != len(REQUIRED_COMMANDS):
fail("OBSERVED_COMMAND_SET_INVALID")
seen: set[str] = set()
for value in commands:
item = exact_dict(value, {"id", "command", "returncode", "raw_evidence"}, "OBSERVED_COMMAND_SCHEMA_INVALID")
command_id = item["id"]
if command_id in seen or command_id not in REQUIRED_COMMANDS or item["returncode"] != 0:
fail("OBSERVED_COMMAND_FAILURE")
if item["command"] != COMMAND_TEXT[command_id]:
fail("OBSERVED_COMMAND_MISMATCH")
if set(item["raw_evidence"]) != REQUIRED_COMMANDS[command_id]:
fail("COMMAND_RAW_BINDING_INVALID")
seen.add(command_id)
if seen != set(REQUIRED_COMMANDS):
fail("OBSERVED_COMMAND_SET_INVALID")
invariants = obs["security_invariants"]
if not isinstance(invariants, list) or len(invariants) != len(INVARIANTS):
fail("SECURITY_INVARIANTS_NOT_CLOSED")
invariant_ids: set[int] = set()
for value in invariants:
item = exact_dict(value, {"id", "name", "status", "locations", "raw_evidence"}, "SECURITY_INVARIANT_SCHEMA_INVALID")
invariant_id = item["id"]
if invariant_id in invariant_ids or invariant_id not in INVARIANTS:
fail("SECURITY_INVARIANT_ID_INVALID")
name, locations = INVARIANTS[invariant_id]
if item["name"] != name or item["status"] != "PASS" or item["locations"] != locations:
fail("SECURITY_INVARIANTS_NOT_CLOSED")
if item["raw_evidence"] != INVARIANT_RAW[invariant_id]:
fail("SECURITY_INVARIANT_RAW_BINDING_INVALID")
invariant_ids.add(invariant_id)
if invariant_ids != set(INVARIANTS):
fail("SECURITY_INVARIANTS_NOT_CLOSED")
junit = junit_totals([raw_paths["pytest-main.xml"], raw_paths["pytest-legacy.xml"]])
tests = exact_dict(obs["test_results"], {"tests_passed", "tests_failed", "tests_skipped", "collection_errors", "junit_tests"}, "TEST_RESULTS_SCHEMA_INVALID")
derived_passed = junit["tests"] - junit["failures"] - junit["errors"] - junit["skipped"]
if tests != {"tests_passed": derived_passed, "tests_failed": junit["failures"] + junit["errors"], "tests_skipped": junit["skipped"], "collection_errors": junit["errors"], "junit_tests": junit["tests"]}:
fail("TEST_RESULTS_RAW_MISMATCH")
if tests["tests_failed"] != 0 or tests["collection_errors"] != 0:
fail("TEST_RESULTS_FAILED")
failure = exact_dict(obs["failure_injection_results"], {"status", "passed", "failed", "scenarios", "raw_evidence"}, "FAILURE_INJECTION_SCHEMA_INVALID")
test_names = passing_junit_names(raw_paths["pytest-main.xml"])
derived_scenarios = [
scenario for scenario, test_name in FAILURE_TESTS.items()
if any(name == test_name or name.startswith(test_name + "[") for name in test_names)
]
if failure != {"status": "PASS", "passed": len(FAILURE_TESTS), "failed": 0, "scenarios": list(FAILURE_TESTS), "raw_evidence": ["pytest-main.xml"]} or derived_scenarios != list(FAILURE_TESTS):
fail("FAILURE_INJECTION_NOT_CLOSED")
systemd = exact_dict(obs["systemd_validation"], {"status", "units_verified", "warnings", "raw_evidence"}, "SYSTEMD_RESULT_SCHEMA_INVALID")
try:
systemd_lines = [line for line in raw_paths["systemd-verify.log"].read_text(encoding="utf-8").splitlines() if line]
compileall_text = raw_paths["compileall.log"].read_text(encoding="utf-8")
except (OSError, UnicodeError):
fail("COMMAND_RAW_INVALID")
denied_systemd = ("failed", "error", "invalid", "not found", "not executable", "unknown key")
if any(any(term in line.lower() for term in denied_systemd) for line in systemd_lines):
fail("SYSTEMD_RAW_FAILED")
if systemd != {"status": "PASS", "units_verified": 6, "warnings": systemd_lines, "raw_evidence": "systemd-verify.log"}:
fail("SYSTEMD_VALIDATION_FAILED")
if compileall_text:
fail("COMPILEALL_RAW_FAILED")
nonroot = exact_dict(obs["non_root_permission_results"], {"status", "uid", "tests_passed", "raw_evidence"}, "NON_ROOT_RESULT_SCHEMA_INVALID")
nonroot_junit = junit_totals([raw_paths["nonroot-focused.xml"]])
nonroot_passed = nonroot_junit["tests"] - nonroot_junit["failures"] - nonroot_junit["errors"] - nonroot_junit["skipped"]
try:
observed_uid = int(junit_property(raw_paths["nonroot-focused.xml"], "process_uid"))
except ValueError:
fail("NON_ROOT_UID_INVALID")
if nonroot != {"status": "PASS", "uid": observed_uid, "tests_passed": nonroot_passed, "raw_evidence": "nonroot-focused.xml"} or observed_uid == 0 or nonroot_passed <= 0 or nonroot_junit["failures"] or nonroot_junit["errors"] or nonroot_junit["skipped"]:
fail("NON_ROOT_VALIDATION_FAILED")
scans = exact_dict(load_json(raw_paths["scans.json"], "SCAN_RAW_INVALID"), {"credential_pattern_hits", "dependency_scan", "hardcoded_credentials", "path_traversal_entries", "source_commit_oid", "symlink_entries", "tracked_path_count"}, "SCAN_RAW_SCHEMA_INVALID")
if scans["source_commit_oid"] != source or scans["path_traversal_entries"] or scans["symlink_entries"] or scans["hardcoded_credentials"] != 0:
fail("STRUCTURAL_SCAN_FAILED")
dependency = exact_dict(obs["dependency_scan"], {"status", "declared_runtime_dependencies", "raw_evidence"}, "DEPENDENCY_RESULT_SCHEMA_INVALID")
if dependency != {"status": "PASS", "declared_runtime_dependencies": 0, "raw_evidence": "scans.json"} or scans["dependency_scan"] != {"declared_runtime_dependencies": 0, "status": "PASS"}:
fail("DEPENDENCY_SCAN_FAILED")
path_scan = exact_dict(obs["path_traversal_scan"], {"status", "entries", "symlinks", "raw_evidence"}, "PATH_SCAN_SCHEMA_INVALID")
if path_scan != {"status": "PASS", "entries": 0, "symlinks": 0, "raw_evidence": "scans.json"}:
fail("PATH_TRAVERSAL_SCAN_FAILED")
credential = exact_dict(obs["credential_leak_scan"], {"status", "hardcoded_credentials", "raw_evidence"}, "CREDENTIAL_SCAN_SCHEMA_INVALID")
if credential != {"status": "PASS", "hardcoded_credentials": 0, "raw_evidence": "scans.json"}:
fail("CREDENTIAL_SCAN_FAILED")
leaks = load_json(raw_paths["gitleaks.json"], "SECRET_RAW_INVALID")
secret = exact_dict(obs["secret_scan"], {"status", "leaks", "raw_evidence"}, "SECRET_RESULT_SCHEMA_INVALID")
if not isinstance(leaks, list) or leaks or secret != {"status": "PASS", "leaks": 0, "raw_evidence": "gitleaks.json"}:
fail("SECRET_SCAN_FAILED")
wheel = exact_dict(load_json(raw_paths["wheel-repro.json"], "ARTIFACT_RAW_INVALID"), {"first_sha256", "second_sha256", "source_commit_oid", "status"}, "ARTIFACT_RAW_SCHEMA_INVALID")
artifact = exact_dict(obs["artifact_reproducibility"], {"status", "sha256", "raw_evidence"}, "ARTIFACT_RESULT_SCHEMA_INVALID")
if wheel["source_commit_oid"] != source or wheel["status"] != "PASS" or wheel["first_sha256"] != wheel["second_sha256"] or artifact != {"status": "PASS", "sha256": wheel["first_sha256"], "raw_evidence": "wheel-repro.json"}:
fail("ARTIFACT_REPRODUCIBILITY_FAILED")
live = exact_dict(load_json(raw_paths["candidate-live.json"], "CANDIDATE_RAW_INVALID"), {"candidate_only", "health", "merge_socket", "process_uid", "production_modified", "source_commit_oid", "status", "tag_execute"}, "CANDIDATE_RAW_SCHEMA_INVALID")
if live != {"candidate_only": True, "health": "PASS", "merge_socket": "PASS", "process_uid": 1000, "production_modified": False, "source_commit_oid": source, "status": "PASS", "tag_execute": False}:
fail("CANDIDATE_LIVE_VALIDATION_FAILED")
validator_raw = exact_dict(load_json(raw_paths["validator.json"], "VALIDATOR_RAW_INVALID"), {"blocking_layer", "product_invariants_passed", "source_commit_oid", "status"}, "VALIDATOR_RAW_SCHEMA_INVALID")
validator = exact_dict(obs["validator_report"], {"status", "source_commit_oid", "product_invariants_passed", "blocking_layer", "raw_evidence"}, "VALIDATOR_RESULT_SCHEMA_INVALID")
if validator_raw != {"blocking_layer": "NONE", "product_invariants_passed": 9, "source_commit_oid": source, "status": "PASS"} or validator != {**validator_raw, "raw_evidence": "validator.json"}:
fail("INDEPENDENT_VALIDATOR_FAILED")
issues = obs["unresolved_issues"]
if not isinstance(issues, list) or any(not isinstance(item, dict) or set(item) != {"id", "status", "description"} or item["status"] not in {"ACCEPTED_BOUNDARY", "RESOLVED"} for item in issues):
fail("UNRESOLVED_ISSUES_INVALID")
return raw_paths
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--repo-root", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--source-commit", required=True)
parser.add_argument("--expected-base", required=True)
parser.add_argument("--authority-main", required=True)
parser.add_argument("--executed-at", required=True)
parser.add_argument("--observations", type=Path, required=True)
args = parser.parse_args()
root = args.repo_root.resolve(strict=True)
output = args.output
if not output.is_absolute() or root not in output.resolve().parents or output.exists():
fail("OUTPUT_PATH_DENIED")
source = run(root, "rev-parse", args.source_commit)
tree = run(root, "rev-parse", f"{source}^{{tree}}")
if run(root, "merge-base", args.expected_base, source) != args.expected_base:
fail("EXPECTED_BASE_NOT_ANCESTOR")
observations = load_json(args.observations, "OBSERVATION_JSON_INVALID")
raw_paths = validate_observations(observations, source)
changed = run(root, "diff", "--name-only", f"{args.expected_base}..{source}").splitlines()
numstat = run(root, "diff", "--numstat", f"{args.expected_base}..{source}").splitlines()
# No output is created until every observation and raw semantic binding passes.
output.mkdir(parents=True, exist_ok=False)
for name, path in raw_paths.items():
shutil.copyfile(path, output / name)
environment = {
"executed_at": args.executed_at,
"git_version": subprocess.check_output(["git", "--version"], text=True).strip(),
"platform": platform.platform(),
"python_executable": str(Path(sys.executable).resolve(strict=True)),
"python_version": platform.python_version(),
"generator": "scripts/generate_v2r1c4_v3_evidence.py",
"generator_schema": "aios.v2r1c4-security-evidence/v3",
}
write_json(output / "SOURCE_MANIFEST.json", {**environment, "authority_main_oid": args.authority_main, "expected_base_oid": args.expected_base, "release_branch": BRANCH, "source_commit_oid": source, "source_tree_oid": tree})
write_json(output / "RELEASE_IDENTIFIERS.json", {"artifact_sha256": "NOT_BUILT", "expected_base_oid": args.expected_base, "production_baseline": "V2R1C3_UNCHANGED", "registry_version": "V2R1C3_UNCHANGED", "release_commit_oid": source, "release_tag": "NOT_CREATED", "release_tree_oid": tree, "rollback_sha256": "NOT_BUILT"})
write_json(output / "DIFF_SUMMARY.json", {"changed_file_count": len(changed), "numstat": numstat, "range": f"{args.expected_base}..{source}"})
write_json(output / "CHANGED_FILES.json", {"files": changed})
write_json(output / "SECURITY_INVARIANT_MATRIX.json", {"fixed": 9, "total": 9, "invariants": observations["security_invariants"]})
(output / "THREAT_MODEL.md").write_text("# V2R1C4 v3 threat model\n\nAssets: Owner approval provenance, release objects, rollback root, Writer credentials, candidate-only state.\n\nTrust boundaries: Gitea/Git authority, non-root Writer and Publisher, local loopback HTTP, Unix socket activation, systemd state directories.\n\nClosed threats: manifest substitution, digest-only declaration, partial activation, rollback target substitution, worktree/remote/credential confusion, early or partial revocation, root-owned directory denial, loopback parser bypass/redirect leak, and candidate state escaping into production.\n\nResidual boundary: the real live-tag test remains intentionally disabled because this task forbids formal tag creation.\n", encoding="utf-8")
outputs = {
"TEST_COMMANDS.json": {"commands": observations["commands"]},
"TEST_RESULTS.json": observations["test_results"],
"FAILURE_INJECTION_RESULTS.json": observations["failure_injection_results"],
"SYSTEMD_VALIDATION.json": observations["systemd_validation"],
"NON_ROOT_PERMISSION_RESULTS.json": observations["non_root_permission_results"],
"DEPENDENCY_SCAN.json": observations["dependency_scan"],
"SECRET_SCAN.json": observations["secret_scan"],
"PATH_TRAVERSAL_SCAN.json": observations["path_traversal_scan"],
"CREDENTIAL_LEAK_SCAN.json": observations["credential_leak_scan"],
"ARTIFACT_REPRODUCIBILITY.json": observations["artifact_reproducibility"],
"VALIDATOR_REPORT.json": observations["validator_report"],
"UNRESOLVED_ISSUES.json": observations["unresolved_issues"],
}
for name, value in outputs.items():
write_json(output / name, value)
payload_files = sorted(path for path in output.iterdir() if path.is_file())
write_json(output / "FILE_SHA256.json", {"files": {path.name: sha256(path) for path in payload_files}})
registered = sorted(path for path in output.iterdir() if path.is_file())
write_json(output / "EVIDENCE_MANIFEST.json", {**environment, "files": {path.name: sha256(path) for path in registered}, "source_commit_oid": source, "source_tree_oid": tree, "status": "CANDIDATE_READY_FOR_INDEPENDENT_VALIDATION"})
return 0
if __name__ == "__main__":
raise SystemExit(main())
+1 -1
View File
@@ -16,7 +16,7 @@ required=(
"config/runtime_selector.yaml"
)
for f in "${required[@]}"; do test -f "$ROOT/$f" || { echo "MISSING $f"; exit 1; }; done
grep -Eq "^V1R1C[0-9]+$" "$ROOT/VERSION"
grep -Eq "^V[0-9]+R[0-9]+C[0-9]+$" "$ROOT/VERSION"
python3 -m py_compile \
"$ROOT/active-runtime/app/aios_gitops_model_api.py" \
"$ROOT/active-runtime/app/aios_chatgpt_actions_api.py" \
+652
View File
@@ -0,0 +1,652 @@
#!/usr/bin/env python3
"""Hardened WeChat outbound backend for AIOS.
Only the dedicated UCC adapter is a supported send backend. OpenClaw channel
discovery is retained for diagnostics, but generic OpenClaw chat or agent
delivery is never promoted to WeChat delivery.
"""
from __future__ import annotations
import json
import os
import re
import selectors
import signal
import subprocess
import time
import urllib.error
import urllib.parse
import urllib.request
from typing import Any, Dict, List, Optional, Tuple
OPENCLAW_BIN = os.environ.get("AIOS_OPENCLAW_BIN", "openclaw")
WECHAT_ACCOUNT_ID = os.environ.get("AIOS_WECHAT_ACCOUNT_ID", "")
WECHAT_CHANNEL = os.environ.get("AIOS_WECHAT_CHANNEL", "")
SEND_BACKEND = os.environ.get("AIOS_WECHAT_SEND_BACKEND", "")
UCC_ADAPTER_URL = os.environ.get("AIOS_UCC_WECHAT_ADAPTER_URL", "http://127.0.0.1:18800")
UCC_ADAPTER_TOKEN = os.environ.get("AIOS_UCC_WECHAT_ADAPTER_TOKEN") or os.environ.get(
"AIOS_WECHAT_QR_ADAPTER_TOKEN", ""
)
UCC_SEND_PATH = os.environ.get("AIOS_UCC_WECHAT_SEND_PATH", "/api/internal/wechat/send")
_allowed_origins = os.environ.get("AIOS_UCC_WECHAT_ALLOWED_ORIGINS", "").strip()
UCC_ADAPTER_ALLOWED_ORIGINS = tuple(
origin.strip() for origin in _allowed_origins.split(",") if origin.strip()
) or (
"http://127.0.0.1:18800",
"http://[::1]:18800",
)
MAX_TARGET_BYTES = 512
MAX_CONTENT_BYTES = 32 * 1024
MAX_IDENTIFIER_BYTES = 512
MAX_METADATA_BYTES = 8 * 1024
MAX_METADATA_DEPTH = 32
MAX_METADATA_NODES = 1024
MAX_RESPONSE_BYTES = 64 * 1024
MAX_ENDPOINT_BYTES = 256
_DEFAULT_TIMEOUT_SECONDS = 10
_MAX_TIMEOUT_SECONDS = 30
_LEGACY_SEND_PATH = "/internal/channels/wechat/send"
_SAFE_PATH = re.compile(r"^/[A-Za-z0-9._~!$&'()*+,;=:@%/-]+$")
_MAX_PATH_DECODE_ROUNDS = 4
_OPENCLAW_TIMEOUT_RETURN_CODE = 124
_OPENCLAW_OUTPUT_LIMIT_RETURN_CODE = 125
_OPENCLAW_SPAWN_ERROR_RETURN_CODE = 126
def _bounded_timeout(value: str) -> int:
try:
parsed = int(value)
except (TypeError, ValueError):
return _DEFAULT_TIMEOUT_SECONDS
return min(max(parsed, 1), _MAX_TIMEOUT_SECONDS)
REQUEST_TIMEOUT_SECONDS = _bounded_timeout(os.environ.get("AIOS_UCC_WECHAT_TIMEOUT_SECONDS", "10"))
class BackendResult:
def __init__(self, ok: bool, backend: str, status: str, data: Dict[str, Any]) -> None:
self.ok = ok
self.backend = backend
self.status = status
self.data = data
def to_dict(self) -> Dict[str, Any]:
return {"ok": self.ok, "backend": self.backend, "status": self.status, **self.data}
class _BackendProtocolError(Exception):
"""Internal marker whose details must never cross the module boundary."""
def _openclaw_base_args() -> List[str]:
"""Return the OpenClaw 2026.6.11-compatible command prefix.
Gateway/auth global flags are not supported by the installed CLI and would
also expose credentials through the process argument vector.
"""
return [OPENCLAW_BIN]
def _terminate_process_tree(process: Any) -> None:
if os.name == "posix":
try:
os.killpg(process.pid, signal.SIGTERM)
except OSError:
pass
try:
process.wait(timeout=0.5)
except (OSError, subprocess.TimeoutExpired):
pass
time.sleep(0.05)
try:
os.killpg(process.pid, signal.SIGKILL)
except OSError:
pass
try:
process.wait(timeout=0.5)
except (OSError, subprocess.TimeoutExpired):
pass
return
if process.poll() is not None:
return
try:
process.terminate()
process.wait(timeout=1)
return
except (OSError, subprocess.TimeoutExpired):
pass
try:
process.kill()
process.wait(timeout=1)
except (OSError, subprocess.TimeoutExpired):
pass
def _run_openclaw(
args: List[str], timeout: int = 15
) -> subprocess.CompletedProcess[str]:
bounded_timeout = min(max(int(timeout), 1), _MAX_TIMEOUT_SECONDS)
popen_options: Dict[str, Any] = {
"stdout": subprocess.PIPE,
"stderr": subprocess.PIPE,
}
if os.name == "posix":
popen_options["start_new_session"] = True
elif hasattr(subprocess, "CREATE_NEW_PROCESS_GROUP"):
popen_options["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP
try:
process = subprocess.Popen(args, **popen_options)
except (OSError, ValueError):
return subprocess.CompletedProcess(args, _OPENCLAW_SPAWN_ERROR_RETURN_CODE, "", "")
selector = selectors.DefaultSelector()
streams = {"stdout": process.stdout, "stderr": process.stderr}
buffers = {"stdout": bytearray(), "stderr": bytearray()}
try:
for name, stream in streams.items():
if stream is not None:
selector.register(stream, selectors.EVENT_READ, name)
except (OSError, ValueError):
selector.close()
_terminate_process_tree(process)
for stream in streams.values():
if stream is not None:
stream.close()
return subprocess.CompletedProcess(args, _OPENCLAW_SPAWN_ERROR_RETURN_CODE, "", "")
deadline = time.monotonic() + bounded_timeout
total_bytes = 0
return_code: Optional[int] = None
try:
while selector.get_map():
remaining = deadline - time.monotonic()
if remaining <= 0:
return_code = _OPENCLAW_TIMEOUT_RETURN_CODE
break
events = selector.select(min(remaining, 0.1))
for key, _mask in events:
allowance = MAX_RESPONSE_BYTES - total_bytes
try:
chunk = os.read(key.fileobj.fileno(), min(8192, allowance + 1))
except OSError:
return_code = _OPENCLAW_SPAWN_ERROR_RETURN_CODE
break
if not chunk:
selector.unregister(key.fileobj)
key.fileobj.close()
continue
if len(chunk) > allowance:
return_code = _OPENCLAW_OUTPUT_LIMIT_RETURN_CODE
break
buffers[key.data].extend(chunk)
total_bytes += len(chunk)
if return_code is not None:
break
finally:
selector.close()
if return_code is not None:
_terminate_process_tree(process)
for stream in streams.values():
if stream is not None and not stream.closed:
stream.close()
return subprocess.CompletedProcess(args, return_code, "", "")
try:
completed_return_code = process.wait(timeout=1)
except subprocess.TimeoutExpired:
_terminate_process_tree(process)
return subprocess.CompletedProcess(args, _OPENCLAW_TIMEOUT_RETURN_CODE, "", "")
stdout = buffers["stdout"].decode("utf-8", errors="replace")
stderr = buffers["stderr"].decode("utf-8", errors="replace")
return subprocess.CompletedProcess(args, completed_return_code, stdout, stderr)
def _json_dict(text: str) -> Dict[str, Any]:
try:
value = json.loads(text or "{}")
except (RecursionError, TypeError, ValueError, json.JSONDecodeError):
return {}
return value if isinstance(value, dict) else {}
def discover_openclaw_wechat_channel() -> Optional[str]:
"""Discover an explicitly typed WeChat/Weixin channel for diagnostics."""
if WECHAT_CHANNEL:
return WECHAT_CHANNEL
try:
proc = _run_openclaw(_openclaw_base_args() + ["channels", "list", "--json"], timeout=15)
except (OSError, subprocess.SubprocessError, ValueError):
return None
if proc.returncode != 0:
return None
data = _json_dict(proc.stdout[:MAX_RESPONSE_BYTES])
candidates: List[str] = []
def walk(value: Any) -> None:
if isinstance(value, dict):
name = value.get("name") or value.get("channel") or value.get("id")
kind = value.get("type") or value.get("kind")
if isinstance(name, str) and isinstance(kind, str):
label = f"{name} {kind}".lower()
if "wechat" in label or "weixin" in label:
candidates.append(name)
for child in value.values():
walk(child)
elif isinstance(value, list):
for child in value:
walk(child)
walk(data)
return candidates[0] if candidates else None
def _auth_headers() -> Dict[str, str]:
headers = {"Content-Type": "application/json", "Accept": "application/json"}
if UCC_ADAPTER_TOKEN:
headers["Authorization"] = "Bearer " + UCC_ADAPTER_TOKEN
return headers
def _safe_path(value: Any) -> Optional[str]:
if not isinstance(value, str):
return None
path = value if value.startswith("/") else "/" + value
try:
encoded_path = path.encode("utf-8")
except UnicodeEncodeError:
return None
if len(encoded_path) > MAX_ENDPOINT_BYTES:
return None
if not _SAFE_PATH.fullmatch(path):
return None
decoded = path
for _ in range(_MAX_PATH_DECODE_ROUNDS):
try:
next_decoded = urllib.parse.unquote_to_bytes(decoded).decode("utf-8")
except UnicodeDecodeError:
return None
if next_decoded == decoded:
break
decoded = next_decoded
if "%" in decoded or "\\" in decoded or "\x00" in decoded:
return None
if not _SAFE_PATH.fullmatch(decoded):
return None
if any(segment in {".", ".."} for segment in decoded.split("/")):
return None
return path
def _unique_paths(paths: List[str]) -> List[str]:
out: List[str] = []
for candidate in paths:
path = _safe_path(candidate)
if path and path not in out:
out.append(path)
if len(out) == 2:
break
return out
def _ucc_send_paths() -> List[str]:
canonical = _safe_path(UCC_SEND_PATH) or "/api/internal/wechat/send"
return _unique_paths([canonical, _LEGACY_SEND_PATH])
def _canonical_origin(value: Any) -> Optional[str]:
if not isinstance(value, str) or not value or len(value) > 2048:
return None
if "\\" in value or any(ord(character) < 32 for character in value):
return None
try:
parsed = urllib.parse.urlsplit(value)
port = parsed.port
except (UnicodeError, ValueError):
return None
scheme = parsed.scheme.lower()
if scheme not in {"http", "https"} or not parsed.hostname:
return None
if parsed.username or parsed.password or parsed.query or parsed.fragment or parsed.path not in {"", "/"}:
return None
try:
host = parsed.hostname.rstrip(".").encode("idna").decode("ascii").lower()
except UnicodeError:
return None
if not host:
return None
if port is None:
port = 80 if scheme == "http" else 443
rendered_host = f"[{host}]" if ":" in host else host
return f"{scheme}://{rendered_host}:{port}"
def _adapter_base_url() -> Optional[str]:
origin = _canonical_origin(UCC_ADAPTER_URL)
allowed = {
canonical
for canonical in (_canonical_origin(value) for value in UCC_ADAPTER_ALLOWED_ORIGINS)
if canonical
}
return origin if origin and origin in allowed else None
class _NoRedirectHandler(urllib.request.HTTPRedirectHandler):
def redirect_request(
self,
req: Any,
fp: Any,
code: int,
msg: str,
headers: Any,
newurl: str,
) -> None:
del req, fp, code, msg, headers, newurl
return None
def _open_no_redirect(request: urllib.request.Request, timeout: int) -> Any:
opener = urllib.request.build_opener(_NoRedirectHandler())
return opener.open(request, timeout=timeout)
def ucc_adapter_alive() -> bool:
base_url = _adapter_base_url()
if not base_url:
return False
request = urllib.request.Request(
base_url + "/health", headers=_auth_headers(), method="GET"
)
try:
with _open_no_redirect(request, timeout=min(5, REQUEST_TIMEOUT_SECONDS)) as response:
return 200 <= int(response.status) < 300
except (OSError, ValueError, urllib.error.URLError):
return False
def select_backend() -> Dict[str, Any]:
explicit = SEND_BACKEND.strip().lower()
if explicit:
if explicit == "ucc-adapter":
return {"backend": "ucc-adapter", "reason": "explicit"}
return {"backend": "unavailable", "reason": "unsupported_backend"}
if ucc_adapter_alive():
return {"backend": "ucc-adapter", "reason": "ucc_adapter_alive"}
return {"backend": "unavailable", "reason": "ucc_adapter_unavailable"}
def _post_ucc(path: str, payload: Dict[str, Any]) -> Tuple[int, Dict[str, Any]]:
base_url = _adapter_base_url()
safe_path = _safe_path(path)
if not base_url or not safe_path:
raise _BackendProtocolError("invalid adapter endpoint")
try:
body = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
except (TypeError, ValueError) as exc:
raise _BackendProtocolError("invalid request payload") from exc
request = urllib.request.Request(
base_url + safe_path,
data=body,
headers=_auth_headers(),
method="POST",
)
with _open_no_redirect(request, timeout=REQUEST_TIMEOUT_SECONDS) as response:
raw = response.read(MAX_RESPONSE_BYTES + 1)
if len(raw) > MAX_RESPONSE_BYTES:
raise _BackendProtocolError("adapter response too large")
try:
text = raw.decode("utf-8")
except UnicodeDecodeError as exc:
raise _BackendProtocolError("adapter response encoding invalid") from exc
data = _json_dict(text)
if not data:
raise _BackendProtocolError("adapter response invalid")
return int(response.status), data
def _ucc_response_sent(data: Dict[str, Any]) -> bool:
return isinstance(data, dict) and data.get("ok") is True and data.get("status") == "sent"
def _ucc_result_is_ok(data: Dict[str, Any], dry_run: bool = False) -> bool:
expected_status = "dry_run" if dry_run else "sent"
return isinstance(data, dict) and data.get("ok") is True and data.get("status") == expected_status
def _utf8_size(value: str) -> Optional[int]:
try:
return len(value.encode("utf-8"))
except UnicodeEncodeError:
return None
def _valid_identifier(value: Any, required: bool = False) -> bool:
if not isinstance(value, str):
return False
if required and not value.strip():
return False
if not value:
return not required
if len(value) > MAX_IDENTIFIER_BYTES:
return False
size = _utf8_size(value)
return size is not None and size <= MAX_IDENTIFIER_BYTES and not any(
ord(character) < 32 or ord(character) == 127 for character in value
)
def _validate_metadata(metadata: Any) -> Optional[str]:
if not isinstance(metadata, dict):
return "invalid_input"
nodes = 0
stack: List[Tuple[Any, int]] = [(metadata, 0)]
while stack:
value, depth = stack.pop()
nodes += 1
if depth > MAX_METADATA_DEPTH or nodes > MAX_METADATA_NODES:
return "input_too_large"
if isinstance(value, dict):
if len(value) + nodes + len(stack) > MAX_METADATA_NODES:
return "input_too_large"
for key, child in value.items():
if (
not isinstance(key, str)
or len(key) > MAX_METADATA_BYTES
or _utf8_size(key) is None
):
return "invalid_input"
stack.append((child, depth + 1))
elif isinstance(value, list):
if len(value) + nodes + len(stack) > MAX_METADATA_NODES:
return "input_too_large"
stack.extend((child, depth + 1) for child in value)
elif isinstance(value, str):
if len(value) > MAX_METADATA_BYTES:
return "input_too_large"
if _utf8_size(value) is None:
return "invalid_input"
elif value is not None and not isinstance(value, (bool, int, float)):
return "invalid_input"
try:
encoded = json.dumps(
metadata,
ensure_ascii=False,
allow_nan=False,
separators=(",", ":"),
).encode("utf-8")
except (RecursionError, TypeError, UnicodeEncodeError, ValueError):
return "invalid_input"
return "input_too_large" if len(encoded) > MAX_METADATA_BYTES else None
def _validate_payload(
target: Any,
content: Any,
account_id: Any,
message_id: Any,
metadata: Any,
dry_run: Any,
) -> Optional[str]:
if not isinstance(target, str) or not isinstance(content, str):
return "invalid_input"
if not target.strip() or not content.strip() or not isinstance(dry_run, bool):
return "invalid_input"
if any(ord(character) < 32 or ord(character) == 127 for character in target):
return "invalid_input"
if "\x00" in content or not _valid_identifier(account_id) or not _valid_identifier(message_id):
return "invalid_input"
if len(target) > MAX_TARGET_BYTES or len(content) > MAX_CONTENT_BYTES:
return "input_too_large"
target_size = _utf8_size(target)
content_size = _utf8_size(content)
if target_size is None or content_size is None:
return "invalid_input"
if target_size > MAX_TARGET_BYTES or content_size > MAX_CONTENT_BYTES:
return "input_too_large"
return _validate_metadata(metadata)
def _safe_provider_message_id(value: Any) -> Optional[str]:
if not isinstance(value, str) or not value:
return None
if len(value) > MAX_IDENTIFIER_BYTES:
return None
size = _utf8_size(value)
if size is None or size > MAX_IDENTIFIER_BYTES:
return None
if any(ord(character) < 32 or ord(character) == 127 for character in value):
return None
return value
def send_ucc_adapter(
target: str,
content: str,
account_id: str = "",
message_id: str = "",
metadata: Optional[Dict[str, Any]] = None,
dry_run: bool = False,
) -> BackendResult:
effective_account = account_id or WECHAT_ACCOUNT_ID
effective_metadata: Any = {} if metadata is None else metadata
error_code = _validate_payload(
target,
content,
effective_account,
message_id,
effective_metadata,
dry_run,
)
if error_code:
return BackendResult(False, "ucc-adapter", "failed", {"code": error_code})
payload = {
"target": target,
"content": content,
"account_id": effective_account,
"message_id": message_id,
"metadata": effective_metadata,
"dry_run": dry_run,
}
last_endpoint: Optional[str] = None
for path in _ucc_send_paths():
last_endpoint = path
try:
http_status, data = _post_ucc(path, payload)
except urllib.error.HTTPError as exc:
if exc.code in {404, 405}:
continue
return BackendResult(
False,
"ucc-adapter",
"failed",
{"code": "ucc_adapter_http_error", "http_status": int(exc.code), "endpoint": path},
)
except (OSError, ValueError, urllib.error.URLError, _BackendProtocolError):
return BackendResult(
False,
"ucc-adapter",
"failed",
{"code": "ucc_adapter_unavailable", "endpoint": path},
)
except Exception:
# Fail closed without returning exception text, type, or chained cause.
return BackendResult(
False,
"ucc-adapter",
"failed",
{"code": "ucc_adapter_unavailable", "endpoint": path},
)
if not (200 <= http_status < 300):
return BackendResult(
False,
"ucc-adapter",
"failed",
{"code": "ucc_adapter_http_error", "http_status": http_status, "endpoint": path},
)
if not _ucc_result_is_ok(data, dry_run):
return BackendResult(
False,
"ucc-adapter",
"failed",
{"code": "ucc_adapter_rejected", "http_status": http_status, "endpoint": path},
)
confirmed_status = "dry_run" if dry_run else "sent"
result_data: Dict[str, Any] = {
"code": confirmed_status,
"http_status": http_status,
"endpoint": path,
}
provider_message_id = _safe_provider_message_id(data.get("provider_message_id"))
if provider_message_id:
result_data["provider_message_id"] = provider_message_id
return BackendResult(True, "ucc-adapter", confirmed_status, result_data)
data: Dict[str, Any] = {"code": "ucc_adapter_unavailable"}
if last_endpoint:
data["endpoint"] = last_endpoint
return BackendResult(False, "ucc-adapter", "failed", data)
def send_openclaw_channel(
target: str,
content: str,
account_id: str = "",
message_id: str = "",
metadata: Optional[Dict[str, Any]] = None,
dry_run: bool = False,
) -> BackendResult:
del target, content, account_id, message_id, metadata, dry_run
return BackendResult(
False,
"openclaw-channel",
"failed",
{"code": "unsupported_backend"},
)
def send_message(
target: str,
content: str,
account_id: str = "",
message_id: str = "",
metadata: Optional[Dict[str, Any]] = None,
dry_run: bool = False,
) -> Dict[str, Any]:
selected = select_backend()
if selected.get("backend") == "ucc-adapter":
return send_ucc_adapter(
target, content, account_id, message_id, metadata, dry_run
).to_dict()
code = "unsupported_backend" if selected.get("reason") == "unsupported_backend" else "wechat_outbound_backend_unavailable"
return BackendResult(False, "unavailable", "failed", {"code": code}).to_dict()
if __name__ == "__main__":
print(json.dumps(select_backend(), ensure_ascii=False, separators=(",", ":")))

Some files were not shown because too many files have changed in this diff Show More