# P9-REMED-02 hosted runner isolation — 24 October 2026 **Hosted MariaDB CI: BLOCKED.** Fresh read-only evidence reproduces the isolation prerequisite at the accepted `3727a723e8d0d9066ef3a0a4eed3e5313ff9cc28` baseline. No job was dispatched, workflow modified, Docker command run against the hosted runner, or infrastructure changed by this investigation. ## Current verified evidence API observation: **2026-10-24T16:58:58.951740Z**, using the existing Git credential in memory for GET requests only. No credential value, Authorization header or credential-helper output is copied into reports. | Question | Verified result | Boundary | | --- | --- | --- | | CI provider | Gitea1.26.0, `/api/v1/version` HTTP200 | Version is not an isolation guarantee | | Actual runner | Baseline [run853](https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/853), job1743: runner5 `Live-Runner`; raw log reports v0.4.1 | Host OS, daemon owner, installed binary hash and registration scope unavailable | | Job execution | `ubuntu-latest` resolves to Docker `node:20-bookworm`, observed image digest `sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5` | Label does not mean an Ubuntu VM; digest is this job-image observation | | Effective host boundary | **Merged** HostConfig: `NetworkMode:host`, bind `/var/run/docker.sock:/var/run/docker.sock`, `Privileged:false`, empty PortBindings | Custom pre-merge `Binds:[]` is not the effective configuration. No socket was used by this investigation | | Runner listing | Repository endpoint HTTP200: runner3 `pi-runner-1`, offline, non-ephemeral, labels `ubuntu-latest` and `ubuntu-22.04` | This is not runner5; instance-runner endpoint and `/user` still HTTP403 despite repository admin/push/pull permissions | | Secret boundary | MariaDB workflow references no production secret. Deployment/backup/maintenance workflows reference production SSH credentials and all use `ubuntu-latest` | Shared routing label is verified; actual host co-location, secret values/scopes, fork/PR token policy and availability to this job are **not established** | | Persistent state | Job mounts `act-toolcache` at `/opt/hostedtoolcache`, plus generated workspace/env volumes | Shared cache isolation and runner host/config state not proven disposable. There is no MariaDB data volume in this run because no service started | | Runtime result | First guard exits1 at16:33:21UTC; raw log confirms checkout/setup main steps skipped and integration artifacts absent | API marks downstream steps failed; raw log distinguishes nonexecution. No MariaDB readiness, migrations, test or teardown occurred | | Cleanup | Raw log removes job container and attempts generated workspace/env volume removal | No service/private-network lifecycle, cancel/interruption recovery or cross-job leakage test exists | The guard remains an unconditional first-step failure. Runner-owned preparation still pulls/creates the host-network/socket job container and prefetches actions before that guard. A workflow step cannot remove the preparation exposure. Current workflow push filters do not include `fix/p9-pdf-security-requalification`; no new branch trigger is added merely to repeat unsafe preparation. The database lane remains blocked until operator evidence and a reviewed enabling change exist. The original run843/844 failures were `docker: command not found` after five mocked runner guards; installing a CLI would not prove a safe daemon. Run853 deliberately does not reach that command. Neither guard tests nor local Docker qualification count as hosted MariaDB execution. ## Version-specific supported capability The official [Gitea1.26 runner documentation](https://docs.gitea.com/1.26/usage/actions/act-runner/) explains registration scope/label routing and warns that job access to a host Docker socket can expose runner registration credentials. The documentation does not certify this deployment. Its general DinD examples are **not** an approved workaround here. Fresh direct HTTPS retrieval of the official v0.4.1 tag resolves to commit `9aafec169b7ebf3d71df2b06780868fb552b435e`; the source bytes match the prior qualification's hashes: - [Pinned config example](https://gitea.com/gitea/runner/src/commit/9aafec169b7ebf3d71df2b06780868fb552b435e/internal/pkg/config/config.example.yaml), lines86–115: empty `container.network` permits automatic network creation; `docker_host: "-"` suppresses daemon mounting into job and service containers; `privileged:false` and `valid_volumes:[]` are separate controls. - [Pinned runner](https://gitea.com/gitea/runner/src/commit/9aafec169b7ebf3d71df2b06780868fb552b435e/internal/app/run/runner.go), lines220–248: passes task secrets, network/socket/options/privilege/volume controls to the engine, disables reuse and requests automatic removal. - [Pinned act execution engine](https://gitea.com/gitea/act/src/tag/v0.261.10/pkg/runner/run_context.go), lines116–121 and309–401: a configured network is reused; otherwise services receive a generated job network and DNS aliases. Declared ports produce bindings. Normal cleanup attempts service/network removal and logs errors. Native services are therefore a supported source capability, **not a verified runtime capability of the installed binary/configuration**. Services start before job steps. Cleanup source/AutoRemove does not prove recovery after crashes or cancellations. A private Docker network also does not itself block host/LAN egress; host/network policy must establish production separation. ## Exact operator implementation and verification handoff The infrastructure owner must perform this work on a **new, dedicated nonproduction CI host/VM/daemon**. Do not repurpose, restart or reconfigure the unknown Live-Runner host under this development task. 1. Supply sanitized host/daemon ownership, runner registration scope, binary version/hash and image/OS identities. Prove no production workloads, credentials, data mounts or management endpoints are present/reachable. Give the dedicated runner a unique routing label, for example `jobtracker-mariadb-isolated`, unavailable on production/deployment runners. Pin its job image version/digest after compatibility validation; `ubuntu-latest` is insufficient. 2. On that dedicated host, generate configuration for the exact chosen supported runner binary. For the reviewed v0.4.1 capability, use `container.network: ""`, `container.docker_host: "-"`, `container.privileged:false`, `container.valid_volumes:[]`, and no `container.options` that reintroduce mounts, host networking, privilege or device access. Limit capacity to1 for the first proof, disable shared caches until qualified, and prefer disposable per-job runner/VM state. The runner controller may manage its dedicated daemon; **job and service containers must not receive a daemon socket/remote Docker endpoint or registration/configuration credentials**. These proposed settings are not applied or certified here. 3. Establish host firewall/egress policy: allow only needed source/package/artifact retrieval, deny production/private management/database access, and prevent cross-job access. Record the effective **merged** job and service HostConfig, mounts, capabilities, network attachments, port bindings and resource limits. Show no published MariaDB port, host network, privileged mode, persistent DB mount or job-accessible daemon. Review repository/fork/PR trust and least-privilege job-token/secret policy; make no production secrets available to this test lane. Do not dump full environments or secret values into proof. 4. Create a runner-managed native service named `mariadb` with exact `mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00`, recorded linux/amd64 identity, development-only credentials and disposable storage. Declare **no service ports or persistent volumes**. Require an image-supported health check plus bounded authenticated readiness/version queries. Prove job DNS `mariadb:3306` and generated-schema ownership. Isolated Docker services need no Docker CLI inside the job. 5. After infrastructure proof, request repository review of the enabling workflow and narrow transport change together. Replace the Compose path with native service use, route only to the unique runner label, preserve default loopback guards, and allow CI-service transport only for actual CI, service name `mariadb`, TCP3306. Do not allow arbitrary remote endpoints or a self-attested bypass variable. Keep actual startup migrations, independent persisted-state assertions, cleanup checks, source/image/version identities, native TRX and useful sanitized failure/server logs. Current provider inventory is35 cases; future changes must use exact discovery, zero hidden retries/skips, and never a hard-coded historical32-case pass. 6. Execute operator-observed success, deliberate test failure, cancellation and interrupted-runner recovery cases. Retain job-scoped before/after resource inventories; prove service/container/network/schema/data removal, no cross-job access and no stale cache/credentials. Identify how leaked resources are reclaimed after daemon/runner failure without broad prune commands or production effects. Only then run and publish the actual hosted RD21/MariaDB lane. Hosted PASS requires executed real MariaDB cases and verified lifecycle evidence. Operator configuration/source examples, guarded exit1, local tests and eventual CLI availability cannot satisfy it. The unmet condition is operator-controlled isolation and recovery evidence, followed by the reviewed workflow/transport change and actual hosted execution. ## Evidence retention and limitations [ci-isolation.json](ci-isolation.json) records sanitized fields and SHA-256 identities. Raw GET responses/logs and fetched sources remain local under `.artifacts/p9-remed-02/ci/`. An initial collector attempt saved its responses, then failed parsing a text log as JSON; its bytes are preserved. The successor correctly distinguishes text logs. Its convenience `mergedHostNetwork:false` substring field expected JSON formatting, while the log is Go-formatted; it is **not used as evidence**. The published interpretation is the actual merged log's `NetworkMode:host`, and `ci-isolation.json` records that explicitly. No failed collector is relabelled hosted test execution. No new hosted job, live infrastructure inspection, secret-value access, socket use, privileged change, production access or deployment was performed. Current CI status remains BLOCKED; its infrastructure prerequisites are independent from local RD21 provider closure and production release approval.