Skip to content

fix(OMN-14900): container-recreate-durable safe.directory + private runner OMNI_HOME write targets for release-train scripts - #2393

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-14900-runner-private-omnihome-safe-directory
Jul 23, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-14900-runner-private-omnihome-safe-directory

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 22, 2026 •

Copy link
Copy Markdown
Collaborator

Ticket

OMN-14900 — release-train-lab runner write-path hardening. This PR makes the 2026-07-21 exec-applied live relief container-recreate-durable: every fix lives in committed scripts/compose/workflow config, none in mutable container state.

Citation semantics: this PR's deploy evidence binds OMN-14900 alone. Context work is referenced by PR number only (release-train trigger #2388; runner listener-liveness #2194; sibling-clone force/mixed-ref follow-up filed off #2388), because deploy-gate treats a bare ticket citation as an evidence binding.

Mode-1 evidence — five red release-train-lab.yml runs, 2026-07-21

All five runs failed on uid-mismatch writes against the SHARED /data/omninode/omni_home clones bind-mounted into omninode-deploy-runner:

Run Created (UTC) Conclusion
29799976126 2026-07-21T03:59:10Z failure
29800099028 2026-07-21T04:01:44Z failure
29800399010 2026-07-21T04:08:02Z failure
29800684577 2026-07-21T04:14:03Z failure
29800954943 2026-07-21T04:19:51Z failure

Failure modes observed across the five runs: fatal: detected dubious ownership (exit 128), FETCH_HEAD EACCES (exit 255), and 'dev' is already checked out in a host worktree (exit 128). The live relief was an exec-applied git config --global safe.directory inside the running container plus an uncommitted compose hand-edit — state that any --force-recreate silently drops. That non-durability is the exact failure mode this PR eliminates.

Seam / write-target table (file-by-file)

File Seam / write target Change
docker/docker-compose.runners.yml deploy-runner OMNI_HOME bind (all git write targets) Private OMNI_HOME via DEPLOY_RUNNER_OMNI_HOME (fail-fast :? interpolation); identical host:container bind path (docker-outside-of-docker requirement); SHARED ${OMNI_HOME} mount REMOVED — shared-clone writes are now structurally impossible; committed root-phase chown init wrapper; reconciled to live reality: repo-scoped GITHUB_ORG_URL + explicitly-empty RUNNER_GROUP; GIT_CONFIG_* safe.directory env retained as defense-in-depth, retargeted at the private clones
docker/runners/entrypoint.sh runner registration (config.sh) --runnergroup now conditional on non-empty RUNNER_GROUP (no-colon default so explicit-empty survives) — prevents bricked re-registration after recreate (repo-scoped config.sh rejects --runnergroup)
scripts/runtime_build/ensure_runner_clones.sh (NEW) private-clone provisioning (write target: $OMNI_HOME/<repo> inside the runner) Idempotent provisioning of the 5 private clones (public repos, anonymous https; base URL overridable for tests); euid-operability assertion; called from all three entry scripts
scripts/runtime_build/refresh_stability_lane.sh stability-lane refresh git writes git_clone() safe.directory wrapper ported from refresh_dev_lane.sh; every bare git -C replaced; ensure call added
scripts/runtime_build/refresh_dev_lane.sh dev-lane refresh git writes ensure call added (wrapper already present)
scripts/runtime_build/cut_release_train_tag.sh tag mint + publish (write target: GitHub tag ref via API, never a credentialed clone push) scoped safe.directory wrapper; execute-mode ensure + fetch before tag-name mint; tag ref created via gh api repos/.../git/refs with the workflow token — private clones carry no push credentials
.github/workflows/release-train-lab.yml cut-tag job token seam permissions: contents: write + GH_TOKEN for the gh-api tag-ref creation; header refreshed
scripts/runtime_build/stage_workspace.sh RT-1 workspace staging git invocations safe.directory scoping on every git invocation (RT-1 write path no longer depends on non-durable container-env GIT_CONFIG_* pass-through)
scripts/runtime_build/deploy_source_ref.py source-ref resolution git invocations safe.directory scoping
scripts/runtime_build/check_sibling_lock_pins.py sibling lock-pin verification git invocations safe.directory scoping
docs/runbooks/release-train-lab.md runbook recreate procedure documented (operator-gated)
tests/unit/scripts/test_runner_private_omni_home_safe_directory.py (NEW) seeded-failure suite see below
tests/scripts/test_deploy_runtime_build_context.py existing build-context suite updated for the new ensure/wrapper seams

Design decision (Q2, sibling tag resolution): externally-cut lab tags fail LOUDLY at RT-1 sibling checkout (private sibling clones cannot resolve them); runner-cut tags resolve via local tags persisted on the private bind.

Seeded-failure tests

tests/unit/scripts/test_runner_private_omni_home_safe_directory.py: 13 of 20 RED at pre-fix base 24ba852d, 20 GREEN post-fix. Coverage: static no-bare-git -C guards across the runtime_build scripts, GIT_TEST_ASSUME_DIFFERENT_OWNER behavioral RED/GREEN (real dubious-ownership reproduction, not a surrogate), compose config-as-data recreate-durability assertions (the fix must survive --force-recreate by construction), and an ensure-script behavioral suite on file:// fixtures.

D1 — runner recreate is operator-gated (this PR enables it, does not perform it)

The live omninode-deploy-runner container is untouched by this PR. Applying the fix requires a container recreate with DEPLOY_RUNNER_OMNI_HOME set — an operator-gated follow-up whose procedure is documented in docs/runbooks/release-train-lab.md. This PR is the prerequisite that makes that recreate safe and durable instead of state-destroying.

OCC companion

The OCC evidence companion is Codex's lane — this PR authors no evidence for itself (implementer must not author their own evidence). The pre-push deploy-scope DoD hook returned NOTICE_COMPANION_UNMERGED for docker/docker-compose.runners.yml; the hosted deploy-gate / Receipt-Gate are expected RED (companion-shape) until the companion lands and binds Evidence-Ticket / Evidence-Source.

Do not auto-merge. Merges are Codex's.

Local gates (author-run)

  • Full pre-commit suite green on commit; pre-push governed impacted-test selector: tests/ci/ tests/unit/scripts/ → 1661 passed, 1 skipped.
  • Deploy-scope DoD parity hook: NOTICE_COMPANION_UNMERGED (expected — companion unmerged).

Evidence-Ticket: OMN-14900
Evidence-Source: OCC#4619
Evidence-Commit: 3039a089904f970ef3ad89419f39e9b918e7bab1

…ry on all runtime_build git invocations

Five release-train-lab.yml runs (2026-07-21T03:59-04:19Z) died on uid-mismatch
against the SHARED /data/omninode/omni_home clones bind-mounted into
omninode-deploy-runner: dubious ownership (128), FETCH_HEAD EACCES (255),
'dev' already checked out in a host worktree (128). The live relief was
exec-applied container state + an uncommitted compose hand-edit -- dropped by
any --force-recreate. This makes the fix committed and recreate-durable:

- docker-compose.runners.yml (deploy runner only): PRIVATE OMNI_HOME via
  DEPLOY_RUNNER_OMNI_HOME (fail-fast :? interpolation), identical
  host:container bind path (docker-outside-of-docker requirement), SHARED
  ${OMNI_HOME} mount REMOVED (shared-clone writes structurally impossible);
  committed root-phase chown init wrapper; reconciled to live reality:
  repo-scoped GITHUB_ORG_URL + explicitly-empty RUNNER_GROUP (repo-scoped
  config.sh rejects --runnergroup); GIT_CONFIG_* safe.directory env retained
  as defense-in-depth, retargeted at the private clones.
- runners/entrypoint.sh: --runnergroup now conditional on non-empty
  RUNNER_GROUP (no-colon default so explicit-empty survives) -- prevents
  bricked re-registration after recreate.
- NEW ensure_runner_clones.sh: idempotent provisioning of the 5 private
  clones (public repos, anonymous https; base URL overridable for tests),
  euid-operability assertion, called from all three entry scripts.
- refresh_stability_lane.sh: git_clone() safe.directory wrapper ported from
  refresh_dev_lane.sh; every bare git -C replaced; ensure call added.
- refresh_dev_lane.sh: ensure call added (wrapper already present).
- cut_release_train_tag.sh: scoped wrapper; execute-mode ensure + fetch
  before tag-name mint; GitHub tag ref now created via gh api
  (repos/.../git/refs) with the workflow token -- private clones carry no
  push credentials (release-train-lab.yml cut-tag job gets
  permissions: contents: write + GH_TOKEN).
- stage_workspace.sh, deploy_source_ref.py, check_sibling_lock_pins.py:
  safe.directory scoping on every git invocation (RT-1 write path no longer
  depends on non-durable container env GIT_CONFIG_* pass-through).
- Seeded-failure tests (tests/unit/scripts/
  test_runner_private_omni_home_safe_directory.py): 13 of 20 RED at
  24ba852 pre-fix, 20 GREEN post-fix -- static no-bare-git-C guards,
  GIT_TEST_ASSUME_DIFFERENT_OWNER behavioral RED/GREEN, compose
  config-as-data recreate-durability assertions, ensure-script behavioral
  suite on file:// fixtures.
- Runbook + workflow header refreshed; recreate procedure documented
  (operator-gated; live container untouched by this PR).

Sibling tag resolution decision (Q2): externally-cut lab tags fail LOUDLY at
RT-1 sibling checkout (private sibling clones cannot resolve them);
runner-cut tags resolve via local tags persisted on the private bind.

Refs OMN-14900 (resume condition 1). Context is referenced by PR number only
(release-train trigger infra#2388; runner listener-liveness infra#2194;
sibling-clone force/mixed-ref follow-up filed off infra#2388) because
deploy-gate treats a bare ticket citation as an evidence binding: this PR's
deploy evidence binds OMN-14900 alone, and its OCC companion is authored in
Codex's lane.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2fafab75-ec78-4b29-8e81-0124a79ab571

📥 Commits

Reviewing files that changed from the base of the PR and between e9a6ae0 and 51c55e2.

📒 Files selected for processing (13)
  • .github/workflows/release-train-lab.yml
  • docker/docker-compose.runners.yml
  • docker/runners/entrypoint.sh
  • docs/runbooks/release-train-lab.md
  • scripts/runtime_build/check_sibling_lock_pins.py
  • scripts/runtime_build/cut_release_train_tag.sh
  • scripts/runtime_build/deploy_source_ref.py
  • scripts/runtime_build/ensure_runner_clones.sh
  • scripts/runtime_build/refresh_dev_lane.sh
  • scripts/runtime_build/refresh_stability_lane.sh
  • scripts/runtime_build/stage_workspace.sh
  • tests/scripts/test_deploy_runtime_build_context.py
  • tests/unit/scripts/test_runner_private_omni_home_safe_directory.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-14900-runner-private-omnihome-safe-directory

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8468/OMN-8524) and do not block merge. Error: all review endpoints [192.168.86.201:8000 192.168.86.201:8001 ] unreachable — preflight short-circuit (no models available)


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical findings No
blocked CRITICAL findings found Yes
degraded All models unavailable (infra) No (pilot)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8468/OMN-8524)

@jonahgabriel
jonahgabriel merged commit c16e76f into dev Jul 23, 2026
147 of 157 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-14900-runner-private-omnihome-safe-directory branch July 23, 2026 00:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant