diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 9ab435ef7..808ab9119 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,20 @@ +## 2026-06-29 — 09:00 non-110 runner post-registration autostart path armed + +**完成內容**: +- `ops/runner/install-awoooi-non110-runner-user-service.sh` 新增 `awoooi-non110-runner-autostart.path` / `.service`;`--apply` 只啟用 path watcher,不直接啟動 runner service。 +- autostart service 只有在 `act_runner` 可執行、`config.yaml` 非空、`.runner` registration metadata 非空時才 touch enable sentinel 並 `systemctl --user enable --now awoooi-non110-runner.service`。 +- `ops/runner/check-awoooi-non110-runner-readiness.sh` 新增 autostart path readback,輸出 `READY_AUTOSTART_PATH_COUNT` 與 `RUNNER_AUTOSTART_PATH_WATCH`,避免 verifier 只顯示缺註冊而看不到 watcher 已 armed。 + +**驗證結果**: +- 本地:`bash -n` 通過;runner focused pytest `13 passed`;`python3 ops/runner/guard-gitea-runner-pressure.py --root .` 通過;`git diff --check` 通過。 +- 188 apply readback:`AUTOSTART_PATH_ENABLE_PERFORMED=1`、`SERVICE_START_PERFORMED=0`、`SERVICE_ENABLE_PERFORMED=0`、autostart path `LoadState=loaded ActiveState=active UnitFileState=enabled`。 +- 188 verifier:`READY_CONFIG_COUNT=1`、`READY_BINARY_COUNT=1`、`READY_SERVICE_COUNT=1`、`READY_AUTOSTART_PATH_COUNT=1`、`READY_REGISTRATION_COUNT=0`、`READY_ACTIVE_SERVICE_COUNT=0`、`UNMANAGED_RUNNER_CONTAINERS=none`、`AWOOOI_NON110_RUNNER_READY=0`。 + +**剩餘 blocker**: +- `.runner` registration metadata 仍不存在;safe next step 是從外部互動 TTY 執行 safe registration helper,不列印 token、不使用 `--token` argv、不讀 `.runner` 內容。註冊完成後 autostart path 會自動 enable runner service,再重跑 verifier。 + +**邊界**:未讀、複製、貼上、外送 runner token / secret / `.runner` 內容 / raw session / SQLite / auth / `.env`;未啟動 188 runner service;未重開 110 runner;未使用 GitHub;未 force push。 + ## 2026-06-29 — 08:51 Delivery Workbench non-110 runner online label blocker 投影 **完成內容**: @@ -49036,19 +49053,3 @@ production browser smoke: - 沒有讀、複製、貼上、外送 runner token / secret / `.env` / raw sessions / SQLite / auth。 - 沒有啟動 188 runner service、沒有重開 110 runner、沒有 GitHub API / gh / GitHub Actions、沒有 force push。 - Gitea CD 仍需等 non-110 runner 完成外部安全註冊並讀回 `AWOOOI_NON110_RUNNER_READY=1` 後才可承接。 - -## 2026-06-29 — 08:58 non-110 runner autostart controlled apply - -**完成內容**: -- 188 `/home/ollama/act-runner-awoooi` 已套用 user-level autostart path / service source:`awoooi-non110-runner-autostart.path` 監看 `.runner` metadata 出現後才觸發 `awoooi-non110-runner.service` enable/start。 -- installer `--apply` 讀回 `AUTOSTART_PATH_ENABLE_PERFORMED=1`、`SERVICE_START_PERFORMED=0`、`SERVICE_ENABLE_PERFORMED=0`;runner 本體維持 `inactive/disabled`,避免未註冊狀態誤開 CD lane。 -- 188 systemd readback:autostart path `LoadState=loaded`、`ActiveState=active`、`UnitFileState=enabled`;autostart service `inactive/static`;runner service `inactive/disabled`。 - -**verifier readback**: -- `check-awoooi-non110-runner-readiness.sh`:`READY_CONFIG_COUNT=1`、`READY_BINARY_COUNT=1`、`READY_REGISTRATION_COUNT=0`、`READY_SERVICE_COUNT=1`、`READY_ACTIVE_SERVICE_COUNT=0`、`BLOCKER_COUNT=3`、`AWOOOI_NON110_RUNNER_READY=0`。 -- blockers 仍為 `runner_registration_missing`、`runner_service_not_active:awoooi-non110-runner.service`、`no_active_runner_service`;safe next step 仍是互動 TTY 執行 safe registration helper,不得由 Codex 讀取或輸入 runner token。 - -**仍維持**: -- 沒有讀、複製、貼上、外送 runner token / secret / `.runner` 內容、`.env`、raw sessions / SQLite / auth。 -- 沒有重開 110 legacy / generic runner、沒有恢復 `ubuntu-latest` / `self-hosted` 泛用 label、沒有把 pressure gate 改成 warn-only。 -- Gitea CD / production UI bundle smoke 仍需等 `AWOOOI_NON110_RUNNER_READY=1` 後承接;目前不得宣稱 runner lane 已 reopened。 diff --git a/ops/runner/check-awoooi-non110-runner-readiness.sh b/ops/runner/check-awoooi-non110-runner-readiness.sh index 1a039157d..1c5b5b4ec 100755 --- a/ops/runner/check-awoooi-non110-runner-readiness.sh +++ b/ops/runner/check-awoooi-non110-runner-readiness.sh @@ -14,6 +14,7 @@ RUNNER_BINARY_PATHS="${RUNNER_BINARY_PATHS:-${RUNNER_HOME}/awoooi-non110-runner/ RUNNER_DOCKER_IMAGES="${RUNNER_DOCKER_IMAGES:-gitea/act_runner:latest}" RUNNER_REGISTRATION_PATHS="${RUNNER_REGISTRATION_PATHS:-${RUNNER_HOME}/awoooi-non110-runner/data/.runner ${RUNNER_HOME}/awoooi-non110-runner/.runner ${RUNNER_HOME}/act-runner-awoooi/.runner /home/wooo/act-runner-awoooi/.runner /home/wooo/awoooi-act-runner/.runner /home/wooo/awoooi-non110-runner/.runner /home/wooo/act-runner/.runner}" RUNNER_SERVICE_NAMES="${RUNNER_SERVICE_NAMES:-awoooi-non110-runner.service gitea-act-runner-awoooi.service gitea-act-runner-host.service}" +RUNNER_AUTOSTART_PATH_UNIT_NAMES="${RUNNER_AUTOSTART_PATH_UNIT_NAMES:-awoooi-non110-runner-autostart.path}" ALLOWED_RUNNER_CONTAINER_NAMES="${ALLOWED_RUNNER_CONTAINER_NAMES:-awoooi-non110-runner stockplatform-ubuntu-runner}" ALLOWED_LABEL_NAMES="${ALLOWED_LABEL_NAMES:-awoooi-non110-host awoooi-non110-ubuntu awoooi-host awoooi-ubuntu}" FORBIDDEN_LABEL_RE="${FORBIDDEN_LABEL_RE:-^(ubuntu-latest|ubuntu-[0-9].*|self-hosted|stockplatform.*|stock-platform.*|headless.*|playwright.*)$}" @@ -30,6 +31,7 @@ READY_BINARY_COUNT=0 READY_REGISTRATION_COUNT=0 READY_SERVICE_COUNT=0 READY_ACTIVE_SERVICE_COUNT=0 +READY_AUTOSTART_PATH_COUNT=0 section() { printf '\n== %s ==\n' "$1" @@ -408,6 +410,39 @@ check_services() { fi } +check_autostart_paths() { + section "runner autostart metadata" + local unit text state registration_watch active enabled + for unit in $RUNNER_AUTOSTART_PATH_UNIT_NAMES; do + if ! text="$(systemd_cat "$unit" 2>/dev/null)"; then + printf 'RUNNER_AUTOSTART_PATH unit=%s installed=0\n' "$unit" + continue + fi + state="$(systemd_show "$unit" | tr '\n' ' ' || true)" + if grep -q 'LoadState=not-found' <<<"$state"; then + printf 'RUNNER_AUTOSTART_PATH unit=%s installed=0\n' "$unit" + continue + fi + registration_watch=0 + active=0 + enabled=0 + if grep -Eq '^[[:space:]]*PathExists=.*\.runner[[:space:]]*$' <<<"$text"; then + registration_watch=1 + fi + if grep -q 'ActiveState=active' <<<"$state"; then + active=1 + fi + if grep -q 'UnitFileState=enabled' <<<"$state"; then + enabled=1 + fi + printf 'RUNNER_AUTOSTART_PATH unit=%s installed=1 %s\n' "$unit" "$state" + printf 'RUNNER_AUTOSTART_PATH_WATCH unit=%s registration_watch=%s active=%s enabled=%s\n' "$unit" "$registration_watch" "$active" "$enabled" + if [ "$registration_watch" -eq 1 ] && [ "$active" -eq 1 ] && [ "$enabled" -eq 1 ]; then + READY_AUTOSTART_PATH_COUNT=$((READY_AUTOSTART_PATH_COUNT + 1)) + fi + done +} + check_rollback() { section "rollback metadata" local unit found=0 @@ -455,6 +490,7 @@ main() { check_binaries check_registrations check_services + check_autostart_paths check_rollback check_pressure @@ -464,6 +500,7 @@ main() { printf 'READY_REGISTRATION_COUNT=%s\n' "$READY_REGISTRATION_COUNT" printf 'READY_SERVICE_COUNT=%s\n' "$READY_SERVICE_COUNT" printf 'READY_ACTIVE_SERVICE_COUNT=%s\n' "$READY_ACTIVE_SERVICE_COUNT" + printf 'READY_AUTOSTART_PATH_COUNT=%s\n' "$READY_AUTOSTART_PATH_COUNT" printf 'WARNING_COUNT=%s\n' "${#WARNINGS[@]}" printf 'BLOCKER_COUNT=%s\n' "${#BLOCKERS[@]}" if [ "${#BLOCKERS[@]}" -eq 0 ]; then @@ -476,6 +513,10 @@ main() { && [ "$READY_BINARY_COUNT" -gt 0 ] \ && [ "$READY_SERVICE_COUNT" -gt 0 ] \ && [ "$READY_REGISTRATION_COUNT" -eq 0 ]; then + if [ "$READY_AUTOSTART_PATH_COUNT" -gt 0 ]; then + printf 'safe_next_step=run_register_awoooi_non110_runner_script_without_printing_token_then_autostart_path_will_enable_service_and_rerun_this_verifier\n' + return 1 + fi printf 'safe_next_step=run_register_awoooi_non110_runner_script_without_printing_token_then_enable_service_and_rerun_this_verifier\n' return 1 fi diff --git a/ops/runner/test_check_awoooi_non110_runner_readiness.py b/ops/runner/test_check_awoooi_non110_runner_readiness.py index 2e07c07ad..e561525dc 100644 --- a/ops/runner/test_check_awoooi_non110_runner_readiness.py +++ b/ops/runner/test_check_awoooi_non110_runner_readiness.py @@ -55,6 +55,24 @@ NoNewPrivileges=true ) +def _write_path_unit(path: Path, registration_path: Path) -> None: + path.write_text( + f""" +[Unit] +Description=Watch AWOOOI non-110 runner registration metadata + +[Path] +PathExists={registration_path} +Unit=awoooi-non110-runner-autostart.service + +[Install] +WantedBy=default.target +""".strip() + + "\n", + encoding="utf-8", + ) + + def _run_verifier( tmp_path: Path, registration_path: Path, @@ -80,6 +98,10 @@ case "$cmd" in unit="${{1:-}}" fi if [ -f "{unit_dir}/$unit" ]; then + if [[ "$unit" == *.path ]]; then + printf 'LoadState=loaded\\nActiveState=active\\nUnitFileState=enabled\\nMainPID=0\\n' + exit 0 + fi printf 'LoadState=loaded\\nActiveState={"active" if active_service else "inactive"}\\nUnitFileState=disabled\\nMainPID={"1234" if active_service else "0"}\\n' exit 0 fi @@ -156,6 +178,10 @@ exit 1 unit_config_path, registration_path, ) + _write_path_unit( + unit_dir / "awoooi-non110-runner-autostart.path", + registration_path, + ) env = { **os.environ, @@ -165,6 +191,7 @@ exit 1 "RUNNER_CONFIG_PATHS": str(config_path), "RUNNER_BINARY_PATHS": str(binary_path), "RUNNER_SERVICE_NAMES": "awoooi-non110-runner.service", + "RUNNER_AUTOSTART_PATH_UNIT_NAMES": "awoooi-non110-runner-autostart.path", "ROLLBACK_UNIT_NAMES": "awoooi-non110-runner-rollback.service", "RUNNER_REGISTRATION_PATHS": str(registration_path), "MAX_HEAVY_PROCESS_COUNT": "0", @@ -186,9 +213,15 @@ def test_non110_readiness_blocks_without_registration_state(tmp_path: Path) -> N assert "AWOOOI_NON110_RUNNER_READY=0" in result.stdout assert "raw_runner_registration_read=false" in result.stdout assert ( - "safe_next_step=run_register_awoooi_non110_runner_script_without_printing_token_then_enable_service_and_rerun_this_verifier" + "safe_next_step=run_register_awoooi_non110_runner_script_without_printing_token_then_autostart_path_will_enable_service_and_rerun_this_verifier" in result.stdout ) + assert "RUNNER_AUTOSTART_PATH unit=awoooi-non110-runner-autostart.path installed=1" in result.stdout + assert ( + "RUNNER_AUTOSTART_PATH_WATCH unit=awoooi-non110-runner-autostart.path registration_watch=1 active=1 enabled=1" + in result.stdout + ) + assert "READY_AUTOSTART_PATH_COUNT=1" in result.stdout def test_non110_readiness_accepts_registration_state_presence_without_reading_it(