diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dd63b3..b8f1394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Не выпущено +- Runner installer сохраняет `HOME` и XDG-пути в user-unit `docker.service`, перезапускает активный daemon и проверяет окружение его процесса. - Runner installer защищает image и mountpoint root-owned home-каталогом, оставляет регистрацию и workspace в runner-owned каталоге, безопасно форматирует образ по открытому FD и проверяет `nosuid,nodev`. - Backend `0.11.3`: ключ подписи поисковых снимков читается из Docker secret-файла, а не из аргументов процесса. Добавлена базовая инфраструктура VPS, Caddy HTTPS proxy с разделёнными Compose-сетями и CI-проверка конфигурации; публикация образов и production-деплой остаются выключены до проверки runner, registry, backup/restore и ограниченного deploy-helper. - Frontend `0.1.2`: на планшетной ширине экран поиска переходит в одну колонку, чтобы фильтры, результаты и документ помещались в окно. diff --git a/docs/operations/CI_RUNNER.md b/docs/operations/CI_RUNNER.md index 7f0e311..38890e4 100644 --- a/docs/operations/CI_RUNNER.md +++ b/docs/operations/CI_RUNNER.md @@ -20,6 +20,11 @@ dedicated ext4 loop-backed Docker data filesystem. The runner account's home directory is root-owned mode `0711`, so CI cannot rename the image or mountpoint entries. Docker config remains under `.config`; registration state and the runner workspace live in `.config/act-runner`, which is runner-owned. The +rootless Docker setup and user service use `.config/act-runner` as writable +`HOME`, `.config` as `XDG_CONFIG_HOME`, and +`.config/act-runner/.local/share` as `XDG_DATA_HOME`. This keeps Docker config +and its systemd user unit in the existing `.config` tree without granting +write access to the protected home. rootless Docker daemon and runner user are separate from production Docker; `codex` is not added to sudo or Docker groups. Jobs do not receive the rootless Docker socket, the diff --git a/docs/operations/CURRENT_STATE.md b/docs/operations/CURRENT_STATE.md index de49f06..e65ef8e 100644 --- a/docs/operations/CURRENT_STATE.md +++ b/docs/operations/CURRENT_STATE.md @@ -95,6 +95,12 @@ UFW rule details, and protected file metadata remain unverified. and runtime state remain in runner-owned subdirectories. It reuses legacy `0755` config directories, creates the image through a pinned file descriptor, rejects path replacement, and requires mount options `nosuid,nodev`. + The reported installation blocker is that rootless setup receives this + protected directory as `HOME`; the installer assigns writable runner-owned + HOME/XDG paths, persists them in the `docker.service` user-unit drop-in, and + restarts an active daemon and checks the running process environment. Local + runner guards pass; + the change has not been run on the VPS. - Gitea repository runner inventory could not be read by the current API principal (403). The owner has not supplied runner state, and no runner Online status or runner-hosted workflow is claimed. The manual diff --git a/infra/runner/act-runner-healthcheck.sh b/infra/runner/act-runner-healthcheck.sh index 3c0b687..4c7da97 100644 --- a/infra/runner/act-runner-healthcheck.sh +++ b/infra/runner/act-runner-healthcheck.sh @@ -2,6 +2,9 @@ set -Eeuo pipefail systemctl is-active --quiet akyldash-act-runner.service runner_uid=$(id -u akyldash-runner) -runuser -u akyldash-runner -- env HOME=/var/lib/akyldash-runner \ +runuser -u akyldash-runner -- env \ + HOME=/var/lib/akyldash-runner/.config/act-runner \ + XDG_CONFIG_HOME=/var/lib/akyldash-runner/.config \ + XDG_DATA_HOME=/var/lib/akyldash-runner/.config/act-runner/.local/share \ DOCKER_HOST="unix:///run/user/$runner_uid/docker.sock" \ /usr/bin/docker info --format '{{.ServerVersion}}' >/dev/null diff --git a/infra/runner/install-runner.sh b/infra/runner/install-runner.sh index f170144..e8fe971 100644 --- a/infra/runner/install-runner.sh +++ b/infra/runner/install-runner.sh @@ -4,6 +4,8 @@ set -Eeuo pipefail readonly runner_user=akyldash-runner readonly runner_home=/var/lib/akyldash-runner readonly runner_runtime_home="$runner_home/.config/act-runner" +readonly runner_xdg_config_home="$runner_home/.config" +readonly runner_xdg_data_home="$runner_runtime_home/.local/share" readonly runner_store="$runner_home/docker-data" readonly runner_image="$runner_home/docker-store.img" readonly runner_mount_unit_name="$(systemd-escape --path --suffix=mount /var/lib/akyldash-runner/docker-data)" @@ -92,6 +94,8 @@ runner_ensure_private_directory "$runner_home/.config/systemd" "$runner_user" "$ runner_ensure_private_directory "$runner_home/.config/systemd/user" "$runner_user" "$runner_user" || die 'runner user systemd directory failed validation' runner_ensure_private_directory "$runner_home/.config/systemd/user/docker.service.d" "$runner_user" "$runner_user" || die 'runner Docker override directory failed validation' runner_ensure_private_directory "$runner_runtime_home" "$runner_user" "$runner_user" || die 'runner runtime home failed directory validation' +runner_ensure_private_directory "$runner_runtime_home/.local" "$runner_user" "$runner_user" || die 'runner XDG data parent failed directory validation' +runner_ensure_private_directory "$runner_xdg_data_home" "$runner_user" "$runner_user" || die 'runner XDG data directory failed directory validation' if [[ -e $runner_home/.runner || -L $runner_home/.runner ]]; then [[ -f $runner_home/.runner && ! -L $runner_home/.runner ]] || die 'legacy runner registration state is not a regular file' if [[ ! -e $runner_runtime_home/.runner && ! -L $runner_runtime_home/.runner ]]; then @@ -141,6 +145,12 @@ TasksMax=1024 Restart=always RestartSec=5 EOF +runner_install_user_content "$runner_home/.config/systemd/user/docker.service.d/environment.conf" "$runner_user" "$runner_user" 0644 <&2 + exit 1 +fi +grep -Fq 'HOME=/var/lib/akyldash-runner/.config/act-runner' infra/runner/act-runner-healthcheck.sh +grep -Fq 'XDG_CONFIG_HOME=/var/lib/akyldash-runner/.config' infra/runner/act-runner-healthcheck.sh +grep -Fq 'XDG_DATA_HOME=/var/lib/akyldash-runner/.config/act-runner/.local/share' infra/runner/act-runner-healthcheck.sh +if grep -Fq 'env HOME="$runner_home"' "$installer"; then + echo 'Protected runner home must not be passed as rootless Docker HOME' >&2 + exit 1 +fi grep -Fq 'die '\''stop akyldash-act-runner.service after all jobs finish before rerunning this installer' "$installer" -grep -Fq 'ReadWritePaths=$runner_runtime_home /var/log/akyldash-runner /run/user/$runner_uid' "$installer" +grep -Fq 'ReadWritePaths=$runner_runtime_home $runner_xdg_config_home /var/log/akyldash-runner /run/user/$runner_uid' "$installer" grep -Fq 'os.O_NOFOLLOW | os.O_CLOEXEC' infra/runner/secure-runner-image.py grep -Fq 'os.posix_fallocate(image_fd, 0, int(bytes_text))' infra/runner/secure-runner-image.py grep -Fq 'pass_fds=(image_fd,)' infra/runner/secure-runner-image.py