# P9-SEC-02 hosted CI assessment — 25 October 2026 ## Repository quarantine checkpoint After the read-only assessment below, the primary agent changed only `.gitea/workflows/mariadb-integration.yml`: removed automatic pull-request preparation, selected the unique `jobtracker-mariadb-isolated` label and added the current qualification branch to push coverage. The unconditional first-step exit1, database guards, image pin and existing test architecture remain. No runner host, registration, privilege, socket, service, backup or deployment workflow changed. Four new workflow invariant tests failed3/passed1 before the change and pass4/4 afterward; the existing five mocked runner tests also pass. The unique label is a routing prerequisite, not proof of a safe matching host. Hosted CI remains BLOCKED and current isolation UNVERIFIED pending operator/runtime evidence. The source hashes below describe the earlier read-only snapshot, not a claim that the workflow was unmodified afterward. **Hosted MariaDB: BLOCKED. Current runner isolation: UNVERIFIED.** Current effective HostConfig is unknown. Historical run853 was unsafe for this database lane; that observation does not certify today's configuration. No hosted MariaDB test or private-service lifecycle was executed by this assessment. Baseline `f17dba2ec06ea8f53c2785eaaebd25abc515ebf8`, branch `fix/p9-model-cache-and-ci-qualification`. Fresh metadata observation **2026-10-25T06:23:27.915835Z / 07:23:27 CET Europe/Paris**. The user authorized bounded read-only CI/API and official-source investigation. Existing Git credentials were used only in memory with redirects refused; no helper output, Authorization header or credential values were retained. Repository permission is not host permission. ## Fresh metadata and boundaries | Observation | Result | Meaning | | --- | --- | --- | | Version/repository | HTTP200; Gitea1.26.0; admin/push/pull reported | Readable repository metadata; no infrastructure authority established | | Repository runners | HTTP200; runner3 `pi-runner-1`, offline, non-ephemeral, `ubuntu-latest`/`ubuntu-22.04` | Not the actual runner5 | | Instance runners and user | Both HTTP403 | Runner5 configuration, registration scope and host remain inaccessible | | Latest runs | Requested100; returned50 | Bounded window, not exhaustive history | | New visible runs | [855](https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/855)/[854](https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/854), main `5f835e54a9b74e6b71418422e28431b2af06453f`, success | Job metadata names `backup`, runner5 `Live-Runner`; these are not MariaDB tests | | Backup job times | Job1745 01:00:47–01:01:04UTC; job1744 00:01:21–00:01:38UTC,25October | Recent runner activity, not proof of its host boundary or production state | | Current task branch | Branch query returns0; none in latest50 | No accessible branch execution in the inspected window; filter support/exhaustive absence not certified | | Latest visible MariaDB run | Historical853/job1743 at3727a72, failure | Isolation guard failure before database execution, as established previously | Only metadata for these jobs was requested. Backup logs, secret endpoints, production hosts, daemon endpoints and runner host files were not accessed. Source workflow backup/deployment/maintenance jobs reference production SSH credentials and share `ubuntu-latest` with the blocked MariaDB workflow. Metadata now verifies that actual runner5 executes backup jobs. It does not establish host co-location, secret values or scopes, or job-to-job credential availability. ## Historical runtime versus current unknown The [previous isolation report](../p9-remed-02/CI_ISOLATION.md) inspected24October run853: runner-reported v0.4.1, job image `node:20-bookworm`, merged **`NetworkMode:host` and `/var/run/docker.sock` bind**, `Privileged:false`, persistent tool cache. The guard exited1 before checkout/SDK/database work. Log SHA256 `448df52f9c9cf3c156b5f742dbef6e3745844b25f968d4e9138c142437837134` identifies that historical evidence. The [earlier metadata refresh](../p9-remed-02/CI_REFRESH_2026-10-25.md) also did not inspect current HostConfig. This investigation downloaded no runtime logs and performed no live HostConfig inspection. Therefore historical exposure is **UNSAFE for the intended lane**, while today's isolation verdict is **UNVERIFIED**, rather than an assertion that current configuration is unchanged. No private-service success/failure/cancel/crash cleanup or cross-job leakage proof exists. ## Source capability and preserved repository guards Fresh immutable upstream retrieval returned HTTP200 and matched all three previous source hashes: | Primary source | SHA256 | Relevant capability | | --- | --- | --- | | [Runner configuration at9aafec169b7ebf3d71df2b06780868fb552b435e](https://gitea.com/gitea/runner/src/commit/9aafec169b7ebf3d71df2b06780868fb552b435e/internal/pkg/config/config.example.yaml) | `e47d046dc368eb85b35665b4a5dba57ce0be4053c665ff737916a7561f7337fa` | Lines86–115: automatic network, independent privilege/volume/options controls, `docker_host: "-"` to suppress socket mounting | | [Runner execution](https://gitea.com/gitea/runner/src/commit/9aafec169b7ebf3d71df2b06780868fb552b435e/internal/app/run/runner.go) | `857b163f42aeb350aa32fbdc884e8d2ceb738d77e8a25504ac38c3e0035ab590` | Lines220–248 pass secrets and container settings, disable reuse and request automatic removal | | [act v0.261.10 engine](https://gitea.com/gitea/act/src/tag/v0.261.10/pkg/runner/run_context.go) | `45aea88466bc40c1cddad7ee6cfe98444ffd225a719683ee319c909075466c2c` | Lines116–121/309–401: generated network for services unless configured network overrides it, service DNS aliases, declared port bindings, normal cleanup attempts | The versioned Gitea documentation request returned403; no refreshed documentation contents are claimed. Pinned source proves supported capability, not installed binary identity, effective configuration, crash recovery or production egress separation. Services and runner-owned preparation precede workflow steps; an in-job guard cannot remove that exposure. Repository source review preserves the unconditional first-step exit1, existing branch filters, explicit failure rather than SQLite fallback, loopback TCP validation, generated schema ownership and cleanup failure propagation. The current task branch has no push trigger. Broad pull-request and manual triggers remain. Five existing Python guard tests passed with mocked subprocesses; their injected cleanup17/setup1 outputs are expected fixtures. Seven bounded source assertions passed. Neither check is a hosted or database test. Exact source hashes for eight relevant workflow/runner/fixture/Compose files are in [ci-assessment.json](ci-assessment.json). **Repository improvement proposal only:** consider removing the broad `pull_request` trigger while isolation is unverified, because the first failing step still allows runner preparation. This prevents an automatic event from preparing the known shared routing lane; manual triggering must remain operator-controlled. Review Gitea event behavior and dedicated routing before restoring it. No workflow or transport change was made here. A step-level bypass, adding Docker CLI, arbitrary remote endpoint exception, or routing to `ubuntu-latest` cannot safely close this gate. ## Exact operator checklist before enabling execution 1. On a **new dedicated nonproduction host/VM and daemon**, provide sanitized ownership, OS/image identity, runner binary version/hash and registration scope. Do not reconfigure Live-Runner under this task. Prove production workloads, data, secrets and management endpoints are absent and unreachable. Register a unique label such as `jobtracker-mariadb-isolated`; validate and pin the job image digest. 2. Generate configuration for the chosen exact binary. For the reviewed source capability, use empty `container.network`, `container.docker_host: "-"`, `privileged:false`, `valid_volumes:[]`, and no options reintroducing mounts, devices, host networking or privilege. Start capacity1; disable shared cache until qualified; use disposable per-job state. Only the controller manages its dedicated daemon; jobs/services receive no daemon endpoint/socket or registration/config credentials. 3. Prove effective **merged** job/service HostConfig, mounts, capabilities, network attachments, port bindings and resource limits. Establish explicit host firewall/egress and cross-job separation; a private Docker network alone does not deny production/LAN access. Review fork/PR trust, token permissions and secret scope without printing secrets. No production credentials may reach this lane. 4. Qualify native service `mariadb`, exact `mariadb:12.2.2@sha256:42a27baaba3e8f3f0159d16381d5a7156661aa91dcc65f663cabb6a6f9503c00`, linux/amd64, development-only credentials and disposable storage. Declare no published ports or persistent DB volumes. Require bounded image health/authenticated readiness and exact version checks; prove job DNS `mariadb:3306` and generated schema ownership. 5. After infrastructure evidence, review workflow and fixture transport together: unique label, native service, preserved default loopback guard, strict CI-only service name `mariadb` and TCP3306. No arbitrary remote endpoint/self-attested isolation bypass. Retain startup migrations, independent persisted-state assertions, sanitized useful logs, native TRX, current exact test discovery and zero hidden retries/skips. Do not substitute historic test totals. 6. Execute success, deliberate test failure, cancellation and interrupted-runner recovery. Retain job-scoped before/after resource inventories proving service/container/network/schema/data removal, no stale credentials/cache and no cross-job access. Document targeted orphan reclamation after daemon/runner failure without broad prune operations or production effects. Then execute and publish the actual hosted MariaDB lane at its exact source/image identities. Hosted PASS requires real MariaDB test execution **and** verified isolation/lifecycle evidence. Current owner action is infrastructure proof followed by reviewed repository enabling changes and actual execution. API success, backup success, labels, source examples, mocked guards and local MariaDB qualification do not satisfy it. Production release remains an independent gate. Raw bounded metadata, source bytes and manifests are retained under `.artifacts/p9-sec-02/ci/`; [ci-assessment.json](ci-assessment.json) records response and source hashes, actual permission failures, limitations and actions. No workflow dispatch, host mutation, Docker socket use, secret-value/log access, database operation or deployment occurred. Final metadata refresh25October12:32UTC: [ci-final-refresh.json](ci-final-refresh.json) records runs856/857 at22ef8d0/30e251a queued for `jobtracker-mariadb-isolated`, with unassigned runner IDs0. The query returned metadata only; no current HostConfig or service lifecycle was inspected and no job log was downloaded. **Hosted MariaDB BLOCKED; isolation UNVERIFIED;0 hosted database cases.** Operator provisioning and actual isolation/execution proof remain necessary. Review stale owned queued guard jobs during that separately authorised operator handoff; this task did not cancel them.