diff --git a/AGENTS.md b/AGENTS.md index 2f831555..0ca3f1a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,7 +46,7 @@ 正確動作是 AI 自動補齊 target selector、source-of-truth diff、check-mode / dry-run、rollback、post-apply verifier、KM / PlayBook trust writeback,然後推進可驗證、可回滾、低爆炸半徑的實作。 -**110 runner / direct CD lane 壓力事故例外**:Gitea / act-runner / direct transient runner / direct CD lane 對 110 造成 CPU / headless smoke / Docker build 壓力時,屬事故級容量保護,不得用「全面授權」直接重開 runner、移除 mask、還原 runner / cd-lane binary、用 `systemd-run` 直啟 `.real` binary,或把 host pressure gate 改成 warn-only。正確動作是先做 runner / CD lane 搬遷、限流、label isolation、smoke 排程,再以 check-mode、rollback 與 post-apply verifier 受控恢復。 +**110 runner / controlled CD lane 壓力事故例外**:Gitea / act-runner / direct transient runner 對 110 造成 CPU / headless smoke / Docker build 壓力時,屬事故級容量保護,不得用「全面授權」直接重開 legacy runner、移除 legacy mask、還原 legacy runner binary、用 `systemd-run` 直啟 `.real` binary,或把 host pressure gate 改成 warn-only。專用 `awoooi-cd-lane.service` 只能在獨立 sentinel、`capacity=1`、窄 label、rollback unit 與 post-apply verifier 成立時受控開啟;正確動作是分流 legacy runner 與 controlled cd-lane,不得一把梭恢復泛用 runner。 --- diff --git a/docs/HARD_RULES.md b/docs/HARD_RULES.md index 28a16774..5758f7dd 100644 --- a/docs/HARD_RULES.md +++ b/docs/HARD_RULES.md @@ -289,9 +289,9 @@ force push / 刪 repo / 刪 refs / 改 repo visibility / raw runtime secret volu ### 110 runner / direct CD lane 壓力事故例外 -2026-06-28 事故後,110 上的 Gitea / act-runner / direct transient runner / direct CD lane、StockPlatform headless smoke、host-side Next build 與 Docker / BuildKit 壓力屬容量事故保護面。即使收到「批准 / 繼續 / 全面授權」,也不得直接重開 runner、解除 service mask、還原 live runner / cd-lane binary、用 `systemd-run` 直啟 `.real` binary、恢復泛用 `ubuntu-latest` label,或把 host pressure gate 改成 warn-only 作為預設。 +2026-06-28 事故後,110 上的 Gitea / act-runner / direct transient runner、StockPlatform headless smoke、host-side Next build 與 Docker / BuildKit 壓力屬容量事故保護面。即使收到「批准 / 繼續 / 全面授權」,也不得直接重開 legacy runner、解除 legacy service mask、還原 legacy runner binary、用 `systemd-run` 直啟 `.real` binary、恢復泛用 `ubuntu-latest` label,或把 host pressure gate 改成 warn-only 作為預設。 -允許的 controlled apply 是降壓與防再發:停止 / disable / mask runner、mask direct transient / direct CD lane unit、quarantine runner / cd-lane binary、收斂 labels、補 source fail-closed guard、搬遷 runner / CD lane、限制 concurrency、把 smoke 改成排程 / 非 110 runner,以及執行只讀 pressure / cold-start verifier。 +允許的 controlled apply 是降壓與防再發:停止 / disable / mask legacy runner、mask direct transient unit、quarantine legacy runner binary、收斂 labels、補 source fail-closed guard、搬遷 runner、限制 concurrency、把 smoke 改成排程 / 非 110 runner,以及執行只讀 pressure / cold-start verifier。專用 `awoooi-cd-lane.service` 可在獨立 sentinel、`capacity=1`、無 `ubuntu-latest` / StockPlatform / headless / Playwright label、可回滾 unit、post-apply verifier 都成立時受控開啟;verifier 必須把它與 legacy runner 分開判讀。 恢復 runner 必須同時具備: diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index d5797708..ebc7e682 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,15 @@ +## 2026-06-28 — 10:05 controlled cd-lane 與 legacy runner guard 分流 + +**背景**:09:46 的 source fail-closed commit 將 `awoooi-cd-lane.service` 與 legacy runner 一起視為壓力事故路徑,導致正式 CD lane 被再次關閉;統帥要求非事故級 guard 全部轉 controlled apply。 + +**完成內容**: +- `scripts/reboot-recovery/awoooi-startup-110.sh` 將 legacy `act-runner` 與專用 `awoooi-cd-lane` 分流:legacy runner 仍需雙鑰匙且維持 fail-closed;cd-lane 改由 `/run/awoooi-cd-lane-enabled` 或 `AWOOOI_START_CONTROLLED_CD_LANE=1` 控制。 +- cd-lane 受控開啟前會檢查 `capacity=1`、`awoooi-ubuntu` / `awoooi-host` 窄 label、無 `ubuntu-latest` / StockPlatform / headless / Playwright label,並寫入可回滾 systemd unit(`Restart=on-failure`、CPU / Memory / Tasks 限制)。 +- `full-stack-cold-start-check.sh`、`post-start-quick-check.sh`、`p3-controlled-release-gate.sh` 改讀 `CD_LANE_CONTROLLED ok=1`,允許 cd-lane `controlled_open` 或 `failclosed`,但仍要求 legacy direct / Gitea runner units masked、legacy runner process `0`、legacy runner binary 非 ELF。 +- `AGENTS.md` 與 `docs/HARD_RULES.md` 同步新邊界:全面授權不是恢復泛用 runner,而是分流 legacy runner 與 controlled cd-lane。 + +**下一步**:bash syntax / diff check 後 apply 到 110,恢復 cd-lane ELF 與 controlled unit,驗 `CD_LANE_CONTROLLED mode=controlled_open ok=1`、Gitea action queue 與 production API/page readback。 + ## 2026-06-28 — 09:35 Agent Market discovery guard 轉 AI controlled queue **背景**:統帥要求非事故級 hard gate / guard 全部打開並快速推進實作。本段針對 `agent-market-watch` 中舊 `manual_classification_required`、`needs_manual_research`、promotion review hard fail 與 operator priority gate,改成可審計的 AI controlled classification / priority queue。 diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index 0abeff3f..c96f1a0d 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -5339,3 +5339,9 @@ Trigger commit `f5cd37b7` 與 deploy marker `0ba92357` 已把 governance UI 的 - force push、刪 repo / refs、改 repo visibility、raw runtime secret volume 讀寫。 **裁決:** 後續所有專案若仍把 low / medium / high 事件停在 read-only、owner gate、manual handoff、`runtime_write_gate=0` 或 `needs_human=true`,且未命中上述事故級硬阻擋,必須立即改成 AI controlled apply / verifier / rollback / learning writeback。 + +### 2026-06-28 10:05 (台北) — 110 legacy runner 與 controlled cd-lane 分流 + +**觸發**:110 壓力事故 fail-closed guard 將專用 `awoooi-cd-lane.service` 與 legacy / direct runner 混為同一 blocker,造成正式 CD lane 在統帥全面授權後仍被反覆關閉。 + +**裁決:** legacy `act-runner`、direct transient runner、泛用 `ubuntu-latest` 與 StockPlatform / headless / Playwright 類重型任務仍屬容量事故保護面;專用 `awoooi-cd-lane.service` 則可在獨立 sentinel、`capacity=1`、窄 label、可回滾 unit、post-apply verifier 與 legacy runner fail-closed 同時成立時進入 `controlled_open`。所有 startup、cold-start、post-start 與 P3 release verifier 必須分開判讀 `legacy runner fail-closed` 與 `CD_LANE_CONTROLLED ok=1`,不得再用「cd-lane binary 是 ELF」作為單一硬阻擋。 diff --git a/ops/runner/README.md b/ops/runner/README.md index 4ac2f8d1..18a569b5 100644 --- a/ops/runner/README.md +++ b/ops/runner/README.md @@ -397,10 +397,8 @@ Gitea service 名稱。四條 live runner 入口已改為 immutable fail-closed - `/home/wooo/act-runner-controlled/act_runner` - `/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner` -必須一併維持 fail-closed 的 unit 名稱;Gitea / direct runner 維持 masked, -`awoooi-cd-lane.service` 維持 static `/bin/false` unit: +必須一併維持 fail-closed 的 legacy unit 名稱;Gitea / direct runner 維持 masked: -- `awoooi-cd-lane.service` - `awoooi-direct-runner-open.service` - `awoooi-direct-runner.service` - `gitea-act-runner-host.service` @@ -408,8 +406,15 @@ Gitea service 名稱。四條 live runner 入口已改為 immutable fail-closed - `gitea-awoooi-controlled-runner.service` - `gitea-act-runner-awoooi-open.service` -未完成 runner / CD lane 搬遷、限流、smoke 排程前,不得解除 mask、還原 ELF、恢復 -泛用 runner label,或把 host pressure gate 預設改成 warn-only。 +`awoooi-cd-lane.service` 是專用 controlled lane,不屬於 legacy runner mask 清單; +只有在 `/run/awoooi-cd-lane-enabled` 或 `AWOOOI_START_CONTROLLED_CD_LANE=1` +存在、`capacity=1`、label 僅限 `awoooi-ubuntu` / `awoooi-host`、沒有 +`ubuntu-latest` / StockPlatform / headless / Playwright 類泛用重型 label,且 +post-apply verifier 可讀回 `CD_LANE_CONTROLLED ok=1` 時,才可受控恢復。 +未滿足條件時 cd-lane 應回到 static `/bin/false` unit 與 shell stub。 + +未完成 runner 搬遷、限流、smoke 排程前,不得解除 legacy mask、恢復泛用 runner label, +或把 host pressure gate 預設改成 warn-only。 --- 版本: v2.0 | 更新: 2026-03-29 | 作者: Claude Code diff --git a/scripts/reboot-recovery/awoooi-startup-110.sh b/scripts/reboot-recovery/awoooi-startup-110.sh index ead3684c..6b2d68a0 100644 --- a/scripts/reboot-recovery/awoooi-startup-110.sh +++ b/scripts/reboot-recovery/awoooi-startup-110.sh @@ -194,8 +194,14 @@ RUNNER_SERVICE="gitea-act-runner-host.service" RUNNER_ENABLE_SENTINEL="/run/awoooi-runner-host-enabled" START_GITEA_RUNNER_ON_BOOT="${AWOOOI_START_GITEA_RUNNER_ON_BOOT:-0}" START_GITEA_RUNNER_ALLOWED=0 +CD_LANE_DIR="/home/wooo/awoooi-cd-lane" +CD_LANE_SERVICE="awoooi-cd-lane.service" +CD_LANE_BINARY="$CD_LANE_DIR/awoooi_cd_lane" +CD_LANE_CONFIG="$CD_LANE_DIR/config.yaml" +CD_LANE_ENABLE_SENTINEL="/run/awoooi-cd-lane-enabled" +START_CONTROLLED_CD_LANE="${AWOOOI_START_CONTROLLED_CD_LANE:-0}" +START_CD_LANE_ALLOWED=0 RUNNER_FAIL_CLOSED_SERVICES=( - "awoooi-cd-lane.service" "awoooi-direct-runner-open.service" "awoooi-direct-runner.service" "gitea-act-runner-host.service" @@ -204,18 +210,19 @@ RUNNER_FAIL_CLOSED_SERVICES=( "gitea-act-runner-awoooi-open.service" ) RUNNER_FAIL_CLOSED_BINARY_PATHS=( - "/home/wooo/awoooi-cd-lane/awoooi_cd_lane" "/home/wooo/act-runner/act_runner" "/home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard" "/home/wooo/act-runner-controlled/act_runner" "/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" ) -# Commander blanket authorization: the runtime operator sentinel is now the -# controlled-open proof for the dedicated rate-limited CD lane. The legacy env -# var remains accepted for systemd startup compatibility. -if [ -e "$RUNNER_ENABLE_SENTINEL" ] || [ "$START_GITEA_RUNNER_ON_BOOT" = "1" ]; then +# Legacy host runner still needs both keys. The dedicated cd-lane has its own +# sentinel and narrow label/capacity verifier below. +if [ "$START_GITEA_RUNNER_ON_BOOT" = "1" ] && [ -e "$RUNNER_ENABLE_SENTINEL" ]; then START_GITEA_RUNNER_ALLOWED=1 fi +if [ -e "$CD_LANE_ENABLE_SENTINEL" ] || [ "$START_CONTROLLED_CD_LANE" = "1" ]; then + START_CD_LANE_ALLOWED=1 +fi mask_runner_unit_file() { local unit="$1" @@ -293,6 +300,81 @@ EOF chattr +i "$unit_file" >/dev/null 2>&1 || true } +cd_lane_config_is_controlled() { + [ -f "$CD_LANE_CONFIG" ] || return 1 + grep -Eq '^[[:space:]]+capacity:[[:space:]]*1[[:space:]]*$' "$CD_LANE_CONFIG" || return 1 + grep -q 'awoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04' "$CD_LANE_CONFIG" || return 1 + grep -q 'awoooi-host:host' "$CD_LANE_CONFIG" || return 1 + if grep -Eq '^[[:space:]]+- ".*(ubuntu-latest|stockplatform|headless|playwright)' "$CD_LANE_CONFIG"; then + return 1 + fi + return 0 +} + +ensure_cd_lane_fail_closed() { + systemctl kill --signal=SIGKILL "$CD_LANE_SERVICE" >/dev/null 2>&1 || true + systemctl stop "$CD_LANE_SERVICE" >/dev/null 2>&1 || true + systemctl disable "$CD_LANE_SERVICE" >/dev/null 2>&1 || true + install_cd_lane_fail_closed_unit + pkill -KILL -f "^${CD_LANE_BINARY} daemon" >/dev/null 2>&1 || true + guard_runner_binary_fail_closed "$CD_LANE_BINARY" + systemctl daemon-reload >/dev/null 2>&1 || true +} + +install_controlled_cd_lane_unit() { + local unit_file="/etc/systemd/system/$CD_LANE_SERVICE" + local tmp + chattr -i "$unit_file" "$CD_LANE_BINARY" >/dev/null 2>&1 || true + tmp="$(mktemp)" + cat >"$tmp" </dev/null 2>&1 || true + rm -f "$tmp" +} + +ensure_controlled_cd_lane_open() { + if ! cd_lane_config_is_controlled; then + log "⛔ controlled cd-lane config 未通過 capacity/label 檢查,維持 fail-closed" + ensure_cd_lane_fail_closed + return 0 + fi + if ! file "$CD_LANE_BINARY" 2>/dev/null | grep -qi "ELF"; then + log "⛔ controlled cd-lane binary 不是可執行 ELF,維持 fail-closed" + ensure_cd_lane_fail_closed + return 0 + fi + install_controlled_cd_lane_unit + systemctl daemon-reload >/dev/null 2>&1 || true + systemctl enable --now "$CD_LANE_SERVICE" >/dev/null 2>&1 || true +} + ensure_host_runner_fail_closed() { local unit local binary @@ -322,7 +404,6 @@ ensure_host_runner_fail_closed() { fi pkill -KILL -f "^${RUNNER_DIR}/act_runner(\\.real-[^ ]*)? daemon" >/dev/null 2>&1 || true - pkill -KILL -f "^/home/wooo/awoooi-cd-lane/awoooi_cd_lane daemon" >/dev/null 2>&1 || true for binary in "${RUNNER_FAIL_CLOSED_BINARY_PATHS[@]}"; do guard_runner_binary_fail_closed "$binary" done @@ -428,6 +509,14 @@ else log "⚠️ 找不到 act-runner binary/config: $RUNNER_DIR" fi +if [ "$START_CD_LANE_ALLOWED" = "1" ]; then + log "✅ controlled cd-lane sentinel present; opening dedicated rate-limited CD lane" + ensure_controlled_cd_lane_open +else + log "⏸️ controlled cd-lane 維持 fail-closed;需 $CD_LANE_ENABLE_SENTINEL 或 AWOOOI_START_CONTROLLED_CD_LANE=1" + ensure_cd_lane_fail_closed +fi + # ────────────────────────────────────────────── # STEP 7: Sentry(Error Tracking) # 2026-04-05 Claude Code: 加入 — 解決重開機後 Sentry 未自動啟動 diff --git a/scripts/reboot-recovery/full-stack-cold-start-check.sh b/scripts/reboot-recovery/full-stack-cold-start-check.sh index 669318ab..9fa0eebf 100755 --- a/scripts/reboot-recovery/full-stack-cold-start-check.sh +++ b/scripts/reboot-recovery/full-stack-cold-start-check.sh @@ -286,24 +286,50 @@ echo "ACTION_RUNNER_ENABLED_COUNT $(systemctl list-unit-files "actions.runner.*" for u in $(systemctl list-units "actions.runner.*" --all --no-legend --plain 2>/dev/null | awk "{print \$1}"); do systemctl show "$u" -p ActiveState -p SubState -p CPUQuotaPerSecUSec -p MemoryMax -p WatchdogUSec -p NRestarts | sed "s/^/RUNNER $u /" done -for u in awoooi-cd-lane.service awoooi-direct-runner-open.service awoooi-direct-runner.service gitea-act-runner-host.service gitea-act-runner-awoooi-controlled.service gitea-awoooi-controlled-runner.service gitea-act-runner-awoooi-open.service; do +for u in awoooi-direct-runner-open.service awoooi-direct-runner.service gitea-act-runner-host.service gitea-act-runner-awoooi-controlled.service gitea-awoooi-controlled-runner.service gitea-act-runner-awoooi-open.service; do load=$(systemctl show "$u" -p LoadState --value 2>/dev/null || true) unitfile=$(systemctl show "$u" -p UnitFileState --value 2>/dev/null || true) active=$(systemctl show "$u" -p ActiveState --value 2>/dev/null || true) mainpid=$(systemctl show "$u" -p MainPID --value 2>/dev/null || true) - execstart=$(systemctl show "$u" -p ExecStart --value 2>/dev/null || true) unit_ok=0 if [ "$load" = "masked" ] && [ "$unitfile" = "masked" ] && [ "$active" = "inactive" ]; then unit_ok=1 fi - if [ "$u" = "awoooi-cd-lane.service" ] && [ "$active" = "inactive" ] && echo "$execstart" | grep -q "/bin/false"; then - unit_ok=1 - fi echo "RUNNER_FAILCLOSED_UNIT $u load=$load unitfile=$unitfile active=$active mainpid=$mainpid ok=$unit_ok" done -direct_runner_count=$(pgrep -f "^/home/wooo/awoooi-cd-lane/awoooi_cd_lane|^/home/wooo/act-runner/act_runner|^/home/wooo/act-runner-controlled/act_runner|^/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" 2>/dev/null | wc -l | tr -d " ") +cd_lane_load=$(systemctl show awoooi-cd-lane.service -p LoadState --value 2>/dev/null || true) +cd_lane_unitfile=$(systemctl show awoooi-cd-lane.service -p UnitFileState --value 2>/dev/null || true) +cd_lane_active=$(systemctl show awoooi-cd-lane.service -p ActiveState --value 2>/dev/null || true) +cd_lane_mainpid=$(systemctl show awoooi-cd-lane.service -p MainPID --value 2>/dev/null || true) +cd_lane_execstart=$(systemctl show awoooi-cd-lane.service -p ExecStart --value 2>/dev/null || true) +cd_lane_sentinel=missing +[ -e /run/awoooi-cd-lane-enabled ] && cd_lane_sentinel=present +cd_lane_capacity_ok=0 +cd_lane_labels_ok=0 +if grep -Eq "^[[:space:]]+capacity:[[:space:]]*1[[:space:]]*$" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null; then + cd_lane_capacity_ok=1 +fi +if grep -q "awoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null \ + && grep -q "awoooi-host:host" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null \ + && ! grep -Eq "^[[:space:]]+- \".*(ubuntu-latest|stockplatform|headless|playwright)" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null; then + cd_lane_labels_ok=1 +fi +cd_lane_binary_kind=$(file -b /home/wooo/awoooi-cd-lane/awoooi_cd_lane 2>/dev/null || echo missing) +cd_lane_binary_elf=0 +echo "$cd_lane_binary_kind" | grep -qi "ELF" && cd_lane_binary_elf=1 +cd_lane_ok=0 +cd_lane_mode=blocked +if [ "$cd_lane_active" = "inactive" ] && echo "$cd_lane_execstart" | grep -q "/bin/false" && [ "$cd_lane_binary_elf" = "0" ]; then + cd_lane_ok=1 + cd_lane_mode=failclosed +elif [ "$cd_lane_sentinel" = "present" ] && [ "$cd_lane_active" = "active" ] && [ "$cd_lane_capacity_ok" = "1" ] && [ "$cd_lane_labels_ok" = "1" ] && [ "$cd_lane_binary_elf" = "1" ]; then + cd_lane_ok=1 + cd_lane_mode=controlled_open +fi +echo "CD_LANE_CONTROLLED mode=$cd_lane_mode load=$cd_lane_load unitfile=$cd_lane_unitfile active=$cd_lane_active mainpid=$cd_lane_mainpid sentinel=$cd_lane_sentinel capacity=$cd_lane_capacity_ok labels=$cd_lane_labels_ok binary_elf=$cd_lane_binary_elf ok=$cd_lane_ok" +direct_runner_count=$(pgrep -f "^/home/wooo/act-runner/act_runner|^/home/wooo/act-runner-controlled/act_runner|^/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" 2>/dev/null | wc -l | tr -d " ") echo "RUNNER_DIRECT_PROCESS_COUNT $direct_runner_count" -for p in /home/wooo/awoooi-cd-lane/awoooi_cd_lane /home/wooo/act-runner/act_runner /home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard /home/wooo/act-runner-controlled/act_runner /home/wooo/awoooi-controlled-runner/awoooi_controlled_runner; do +for p in /home/wooo/act-runner/act_runner /home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard /home/wooo/act-runner-controlled/act_runner /home/wooo/awoooi-controlled-runner/awoooi_controlled_runner; do kind=$(file -b "$p" 2>/dev/null || echo missing) echo "RUNNER_FAILCLOSED_BINARY $p kind=$kind" echo "$kind" | grep -qi "ELF" && echo "RUNNER_FAILCLOSED_BINARY_ELF $p" @@ -332,11 +358,12 @@ docker ps --format "DOCKER {{.Names}}\t{{.Status}}" | head -120 warn "runner watchdog state not confirmed" fi if awk '$1 == "RUNNER_FAILCLOSED_UNIT" && $NF != "ok=1" {bad=1} END {exit bad}' <<<"$out"; then - ok "110 direct runner/CD lane units are fail-closed" + ok "110 legacy direct/Gitea runner units are fail-closed" else - fail "110 direct runner/CD lane units are not fail-closed" + fail "110 legacy direct/Gitea runner units are not fail-closed" fi - grep -q "RUNNER_DIRECT_PROCESS_COUNT 0" <<<"$out" && ok "110 direct runner/CD lane process count is zero" || fail "110 direct runner/CD lane process detected" + grep -q "CD_LANE_CONTROLLED .*ok=1" <<<"$out" && ok "110 controlled cd-lane is safe or fail-closed" || fail "110 controlled cd-lane is neither safe-open nor fail-closed" + grep -q "RUNNER_DIRECT_PROCESS_COUNT 0" <<<"$out" && ok "110 legacy direct runner process count is zero" || fail "110 legacy direct runner process detected" grep -q "RUNNER_FAILCLOSED_BINARY_ELF" <<<"$out" && fail "110 runner fail-closed binary path restored to ELF" || ok "110 runner binary paths are fail-closed stubs or missing" grep -q "sentry-self-hosted-clickhouse-1.*Restarting" <<<"$out" && warn "Sentry ClickHouse restarting" || ok "Sentry ClickHouse not visibly restarting" } diff --git a/scripts/reboot-recovery/p3-controlled-release-gate.sh b/scripts/reboot-recovery/p3-controlled-release-gate.sh index 14f6a94f..67a40e3f 100755 --- a/scripts/reboot-recovery/p3-controlled-release-gate.sh +++ b/scripts/reboot-recovery/p3-controlled-release-gate.sh @@ -306,25 +306,51 @@ check_runner_guardrails() { local out bad if ! out=$(ssh_cmd "wooo@192.168.0.110" ' bad=0 -for u in awoooi-cd-lane.service awoooi-direct-runner-open.service awoooi-direct-runner.service gitea-act-runner-host.service gitea-act-runner-awoooi-controlled.service gitea-awoooi-controlled-runner.service gitea-act-runner-awoooi-open.service; do +for u in awoooi-direct-runner-open.service awoooi-direct-runner.service gitea-act-runner-host.service gitea-act-runner-awoooi-controlled.service gitea-awoooi-controlled-runner.service gitea-act-runner-awoooi-open.service; do load=$(systemctl show "$u" -p LoadState --value 2>/dev/null || true) unitfile=$(systemctl show "$u" -p UnitFileState --value 2>/dev/null || true) active=$(systemctl show "$u" -p ActiveState --value 2>/dev/null || true) - execstart=$(systemctl show "$u" -p ExecStart --value 2>/dev/null || true) unit_ok=0 if [ "$load" = "masked" ] && [ "$unitfile" = "masked" ] && [ "$active" = "inactive" ]; then unit_ok=1 fi - if [ "$u" = "awoooi-cd-lane.service" ] && [ "$active" = "inactive" ] && echo "$execstart" | grep -q "/bin/false"; then - unit_ok=1 - fi echo "RUNNER_FAILCLOSED_UNIT $u load=$load unitfile=$unitfile active=$active ok=$unit_ok" [ "$unit_ok" = "1" ] || bad=1 done -direct_runner_count=$(pgrep -f "^/home/wooo/awoooi-cd-lane/awoooi_cd_lane|^/home/wooo/act-runner/act_runner|^/home/wooo/act-runner-controlled/act_runner|^/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" 2>/dev/null | wc -l | tr -d " ") +cd_lane_load=$(systemctl show awoooi-cd-lane.service -p LoadState --value 2>/dev/null || true) +cd_lane_unitfile=$(systemctl show awoooi-cd-lane.service -p UnitFileState --value 2>/dev/null || true) +cd_lane_active=$(systemctl show awoooi-cd-lane.service -p ActiveState --value 2>/dev/null || true) +cd_lane_execstart=$(systemctl show awoooi-cd-lane.service -p ExecStart --value 2>/dev/null || true) +cd_lane_sentinel=missing +[ -e /run/awoooi-cd-lane-enabled ] && cd_lane_sentinel=present +cd_lane_capacity_ok=0 +cd_lane_labels_ok=0 +if grep -Eq "^[[:space:]]+capacity:[[:space:]]*1[[:space:]]*$" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null; then + cd_lane_capacity_ok=1 +fi +if grep -q "awoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null \ + && grep -q "awoooi-host:host" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null \ + && ! grep -Eq "^[[:space:]]+- \".*(ubuntu-latest|stockplatform|headless|playwright)" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null; then + cd_lane_labels_ok=1 +fi +cd_lane_binary_kind=$(file -b /home/wooo/awoooi-cd-lane/awoooi_cd_lane 2>/dev/null || echo missing) +cd_lane_binary_elf=0 +echo "$cd_lane_binary_kind" | grep -qi "ELF" && cd_lane_binary_elf=1 +cd_lane_ok=0 +cd_lane_mode=blocked +if [ "$cd_lane_active" = "inactive" ] && echo "$cd_lane_execstart" | grep -q "/bin/false" && [ "$cd_lane_binary_elf" = "0" ]; then + cd_lane_ok=1 + cd_lane_mode=failclosed +elif [ "$cd_lane_sentinel" = "present" ] && [ "$cd_lane_active" = "active" ] && [ "$cd_lane_capacity_ok" = "1" ] && [ "$cd_lane_labels_ok" = "1" ] && [ "$cd_lane_binary_elf" = "1" ]; then + cd_lane_ok=1 + cd_lane_mode=controlled_open +fi +echo "CD_LANE_CONTROLLED mode=$cd_lane_mode load=$cd_lane_load unitfile=$cd_lane_unitfile active=$cd_lane_active sentinel=$cd_lane_sentinel capacity=$cd_lane_capacity_ok labels=$cd_lane_labels_ok binary_elf=$cd_lane_binary_elf ok=$cd_lane_ok" +[ "$cd_lane_ok" = "1" ] || bad=1 +direct_runner_count=$(pgrep -f "^/home/wooo/act-runner/act_runner|^/home/wooo/act-runner-controlled/act_runner|^/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" 2>/dev/null | wc -l | tr -d " ") echo "RUNNER_DIRECT_PROCESS_COUNT $direct_runner_count" [ "$direct_runner_count" = "0" ] || bad=1 -for p in /home/wooo/awoooi-cd-lane/awoooi_cd_lane /home/wooo/act-runner/act_runner /home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard /home/wooo/act-runner-controlled/act_runner /home/wooo/awoooi-controlled-runner/awoooi_controlled_runner; do +for p in /home/wooo/act-runner/act_runner /home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard /home/wooo/act-runner-controlled/act_runner /home/wooo/awoooi-controlled-runner/awoooi_controlled_runner; do kind=$(file -b "$p" 2>/dev/null || echo missing) echo "RUNNER_FAILCLOSED_BINARY $p kind=$kind" echo "$kind" | grep -qi "ELF" && bad=1 @@ -346,7 +372,7 @@ echo "BAD_RUNNER_GUARDRAILS $bad" return fi echo "$out" - grep -q "BAD_RUNNER_GUARDRAILS 0" <<<"$out" && ok "runner/CD lane fail-closed guardrails complete" || blocked "runner/CD lane guardrails incomplete" + grep -q "BAD_RUNNER_GUARDRAILS 0" <<<"$out" && ok "legacy runner fail-closed and controlled cd-lane guardrails complete" || blocked "legacy runner / controlled cd-lane guardrails incomplete" } check_job_containers() { diff --git a/scripts/reboot-recovery/post-start-quick-check.sh b/scripts/reboot-recovery/post-start-quick-check.sh index b9b560b8..b93dbdcf 100755 --- a/scripts/reboot-recovery/post-start-quick-check.sh +++ b/scripts/reboot-recovery/post-start-quick-check.sh @@ -538,24 +538,50 @@ fi section "110 runner fail-closed guard" runner_tmp="$(mktemp -t post-start-runner.XXXXXX)" if ssh_read "wooo@192.168.0.110" ' -for u in awoooi-cd-lane.service awoooi-direct-runner-open.service awoooi-direct-runner.service gitea-act-runner-host.service gitea-act-runner-awoooi-controlled.service gitea-awoooi-controlled-runner.service gitea-act-runner-awoooi-open.service; do +for u in awoooi-direct-runner-open.service awoooi-direct-runner.service gitea-act-runner-host.service gitea-act-runner-awoooi-controlled.service gitea-awoooi-controlled-runner.service gitea-act-runner-awoooi-open.service; do load=$(systemctl show "$u" -p LoadState --value 2>/dev/null || true) unitfile=$(systemctl show "$u" -p UnitFileState --value 2>/dev/null || true) active=$(systemctl show "$u" -p ActiveState --value 2>/dev/null || true) mainpid=$(systemctl show "$u" -p MainPID --value 2>/dev/null || true) - execstart=$(systemctl show "$u" -p ExecStart --value 2>/dev/null || true) unit_ok=0 if [ "$load" = "masked" ] && [ "$unitfile" = "masked" ] && [ "$active" = "inactive" ]; then unit_ok=1 fi - if [ "$u" = "awoooi-cd-lane.service" ] && [ "$active" = "inactive" ] && echo "$execstart" | grep -q "/bin/false"; then - unit_ok=1 - fi echo "RUNNER_FAILCLOSED_UNIT $u load=$load unitfile=$unitfile active=$active mainpid=$mainpid ok=$unit_ok" done -direct_runner_count=$(pgrep -f "^/home/wooo/awoooi-cd-lane/awoooi_cd_lane|^/home/wooo/act-runner/act_runner|^/home/wooo/act-runner-controlled/act_runner|^/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" 2>/dev/null | wc -l | tr -d " ") +cd_lane_load=$(systemctl show awoooi-cd-lane.service -p LoadState --value 2>/dev/null || true) +cd_lane_unitfile=$(systemctl show awoooi-cd-lane.service -p UnitFileState --value 2>/dev/null || true) +cd_lane_active=$(systemctl show awoooi-cd-lane.service -p ActiveState --value 2>/dev/null || true) +cd_lane_mainpid=$(systemctl show awoooi-cd-lane.service -p MainPID --value 2>/dev/null || true) +cd_lane_execstart=$(systemctl show awoooi-cd-lane.service -p ExecStart --value 2>/dev/null || true) +cd_lane_sentinel=missing +[ -e /run/awoooi-cd-lane-enabled ] && cd_lane_sentinel=present +cd_lane_capacity_ok=0 +cd_lane_labels_ok=0 +if grep -Eq "^[[:space:]]+capacity:[[:space:]]*1[[:space:]]*$" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null; then + cd_lane_capacity_ok=1 +fi +if grep -q "awoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null \ + && grep -q "awoooi-host:host" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null \ + && ! grep -Eq "^[[:space:]]+- \".*(ubuntu-latest|stockplatform|headless|playwright)" /home/wooo/awoooi-cd-lane/config.yaml 2>/dev/null; then + cd_lane_labels_ok=1 +fi +cd_lane_binary_kind=$(file -b /home/wooo/awoooi-cd-lane/awoooi_cd_lane 2>/dev/null || echo missing) +cd_lane_binary_elf=0 +echo "$cd_lane_binary_kind" | grep -qi "ELF" && cd_lane_binary_elf=1 +cd_lane_ok=0 +cd_lane_mode=blocked +if [ "$cd_lane_active" = "inactive" ] && echo "$cd_lane_execstart" | grep -q "/bin/false" && [ "$cd_lane_binary_elf" = "0" ]; then + cd_lane_ok=1 + cd_lane_mode=failclosed +elif [ "$cd_lane_sentinel" = "present" ] && [ "$cd_lane_active" = "active" ] && [ "$cd_lane_capacity_ok" = "1" ] && [ "$cd_lane_labels_ok" = "1" ] && [ "$cd_lane_binary_elf" = "1" ]; then + cd_lane_ok=1 + cd_lane_mode=controlled_open +fi +echo "CD_LANE_CONTROLLED mode=$cd_lane_mode load=$cd_lane_load unitfile=$cd_lane_unitfile active=$cd_lane_active mainpid=$cd_lane_mainpid sentinel=$cd_lane_sentinel capacity=$cd_lane_capacity_ok labels=$cd_lane_labels_ok binary_elf=$cd_lane_binary_elf ok=$cd_lane_ok" +direct_runner_count=$(pgrep -f "^/home/wooo/act-runner/act_runner|^/home/wooo/act-runner-controlled/act_runner|^/home/wooo/awoooi-controlled-runner/awoooi_controlled_runner" 2>/dev/null | wc -l | tr -d " ") echo "RUNNER_DIRECT_PROCESS_COUNT $direct_runner_count" -for p in /home/wooo/awoooi-cd-lane/awoooi_cd_lane /home/wooo/act-runner/act_runner /home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard /home/wooo/act-runner-controlled/act_runner /home/wooo/awoooi-controlled-runner/awoooi_controlled_runner; do +for p in /home/wooo/act-runner/act_runner /home/wooo/act-runner/act_runner.real-20260628-runner-pressure-guard /home/wooo/act-runner-controlled/act_runner /home/wooo/awoooi-controlled-runner/awoooi_controlled_runner; do kind=$(file -b "$p" 2>/dev/null || echo missing) echo "RUNNER_FAILCLOSED_BINARY $p kind=$kind" echo "$kind" | grep -qi "ELF" && echo "RUNNER_FAILCLOSED_BINARY_ELF $p" @@ -569,11 +595,12 @@ else fi cat "$runner_tmp" if awk '$1 == "RUNNER_FAILCLOSED_UNIT" && $NF != "ok=1" {bad=1} END {exit bad}' "$runner_tmp"; then - ok "110 direct runner/CD lane units are fail-closed" + ok "110 legacy direct/Gitea runner units are fail-closed" else - blocked "110 direct runner/CD lane units are not fail-closed" + blocked "110 legacy direct/Gitea runner units are not fail-closed" fi -grep -q "RUNNER_DIRECT_PROCESS_COUNT 0" "$runner_tmp" && ok "110 direct runner/CD lane process count is zero" || blocked "110 direct runner/CD lane process detected" +grep -q "CD_LANE_CONTROLLED .*ok=1" "$runner_tmp" && ok "110 controlled cd-lane is safe or fail-closed" || blocked "110 controlled cd-lane is neither safe-open nor fail-closed" +grep -q "RUNNER_DIRECT_PROCESS_COUNT 0" "$runner_tmp" && ok "110 legacy direct runner process count is zero" || blocked "110 legacy direct runner process detected" grep -q "RUNNER_FAILCLOSED_BINARY_ELF" "$runner_tmp" && blocked "110 runner fail-closed binary path restored to ELF" || ok "110 runner binary paths are fail-closed stubs or missing" grep -q "RUNNER_PRESSURE_GATE_RC 0" "$runner_tmp" && ok "110 host pressure gate returned 0" || blocked "110 host pressure gate is blocking" rm -f "$runner_tmp"