Files
jobtrackingapp/docs/redesign/phase-9/p9-remed-02/CI_ISOLATION.md
T

10 KiB
Raw Blame History

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, 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 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, 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, lines220–248: passes task secrets, network/socket/options/privilege/volume controls to the engine, disables reuse and requests automatic removal.
  • Pinned act execution engine, 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 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.