Skip to content

fix(OMN-17800): the privilege-dropped co-install stops inheriting root's CWD - #3165

Merged
jonahgabriel merged 1 commit into
devfrom
jonah/omn-17800-reconcile-cwd-and-receipt-json
Sep 4, 2026
Merged

jonahgabriel merged 1 commit into
devfrom
jonah/omn-17800-reconcile-cwd-and-receipt-json

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-17800 — the privilege-dropped co-install stops inheriting root's CWD

What

scripts/reconcile-host.sh / scripts/reconcile-workspace-venvs.sh run the workspace
co-install after dropping privileges from root. The dropped child kept root's working
directory (CWD=/root), so uv walked up from /root and tried to read /root/uv.toml,
which the unprivileged user cannot open — the reconcile step failed with a permission
denial that had nothing to do with the workspace being reconciled.

This change makes the privilege-dropped co-install enter the workspace directory itself
rather than inheriting the caller's CWD, and adds scripts/check_reconciler_privilege.py
plus tests/.../test_reconcile_cwd_and_receipt_omn17800.py so the invariant is asserted
rather than assumed.

Why

The failure is deterministic under the root-cron reconcile path: root's CWD is /root,
/root/uv.toml is 0600 root:root, and the dropped user gets EACCES on every run. The
receipt JSON emitted by the reconcile step recorded the failure without naming the cause,
so the same denial had to be re-diagnosed each time.

  • Ticket: OMN-17800
  • Commit: d2771b641
  • Tests: tests/ci/test_reconcile_cwd_and_receipt_omn17800.py (355 lines added) asserts the
    co-install CWD and the receipt-JSON shape.

Evidence-Ticket: OMN-17800
Evidence-Source: OCC#8157

…t's CWD

`runuser -u <owner> -- env HOME=...` changes UID, GID and HOME. It does not
change the inherited working directory. Under the .201 root reconcile cron
that directory is /root at mode 0700, so the provider co-install became the
operator while still standing in root's home, and uv -- which discovers its
configuration by walking UP from the working directory -- refused with

  error: failed to open file `/root/uv.toml`: Permission denied (os error 13)

on 67 consecutive hourly ticks. The co-install is the first step of the venv
repair and forces the lock pass after it, so one unreadable directory took out
venv:omnibase-infra, venv:omnibase-core and venv:omnimarket together -- the
exact three DID_NOT_MOVE surfaces in the live receipt.

It was the only as_owner-wrapped package operation in the file without a `cd`;
lines 406, 589 and 629 were already `(cd "$project" && as_owner ...)`. It is
also the second defect on that line, after OMN-17383 fixed the inherited PATH
there and left the inherited directory.

$OMNI_HOME rather than $INFRA_DIR: this is a `uv pip install`, and from inside
the project uv would newly discover pyproject.toml's [tool.uv]
override-dependencies -- the layer beneath, which this install exists not to
re-resolve. The workspace root carries no uv config on either host.

Second defect, found while proving the first: reconcile-host.sh wrote the
receipt's array separator as sep=",\n". Bash does not interpret \n in a plain
double-quoted assignment, and printf does not interpret escapes in a %s
ARGUMENT, so every receipt this script has produced on BOTH hosts carried a
literal backslash-n and failed json.loads. The existing receipt test missed it
because its workspace yields one surface, and a separator is untested until
something is separated.

check_reconciler_privilege.py gains Part 7, failing the build on any
as_owner-wrapped uv sync or co-install that does not set a working directory.
CLAUDE.md rule 5: the gate ships with the fix it protects.

Red first: 6 failed, 2 passed against origin/dev@4053dc3c0, including the
receipt's JSONDecodeError at the same line-8 signature as the live .201 file.
Green after: 154 passed across all 13 reconciler test files.

Evidence-Ticket: OMN-17800

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hostile Reviewer — adversarial findings (OMN-17492)

Models succeeded: glm-review
Models failed: codex
New finding threads: 0
Deduped (already posted on this PR): 0
Nit-level findings suppressed: 2

The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.

Findings not anchored to a changed file

  • [MAJOR] hostile-reviewer (glm-review)

    Gate detector keys on fragile substrings, not on uv package operations | The new Part 7 check decides whether an as_owner-wrapped line needs a working directory using _UV_INVOCATION.search(...) and " sync" in executable and _INSTALL_INVOCATION.search(...) and "--execute" in executable. These are substring tests against the joined logical line, not a parse of the uv subcommand. A future uv sync --frozen variant matches, but uv pip install without --execute, a uv pip sync, or an install script inv

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MAJOR] hostile-reviewer (glm-review)

    Any occurrence of 'cd' in the line satisfies the working-directory rule | _WORKDIR_SET = re.compile(r"(?<![\w.$-])cd\s") is searched against the whole joined executable line. A line containing cd anywhere (in a quoted string argument, in a dead branch such as x && cd y || as_owner ..., or in a comment that survives joining) passes the check even when the privilege-dropped invocation itself never runs inside a chosen directory. The gate therefore provides weaker protection than the narrative claims, an

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (glm-review)

    Co-install CWD chosen to OMNI_HOME relies on an unverifiable invariant | The fix places the dropped-privilege child in $OMNI_HOME on the argument that 'the workspace root carries no uv configuration on any host'. Nothing in the diff enforces or tests that invariant; if a uv.toml or pyproject.toml later appears in OMNI_HOME, the install silently changes resolution behavior again, exactly the failure mode this change exists to prevent. The gate also accepts any cd target, so a future drift to $INFRA_DIR

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (glm-review)

    Backslash assertion will false-positive on legitimately escaped content | assert "\\n" not in raw rejects any receipt whose JSON encoding contains the two-character sequence backslash-n, which json.dumps produces for any detail string containing a newline or a backslash followed by n (e.g. a Windows-style path or a verbatim error message). The receipt is now valid JSON, and JSON escapes are the normal mechanism; asserting their absence conflates the historical bug with valid encoding. | Evidence: `assert

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (glm-review)

    Mutation test asserts gate message routed to stderr without verifying the contract | test_the_gate_rejects_... asserts 'without setting a working directory' in result.stderr. The gate's main() output stream is not asserted anywhere in this diff; if a refactor moves failure reporting to stdout, the test fails for the wrong reason and the diagnosis cost lands on whoever refactors. The test also depends on the exact wording of a user-facing message, coupling CI to prose. | Evidence: `assert result.returnco

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (glm-review)

    Tests import private helpers from other test modules | The new test module pulls Workspace, _run, _stub, _make_clone, _advance_origin, _lock, _make_uv_shim, and _Workspace from two sibling test files. This makes three modules refactor-locked together; renaming a helper in the OMN-17307 test breaks this file, and pytest collection order/caching assumptions now span modules. The underscore-prefixed names were never a public contract. | Evidence: `from tests.scripts.test_reconcile_host_omn17307

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Critical findings: 0
Major findings: 2
Total findings: 8
Models succeeded: glm-review

Note: Fewer than 2 reviewer models succeeded. Degraded results are informational (OMN-8468/OMN-8524) and do not block merge. Error: cli_review exit 2 (fewer than 2 models succeeded — partial/total outage)


Semantics (OMN-17492 — the model finds, thread resolution gates)

Surface Meaning Blocks merge?
Review threads Per-finding, posted by the reviewer No (informational)
Hostile Review Thread Gate Deterministic: unresolved hostile-reviewer threads exist Fails until resolved (not yet a required context)
degraded verdict Fewer than 2 models succeeded (infra) No

Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review, qwen3-review-b, glm-review (OMN-8468/OMN-8524/OMN-17492)

jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 4, 2026
#8157)

* evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#3165

* evidence: OCC companion self-bind for #8157

---------

Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
@jonahgabriel
jonahgabriel merged commit faab49e into dev Sep 4, 2026
169 of 175 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-17800-reconcile-cwd-and-receipt-json branch September 4, 2026 04:27
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