Compare commits

...
Author SHA1 Message Date
Codex 0193a12b57 chore(worktree): ignore registered child worktrees 2026-07-21 15:13:47 +08:00
Codex Git Acceptance b87266d63f docs: complete secret acl hardening evidence 2026-07-15 01:13:46 +08:00
Codex Git Acceptance c0d8284615 evidence: finalize secret acl hardening 2026-07-15 01:06:40 +08:00
Codex Git Acceptance 7c42363058 acceptance: codex git writer TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8-FINAL 2026-07-15 01:06:10 +08:00
AIOS Codex Migration 1bb06334ff docs(codex): record mode restoration verification 20260715T001652UTC8 2026-07-15 00:38:01 +08:00
AIOS Codex Migration 5f0f1a443b docs(codex): clarify persisted raw-log scope 20260715T001652UTC8 2026-07-15 00:35:30 +08:00
AIOS Codex Migration acd42f3601 docs(codex): correct raw-log count note 20260715T001652UTC8 2026-07-15 00:34:41 +08:00
AIOS Codex Migration 523eb0898d docs(codex): correct migration result formatting 20260715T001652UTC8 2026-07-15 00:34:09 +08:00
AIOS Codex Migration 120fb909f8 docs(codex): record isolated worktree migration 20260715T001652UTC8 2026-07-15 00:32:53 +08:00
AIOS Codex Migration bcbda0d048 test(Codex): isolated worktree migration acceptance 20260715T001652UTC8 2026-07-15 00:32:53 +08:00
openclaw b05eb1babe task(codex): execute isolated worktree migration 20260715T001652UTC8 2026-07-15 00:17:28 +08:00
openclaw a8581699f2 task(openclaw): migrate GitOps to isolated worktrees 20260714T233742UTC8 2026-07-14 23:32:52 +08:00
openclaw cc9cada5df feat(gitops): add unified systemd runtime identity drop-in 2026-07-14 23:32:18 +08:00
openclaw dbed29c8c7 feat(gitops): add task environment preflight 2026-07-14 23:32:12 +08:00
openclaw 24f7e4ecc3 feat(gitops): add per-task worktree lifecycle script 2026-07-14 23:31:59 +08:00
openclaw b588bf8fb2 feat(gitops): add isolated worktree bootstrap script 2026-07-14 23:31:43 +08:00
openclaw f300033138 fix(gitops): correct default ACL runtime user 2026-07-14 23:31:32 +08:00
openclaw 7308c9c0c1 feat(gitops): add isolated worktree governance policy 2026-07-14 23:31:21 +08:00
openclaw 48290bd620 chore(gitops): start isolated worktree and unified identity governance 2026-07-14 23:30:07 +08:00
12 changed files with 708 additions and 0 deletions
@@ -0,0 +1,267 @@
# 执行 GitOps 独立 Worktree 与统一运行身份迁移
```yaml
task_id: TASK-GITOPS-ISOLATED-WORKTREE-MIGRATION-20260714T233742UTC8
created_at: 2026-07-14T23:37:42+08:00
timezone: Asia/Shanghai
owner_approved: true
user_action_required: false
risk: high
production_business_change: false
```
## 目标
根治共享 worktree 与多身份写入导致的 ACL、checkout 和未跟踪文件覆盖问题。
实施:
1. 统一 GitOps/OpenClaw 写入身份为 `aiman:gitops`;
2. 统一 `UMask=0002`;
3. 为 GitOps 根目录设置 setgid 与默认 ACL;
4. 建立 bare repo 和每任务独立 worktree;
5. 启用任务启动前自检;
6. 验证 OpenClaw 与 ChatGPT 并发任务互不干扰;
7. 保留原共享 workspace 作为只读回滚源,禁止智能体继续在其中切换分支。
## 强制通知
收到任务后立即微信通知 Owner:
```text
【任务已接收】GitOps独立worktree与统一运行身份迁移开始。将暂停写入服务、建立独立任务工作树并验证并发执行;生产业务版本不变。
```
任务结束后无论 PASS、BLOCKED 或 ROLLED_BACK,立即微信汇报结果并记录 message_id。
## 1. 变更前检查与封存
```bash
set -euo pipefail
cd /data/aios-gitops/workspace
pwd
id
umask
git status --short --branch
git rev-parse HEAD
systemctl list-units --type=service --all | grep -Ei 'openclaw|gitops|aios'
```
将工作区未提交内容完整提交到非 main 证据分支或 stash,禁止 `git clean -fd`。
记录当前运行服务、用户、组、umask、PID、工作区 HEAD 和未跟踪文件清单。
## 2. 暂停所有写入服务
识别并停止实际写入服务:
```bash
systemctl stop <gitops-writer-service>
systemctl stop <openclaw-controller-service>
systemctl stop <openclaw-watcher-service>
```
只停止写入者,不停止生产业务服务。记录每条命令和退出码。
## 3. 安装统一运行身份 drop-in
对每个 GitOps/OpenClaw 写入服务安装:
```text
config/systemd/aios-gitops-runtime-identity.conf
```
目标:
```yaml
User: aiman
Group: gitops
SupplementaryGroups: gitops
UMask: 0002
```
执行:
```bash
systemctl daemon-reload
systemctl cat <service>
```
不得让服务继续以 root 写 workspace。
## 4. 初始化 bare repo 与独立 worktree 根目录
执行治理补丁中的脚本:
```bash
bash scripts/gitops/bootstrap_isolated_worktrees.sh
```
验收:
```yaml
bare_repo: /data/aios-gitops/repo.git
worktree_root: /data/aios-gitops/worktrees
owner: aiman
group: gitops
directory_mode: 2775
default_acl: inherited
```
## 5. 创建 controller 独立 worktree
以 `aiman`、`umask 0002` 执行:
```bash
sudo -u aiman -g gitops bash -lc '
umask 0002
cd /data/aios-gitops
scripts/gitops/task_worktree.sh create controller controller-runtime origin/main
'
```
将 controller/watcher 的工作目录改为:
```text
/data/aios-gitops/worktrees/controller/controller-runtime
```
## 6. 启用任务启动前自检
每个任务在执行前必须运行:
```bash
scripts/gitops/preflight_task_environment.sh
```
任何一项失败时不得开始任务:
- 用户不是 aiman;
- 不在 gitops 组;
- umask 不是 0002;
- 使用共享 `/data/aios-gitops/workspace`;
- worktree 不干净;
- task/result/git dir 不可写;
- 存在 Git lock。
## 7. 启动服务
```bash
systemctl start <gitops-writer-service>
systemctl start <openclaw-controller-service>
systemctl start <openclaw-watcher-service>
```
验证:
```bash
systemctl show <service> -p User -p Group -p UMask -p WorkingDirectory
ps -eo user,group,pid,cmd | grep -Ei 'openclaw|gitops|aios'
```
## 8. 并发验收
创建两个独立任务:
```text
OpenClaw: TASK-WORKTREE-CONCURRENCY-OPENCLAW-<timestamp>
ChatGPT: TASK-WORKTREE-CONCURRENCY-CHATGPT-<timestamp>
```
分别使用:
```text
/data/aios-gitops/worktrees/openclaw/<task-id>
/data/aios-gitops/worktrees/chatgpt/<task-id>
```
两个任务同时执行:
1. 写各自 `.agent/tasks/<agent>/`;
2. 写各自 `.agent/results/<agent>/`;
3. 创建深层子目录,验证默认 ACL;
4. commit;
5. push;
6. 不切换共享 workspace 分支。
验收必须全部通过:
```yaml
permission_denied: 0
untracked_overwrite_errors: 0
git_lock_collisions: 0
openclaw_commit_push: PASS
chatgpt_commit_push: PASS
deep_directory_acl_inheritance: PASS
shared_workspace_branch_switches: 0
```
## 9. 回滚
若迁移失败:
1. 停止新服务;
2. 保留失败 worktree 供审计;
3. 恢复 systemd drop-in 备份;
4. `daemon-reload`;
5. 恢复原服务状态;
6. 不删除 `/data/aios-gitops/workspace`;
7. 生产业务保持不变。
## 10. 结果文件
提交:
```text
.agent/results/openclaw/RESULT-GITOPS-ISOLATED-WORKTREE-MIGRATION-20260714T233742UTC8.md
```
首段必须包含:
```yaml
status: PASS | BLOCKED | ROLLED_BACK
task_id: TASK-GITOPS-ISOLATED-WORKTREE-MIGRATION-20260714T233742UTC8
created_at: 2026-07-14T23:37:42+08:00
timezone: Asia/Shanghai
user_action_required: false
runtime_identity:
user:
group:
umask:
bare_repo:
worktree_root:
controller_worktree:
services:
default_acl:
preflight:
concurrency_test:
openclaw_branch:
openclaw_commit:
chatgpt_branch:
chatgpt_commit:
permission_denied_count:
untracked_overwrite_count:
git_lock_collision_count:
owner_notifications:
received_message_id:
terminal_message_id:
rollback:
remaining_risks:
next_step:
```
提交并推送到独立执行分支。禁止直接推 main。
## 完成微信模板
PASS:
```text
【任务完成】GitOps独立worktree迁移已通过。所有写入服务统一为aiman:gitops、umask=0002;OpenClaw与ChatGPT并发commit/push无ACL或checkout冲突。生产业务版本未变化。
```
阻塞:
```text
【任务阻塞】GitOps独立worktree迁移未通过。原因=<具体服务/权限/并发验收>;已保留原workspace和回滚能力,生产业务未变化。
```
+58
View File
@@ -11,3 +11,61 @@ runtime/tmp/
runtime/cache/
logs/
config/test_write_perms
# BEGIN AIOS REGISTERED CHILD WORKTREES (V2R1C1 2026-07-21)
/A0-C1-WECHAT-BACKEND-LINEAGE-REMEDIATION-20260718/
/A0-CALLBACK-TRANSPORT-PENDING-RECOVERY-20260718/
/A0-CENTRAL-GPT-LIVE-CLOSURE-20260718/
/A0-CODEX-AUTOMATION-CLOSURE-INTEGRATION-20260718/
/A0-CODEX-AUTOMATION-CLOSURE-RESULT-20260718/
/A0-CODEX-LOCAL-CENTRAL-CHANNEL-20260718/
/A0-FINAL-AUTOMATION-INTEGRATION-20260718/
/A0-PENDING-PLAN-READONLY-20260718/
/A0-REMOTE-CODEX-BRAIN-192-168-88-6-20260719/
/A0-REMOTE-CODEX-HOME-IMRUYI-20260719/
/A0-WORKSPACE-TRIGGER-PROTOCOL-HARDENING-20260718/
/AIOS-V2R1-PRODUCTION-SUPERVISOR-20260720/
/RESULT-A0-CALLBACK-TRANSPORT-PENDING-RECOVERY-20260718/
/RESULT-A0-WORKSPACE-TRIGGER-PROTOCOL-HARDENING-20260718/
/RESULT-AIOS-SPARK-RUNNER-V2-OWNER-FIXES-20260717/
/RESULT-CODEX-AIOS-ORCHESTRATOR-GATEWAY-V1-BLOCKED-20260718/
/RESULT-CODEX-AIOS-SPARK-RUNNER-PROVISIONING-V2-20260717T174800UTC8/
/RESULT-CODEX-V2R1-PWX-B3-REPAIR3-GATE0-20260717T214100UTC8/
/TASK-CODEX-AIOS-ORCHESTRATOR-GATEWAY-V1-20260718T010100UTC8/
/TASK-CODEX-AIOS-SPARK-RUNNER-PROVISIONING-RESULT-20260717T040314Z/
/TASK-CODEX-AIOS-SPARK-RUNNER-PROVISIONING-V2-20260717T075800Z/
/TASK-CODEX-V2R1-PERSONAL-WEIXIN-FOUNDATION-RETRY1-20260715T183951UTC8/
/TASK-CODEX-V2R1-PWX-B3-REPAIR3-20260716/
/TASK-CODEX-V2R1-PWX-B3-REPAIR3-EXECUTION-BLOCKED-20260717T041314UTC8/
/TASK-CODEX-V2R1-PWX-B3-REPAIR3-GATE0-20260717T203000UTC8/
/v2r1-personal-weixin-b3-b4-owner-authorization-20260716T120210UTC8/
/v2r1-personal-weixin-b3-evidence-git-20260716T123454UTC8/
/v2r1-personal-weixin-b3-evidence-git-worktree-20260716T124948UTC8/
/v2r1-personal-weixin-b3-evidence-repair3-20260716T232732UTC8/
/v2r1-personal-weixin-b3-evidence-source-20260716/
/v2r1-personal-weixin-b3-evidence-source-result-20260716T140343UTC8/
/v2r1-personal-weixin-foundation-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry1-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry10-20260716T092623UTC8/
/v2r1-personal-weixin-foundation-retry10-result-20260716T092623UTC8/
/v2r1-personal-weixin-foundation-retry2-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry2-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry3-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry3-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry4-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry4-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry5-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry6-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry6-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry7-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry7-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry8-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry8-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry9-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry9-result-20260715T183951UTC8/
/v2r1-personal-weixin-foundation-retry9-resume-owner-patch-20260716T014714UTC8/
/v2r1-personal-weixin-foundation-takeover-20260715T183951UTC8/
/v2r1-personal-weixin-r10-b3-b4-evidence-gate-20260716T101002UTC8/
/v2r1-personal-weixin-r10-lineage-amendment-20260716T095245UTC8/
/v2r1-personal-weixin-upstream-protocol-evidence-20260716T105003UTC8/
# END AIOS REGISTERED CHILD WORKTREES (V2R1C1 2026-07-21)
@@ -0,0 +1,62 @@
# CODEX GitOps isolated worktree migration result
- Run: `20260715T001652UTC8`
- Host: `cn-network-mkt`
- Source rollback workspace: `/data/aios-gitops/workspace` (preserved; no reset, clean, force-push, or prune performed)
- Source head/branch: `b05eb1babe9c657e8776c09eec71302166902cc3` / `task/codex/gitops-isolated-worktree-migration-20260715T001652UTC8`
- Untracked snapshot: `/data/aios-gitops/artifacts/worktree-untracked-backups/migration-20260715T001652UTC8/workspace-untracked-51-files.tar.gz`
- Snapshot SHA256: `d5cf772d1badec5a9582e366ac4709d6aaa7613a2d091372d35787e7152d9b2a`
- Untracked files archived: `51`
## Isolated roots
| role | path | branch | HEAD |
|---|---|---|---|
| bare remote | `/data/aios-gitops/repo.git` | n/a | `b05eb1babe9c657e8776c09eec71302166902cc3` |
| controller | `/data/aios-gitops/worktrees/controller` | `agent/controller/gitops-isolated-worktree-migration-20260715T001652UTC8` | `b05eb1babe9c657e8776c09eec71302166902cc3` |
| openclaw | `/data/aios-gitops/worktrees/openclaw` | `agent/openclaw/gitops-isolated-worktree-migration-20260715T001652UTC8` | `6483e34892f56daa2abdd11f6a73fc4f99648841` |
| codex acceptance | `/data/aios-gitops/worktrees/codex` | `agent/codex/gitops-isolated-worktree-migration-20260715T001652UTC8` | `bcbda0d048dad164414c05740736d252652fc927` |
The bare root, worktree root, and controller/openclaw/codex worktree roots are `aiman:gitops`, mode `2775` for directories, with default ACL entries `user:aiman:rwx`, `group:gitops:rwx`, and mask `rwx`. Recursive inheritance was tested as `aiman`: a new file retains named ACL `rwx` with effective `rw-` due to its file mask. Bare `core.sharedRepository=group`.
## Cutover
Actual GitOps writers were drained before cutover. Systemd drop-ins route controller, autonomous daemon, agent command watcher, and active model API to `/data/aios-gitops/worktrees/controller`; OpenClaw receives `/data/aios-gitops/worktrees/openclaw` through safe environment overrides and remains stopped because it was inactive before this migration. All migrated writer units use `UMask=0002`; controller/daemon/watcher/model API use `aiman:gitops`, and root-run OpenClaw has primary group `gitops` to preserve its root-owned production home access.
Model API restart health response:
```json
{
"status": "ok",
"service": "chatgpt-gitops-adapter",
"workspace": "/data/aios-gitops/worktrees/controller"
}
```
Gitea and its branch-consistency sentinel were not modified. The sentinel still references the preserved rollback source and was already failed/inactive at preflight; this report therefore makes no claim that every non-writer reference on the host is source-free.
Scope note: normalizing the existing `/data/aios-gitops/worktrees` parent recursively applied the requested aiman:gitops ACL/group policy to pre-existing worktrees below that parent. No repository contents, source workspace refs, source worktree files, reset/clean, force-push, or prune were changed.
During final verification, ACL normalization was found to have removed Git-tracked executable bits in the three new worktrees only. The diffs were mode-only (no content delta), and every tracked file mode was restored from its Git index; all three worktrees then returned clean. The preserved source workspace was never touched.
## Concurrent acceptance
OpenClaw and Codex jobs ran concurrently on distinct branches/worktrees; each committed and pushed to the isolated bare remote without retry and without `GIT_OPTIONAL_LOCKS=0`.
| job | local OID | bare remote OID | verified |
|---|---|---|---|
| OpenClaw | `6483e34892f56daa2abdd11f6a73fc4f99648841` | `6483e34892f56daa2abdd11f6a73fc4f99648841` | yes |
| Codex acceptance | `bcbda0d048dad164414c05740736d252652fc927` | `bcbda0d048dad164414c05740736d252652fc927` | yes |
## Raw-log collision/error counts
| pattern | count |
|---|---:|
| permission denied | 3 |
| checkout collision | 0 |
| lock collision / index.lock | 0 |
The three `permission denied` matches are from the first malformed report generator attempting to execute Markdown-backticked paths; they are not Git/ACL/checkout permission failures. That report was replaced by a literal-format correction without rewriting history. Count scope is the two persisted orchestration logs plus the two acceptance logs; report-correction output is excluded to avoid self-counting the explanatory text.
Persisted raw logs: `/data/aios-gitops/logs/CODEX-GITOPS-ISOLATED-WORKTREE-MIGRATION-20260715T001652UTC8.raw.log`, `/data/aios-gitops/logs/CODEX-GITOPS-OpenClaw-ACCEPTANCE-20260715T001652UTC8.raw.log`, and `/data/aios-gitops/logs/CODEX-GITOPS-Codex-ACCEPTANCE-20260715T001652UTC8.raw.log`.
+59
View File
@@ -0,0 +1,59 @@
version: 1
policy_id: gitops-isolated-worktree-governance-20260714T232948UTC8
runtime_identity:
user: aiman
group: gitops
umask: "0002"
prohibit_root_workspace_writes: true
repository:
source_worktree: /data/aios-gitops/workspace
bare_repo: /data/aios-gitops/repo.git
worktree_root: /data/aios-gitops/worktrees
remote: origin
worktrees:
controller: /data/aios-gitops/worktrees/controller
task_pattern: /data/aios-gitops/worktrees/{agent}/{task_id}
allowed_agents:
- openclaw
- chatgpt
- controller
require_clean_start: true
remove_after_successful_push: true
retain_on_failure: true
permissions:
owner: aiman
group: gitops
directory_mode: "2775"
file_mode: "0664"
default_acl:
user:aiman: rwx
group:gitops: rwx
apply_to:
- /data/aios-gitops
- /data/aios-gitops/worktrees
preflight:
required_user: aiman
required_group: gitops
required_umask: "0002"
require_writable_git_dir: true
require_writable_task_dir: true
require_writable_result_dir: true
reject_shared_source_worktree: true
reject_existing_git_lock: true
notifications:
owner_on_received: required
owner_on_terminal: required
preferred_channel: weixin
redact_secrets: true
rollback:
preserve_source_worktree: true
remove_created_worktrees: true
restore_service_dropins: true
restore_service_state: true
@@ -0,0 +1,14 @@
# Install as a systemd drop-in for GitOps/OpenClaw writer services.
# Example: /etc/systemd/system/<service>.service.d/10-runtime-identity.conf
[Service]
User=aiman
Group=gitops
SupplementaryGroups=gitops
UMask=0002
Environment=AIOS_GITOPS_ROOT=/data/aios-gitops
Environment=AIOS_BARE_REPO=/data/aios-gitops/repo.git
Environment=AIOS_WORKTREE_ROOT=/data/aios-gitops/worktrees
Environment=AIOS_RUNTIME_USER=aiman
Environment=AIOS_RUNTIME_GROUP=gitops
Environment=AIOS_RUNTIME_UMASK=0002
@@ -0,0 +1,57 @@
# GitOps secret ACL and identity hardening
task_id=TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8
phase=precheck_complete
acl_owner_group=root:gitops
acl_mode=750
acl_named_aiman=rwx_effective_rx
acl_default_entries=absent
acl_negative_probe_scope=two_nonsecret_write_vectors
acl_negative_probe_result=expected_rejection_checksum_preserved
negative_probe_artifact=restricted_outside_repository
openclaw_gateway_identity=unchanged_root
openclaw_writer_unit=openclaw-git-writer@.service
openclaw_writer_identity=aiman:gitops
openclaw_writer_worktree=/data/aios-gitops/worktrees/openclaw
openclaw_writer_secret_environment=absent
acceptance=scheduled
prior_attempt_identity_guard=primary_group_mismatch
prior_attempt_git_operation_started=0
final_acceptance_task=TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8-FINAL
final_acceptance_concurrent_launch=scheduled
final_acceptance_codex_branch=acceptance/codex/TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8-FINAL
final_acceptance_codex_oid=7c4236305848dbb47c7134cafb3376fb713f8e03
final_acceptance_openclaw_branch=acceptance/openclaw/TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8-FINAL
final_acceptance_openclaw_oid=6cd0f5aa0ad28f767ffd5396c29d1a9182f88c43
final_bare_oid_match_codex=1
final_bare_oid_match_openclaw=1
openclaw_writer_systemd_result=success
openclaw_writer_proc_identity=Uid: 1000 1000 1000 1000;Gid: 1001 1001 1001 1001
openclaw_writer_proc_command=aiman gitops bash /usr/local/libexec/openclaw-git-writer TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8-FINAL
model_api_active=1
model_api_health_http_code=200
worktree_mode_codex=2775 aiman:gitops
worktree_mode_openclaw=2775 aiman:gitops
clean_log_sha256=cc7def630ab998fc2363c8cebe8c6e9d44769a6a418b4a0a18d2873806164c85
## Documentation gate supplement
negative_acl_probe_artifact_path=/data/aios-gitops/runtime/secrets/acl-negative-probe-TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8.log
negative_acl_probe_artifact_sha256=a4ca7dd2a9801d2254c019b99354882617290d2739281c204db1c1ef4a8c8039
negative_acl_probe_artifact_mode=600 root:root
negative_acl_probe_artifact_content=not_embedded
clean_final_log_path=/data/aios-gitops/runtime/verification/clean-TASK-CODEX-GITOPS-SECRET-ACL-AND-IDENTITY-HARDENING-20260715T004818UTC8.log
clean_final_log_sha256=cc7def630ab998fc2363c8cebe8c6e9d44769a6a418b4a0a18d2873806164c85
clean_final_log_scope=final_clean_corpus_only
permission_denied_count: 0
checkout_collision_count: 0
git_lock_collision_count: 0
codex_acceptance_commit_oid=7c4236305848dbb47c7134cafb3376fb713f8e03
codex_acceptance_commit_local_verified=1
codex_acceptance_commit_bare_verified=1
report_commit_tip_before_documentation_correction=c0d82846151d577b3d80a95d20a6917228457272
report_commit_tip_before_documentation_correction_local_bare_verified=1
openclaw_gateway_identity=root:gitops
openclaw_gateway_root_credentials_boundary=unchanged
model_api_health_endpoint=http://127.0.0.1:resolved-local-port/health
model_api_health_http_status=200
@@ -0,0 +1,9 @@
{
"id": "patch-1784043007770-e97206c3",
"patch_name": "gitops-isolated-worktree-governance-20260714T232948UTC8",
"branch": "patch/gitops-isolated-worktree-governance-20260714T232948UTC8",
"risk": "high",
"description": "Root-cause remediation for recurring ACL and shared-worktree failures: unified aiman:gitops runtime identity, UMask=0002, inherited default ACLs, per-task isolated Git worktrees, startup preflight, migration/rollback scripts, systemd drop-in templates, audit evidence, and an OpenClaw execution task. No production business deployment in this patch.",
"created_by": "chatgpt-gitops-bot",
"created_at": "2026-07-14T15:30:07Z"
}
@@ -0,0 +1,9 @@
{
"type": "branch",
"branch": "task/codex/gitops-isolated-worktree-migration-20260715T001652UTC8",
"base": "patch/gitops-isolated-worktree-governance-20260714T232948UTC8",
"created_by": "chatgpt-gitops-bot",
"created_at": "2026-07-14T16:17:28Z",
"direct_main_push": false,
"owner_approval_required": true
}
@@ -0,0 +1,5 @@
# Codex isolated-worktree acceptance
branch: `agent/codex/gitops-isolated-worktree-migration-20260715T001652UTC8`
base: `b05eb1babe9c657e8776c09eec71302166902cc3`
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="${AIOS_GITOPS_ROOT:-/data/aios-gitops}"
SOURCE="${AIOS_SOURCE_WORKTREE:-$ROOT/workspace}"
BARE="${AIOS_BARE_REPO:-$ROOT/repo.git}"
WORKTREES="${AIOS_WORKTREE_ROOT:-$ROOT/worktrees}"
RUNTIME_USER="${AIOS_RUNTIME_USER:-aiman}"
RUNTIME_GROUP="${AIOS_RUNTIME_GROUP:-gitops}"
if [[ "$(id -u)" -ne 0 ]]; then
echo "ERROR: bootstrap must run as root" >&2
exit 2
fi
getent passwd "$RUNTIME_USER" >/dev/null
getent group "$RUNTIME_GROUP" >/dev/null
[[ -d "$SOURCE/.git" || -f "$SOURCE/.git" ]] || {
echo "ERROR: source worktree not found: $SOURCE" >&2
exit 3
}
install -d -o "$RUNTIME_USER" -g "$RUNTIME_GROUP" -m 2775 "$ROOT" "$WORKTREES"
install -d -o "$RUNTIME_USER" -g "$RUNTIME_GROUP" -m 2775 \
"$WORKTREES/openclaw" "$WORKTREES/chatgpt" "$WORKTREES/controller"
if [[ ! -d "$BARE" ]]; then
sudo -u "$RUNTIME_USER" -g "$RUNTIME_GROUP" git clone --bare "$SOURCE" "$BARE"
fi
chown -R "$RUNTIME_USER:$RUNTIME_GROUP" "$BARE" "$WORKTREES"
find "$BARE" "$WORKTREES" -type d -exec chmod 2775 {} +
find "$BARE" "$WORKTREES" -type f -exec chmod ug+rw {} +
setfacl -R -m "u:${RUNTIME_USER}:rwX,g:${RUNTIME_GROUP}:rwX,m::rwX" "$BARE" "$WORKTREES"
find "$BARE" "$WORKTREES" -type d -exec \
setfacl -m "d:u:${RUNTIME_USER}:rwx,d:g:${RUNTIME_GROUP}:rwx,d:m::rwx" {} +
cat <<EOF
bootstrap_status: PASS
root: $ROOT
source_worktree: $SOURCE
bare_repo: $BARE
worktree_root: $WORKTREES
runtime_user: $RUNTIME_USER
runtime_group: $RUNTIME_GROUP
EOF
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
EXPECTED_USER="${AIOS_RUNTIME_USER:-aiman}"
EXPECTED_GROUP="${AIOS_RUNTIME_GROUP:-gitops}"
EXPECTED_UMASK="${AIOS_RUNTIME_UMASK:-0002}"
TASK_DIR="${AIOS_TASK_DIR:-.agent/tasks}"
RESULT_DIR="${AIOS_RESULT_DIR:-.agent/results}"
fail() {
echo "preflight_status: FAIL"
echo "reason: $1"
exit 1
}
USER_NOW="$(id -un)"
GROUPS_NOW="$(id -Gn)"
UMASK_NOW="$(umask)"
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
GIT_DIR="$(git rev-parse --git-dir 2>/dev/null || true)"
BRANCH="$(git branch --show-current 2>/dev/null || true)"
[[ "$USER_NOW" == "$EXPECTED_USER" ]] || fail "runtime user is $USER_NOW, expected $EXPECTED_USER"
[[ " $GROUPS_NOW " == *" $EXPECTED_GROUP "* ]] || fail "runtime user is not in $EXPECTED_GROUP"
[[ "$UMASK_NOW" == "$EXPECTED_UMASK" || "$UMASK_NOW" == "002" ]] || fail "umask is $UMASK_NOW, expected $EXPECTED_UMASK"
[[ -n "$ROOT" ]] || fail "not inside a git worktree"
[[ "$ROOT" == /data/aios-gitops/worktrees/* ]] || fail "shared source worktree is prohibited: $ROOT"
[[ -w "$ROOT" ]] || fail "worktree root is not writable"
[[ -w "$GIT_DIR" ]] || fail "git dir is not writable: $GIT_DIR"
[[ ! -e "$GIT_DIR/index.lock" ]] || fail "git index lock exists"
install -d -m 2775 "$TASK_DIR" "$RESULT_DIR"
[[ -w "$TASK_DIR" ]] || fail "task directory is not writable: $TASK_DIR"
[[ -w "$RESULT_DIR" ]] || fail "result directory is not writable: $RESULT_DIR"
[[ -z "$(git status --porcelain)" ]] || fail "worktree is not clean at task start"
cat <<EOF
preflight_status: PASS
runtime_user: $USER_NOW
runtime_groups: $GROUPS_NOW
umask: $UMASK_NOW
worktree: $ROOT
git_dir: $GIT_DIR
branch: $BRANCH
workspace_clean: true
task_path_writable: true
result_path_writable: true
git_lock_present: false
EOF
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail
ACTION="${1:-}"
AGENT="${2:-}"
TASK_ID="${3:-}"
BASE_REF="${4:-origin/main}"
ROOT="${AIOS_GITOPS_ROOT:-/data/aios-gitops}"
BARE="${AIOS_BARE_REPO:-$ROOT/repo.git}"
WORKTREES="${AIOS_WORKTREE_ROOT:-$ROOT/worktrees}"
RUNTIME_USER="${AIOS_RUNTIME_USER:-aiman}"
RUNTIME_GROUP="${AIOS_RUNTIME_GROUP:-gitops}"
usage() {
echo "usage: $0 create|remove <openclaw|chatgpt|controller> <task-id> [base-ref]" >&2
exit 64
}
[[ "$ACTION" =~ ^(create|remove)$ ]] || usage
[[ "$AGENT" =~ ^(openclaw|chatgpt|controller)$ ]] || usage
[[ "$TASK_ID" =~ ^[A-Za-z0-9._-]+$ ]] || {
echo "ERROR: invalid task id" >&2
exit 65
}
[[ "$(id -un)" == "$RUNTIME_USER" ]] || {
echo "ERROR: must run as $RUNTIME_USER" >&2
exit 66
}
[[ "$(id -gn)" == "$RUNTIME_GROUP" || " $(id -Gn) " == *" $RUNTIME_GROUP "* ]] || {
echo "ERROR: user must be in $RUNTIME_GROUP" >&2
exit 67
}
[[ "$(umask)" == "0002" || "$(umask)" == "002" ]] || {
echo "ERROR: umask must be 0002" >&2
exit 68
}
[[ -d "$BARE" ]] || {
echo "ERROR: bare repository missing: $BARE" >&2
exit 69
}
PATHNAME="$WORKTREES/$AGENT/$TASK_ID"
BRANCH="task/$AGENT/$TASK_ID"
case "$ACTION" in
create)
[[ ! -e "$PATHNAME" ]] || {
echo "ERROR: worktree already exists: $PATHNAME" >&2
exit 70
}
git --git-dir="$BARE" fetch --all --prune
git --git-dir="$BARE" worktree add -b "$BRANCH" "$PATHNAME" "$BASE_REF"
install -d -m 2775 "$PATHNAME/.agent/tasks/$AGENT" "$PATHNAME/.agent/results/$AGENT"
setfacl -m "u:${RUNTIME_USER}:rwx,g:${RUNTIME_GROUP}:rwx,m::rwx" "$PATHNAME"
find "$PATHNAME" -type d -exec chmod g+s {} +
find "$PATHNAME" -type d -exec \
setfacl -m "d:u:${RUNTIME_USER}:rwx,d:g:${RUNTIME_GROUP}:rwx,d:m::rwx" {} +
printf 'worktree: %s\nbranch: %s\nbase: %s\n' "$PATHNAME" "$BRANCH" "$BASE_REF"
;;
remove)
[[ -d "$PATHNAME" ]] || {
echo "ERROR: worktree not found: $PATHNAME" >&2
exit 71
}
[[ -z "$(git -C "$PATHNAME" status --porcelain)" ]] || {
echo "ERROR: worktree is not clean; retain for investigation" >&2
exit 72
}
git --git-dir="$BARE" worktree remove "$PATHNAME"
printf 'removed: %s\n' "$PATHNAME"
;;
esac