Skip to content

fix(control): verify Windows control anchor owner (D062 F1) - #85

Draft
LogicDuke wants to merge 7 commits into
feature/d062-post-start-control-channelfrom
repair/pr84-f1-control-anchor-owner
Draft

fix(control): verify Windows control anchor owner (D062 F1)#85
LogicDuke wants to merge 7 commits into
feature/d062-post-start-control-channelfrom
repair/pr84-f1-control-anchor-owner

Conversation

@LogicDuke

Copy link
Copy Markdown
Owner

Isolated F1 repair for PR #84 (Decision 062 Amendment A): the control-anchor gate verified the DACL but not the owner SID, so a foreign owner could rewrite the DACL, grant itself access, and read the descriptor token. verifyControlAnchor now also requires the anchor OWNER SID to equal the exact runtime operator SID (SYSTEM allowed as a DACL principal, never as owner), fail-closed — the owner SID is read by a build-provenanced, hash-verified native helper run through the existing bounded, shell-free runner.

Identity

  • Repair HEAD: 756fb5ecba5ab6140ba6acd51e6f3f48eae16b26
  • Parent (base) SHA: 2b00c91c5217b62d2e238fa28018d43969284694
  • Delta: exactly one commit (fix(control): verify Windows control anchor owner)
  • Validated committed patch SHA256: 13132c0686e167601e96695de4a3f64c10e3fc69a0aefc7c525592a7badb275d (44183 bytes)
  • Base branch: feature/d062-post-start-control-channel (PR D62 — Authenticated post-start Autoflow control channel #84's current head)

Scope guarantees

  • F2 intentionally untouchedsrc/control/control-runtime.ts byte-identical (0c1ab700…182); the older-runtime-close defect is out of scope here.
  • F3 intentionally untouched — the localized icacls parser is unchanged; owner query and DACL query remain separate/non-atomic (TOCTOU preserved, not absorbed).
  • Six D062 protected files unchanged.

Governance

🤖 Generated with Claude Code

https://claude.ai/code/session_01GC2pVoLmjUX5FPLq4urhJT

Decision 062 Amendment A (PR #84 F1). The control-anchor gate verified the
DACL but not the OWNER SID, so a foreign owner could rewrite the DACL, grant
itself access, and read the descriptor token. verifyControlAnchor now also
requires the anchor OWNER SID to equal the exact runtime operator SID
(SYSTEM is allowed as a DACL principal, never as owner), fail-closed.

The owner SID is read by a single source-in-repo native helper built from
reviewed C by a trusted Windows build; its identity and SHA-256 are generated
build metadata (a built JS artifact, not a committed literal or .sha256
sidecar) and the helper bytes are hash-verified before it is executed via the
existing bounded, shell-free runner. This adds one read-only executable
(whoami, icacls, owner helper) and no more.

F2 (control-runtime.ts) and F3 (icacls parser) are unchanged. Full suite
2010/2010; typecheck/lint/build/diff-check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GC2pVoLmjUX5FPLq4urhJT
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: df10fe8e-6552-463d-823f-74a5c296604b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

The real Windows owner-helper positive test assumed mkdtempSync(tmpdir())
yields an operator-owned directory (owner SID == whoami SID). That holds in a
non-elevated context but not on GitHub's elevated Windows runner, where a
freshly created directory is owned by Administrators (or SYSTEM) — a
non-operator SID — so production correctly fails closed and the ok:true
assertion breaks.

The test now reads the temp directory's ACTUAL owner SID via the same real,
build-provenanced helper binary, then asserts the corresponding deterministic
gate behaviour: owner == operator must accept and echo that SID; a non-operator
owner must fail closed with the exact reason (OWNER_IS_SYSTEM for SYSTEM,
OWNER_MISMATCH otherwise). Meaningful in both elevated and non-elevated
contexts, and never treats a foreign owner as success.

Test-only. Production (ownerSid === operatorSid gate) unchanged; F1/F2/F3 and
the six protected files byte-identical. Full suite 2010/2010;
typecheck/lint/build/diff-check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPAMmQpdQbunE8kGbezgih
LogicDuke and others added 2 commits September 6, 2026 20:36
…context

test(control): make owner helper integration context-aware
The control runtime unlinked the fixed runtime-descriptor.json
unconditionally in close() and in the listen-failure cleanup. Under an
overlapped start (runtime B rotates and publishes its descriptor before
runtime A closes), A's cleanup deleted B's descriptor, leaving B's live
pipe undiscoverable by the official CLI. Availability/correctness only;
no authority or token exposure.

Cleanup is now bound to the runtime instance identity: the descriptor is
read and validated through the existing trusted parser and unlinked only
on an exact pipeName match (the per-process 128-bit-random identity; a
pid can be reused, a pipeName cannot). A missing, malformed, unreadable,
or successor-owned descriptor is left untouched, so cleanup fails safe
for the successor in both lifecycle locations. The startup rotation of a
stale crash descriptor is intentionally unchanged.

Read-compare-unlink is not atomic; the residual race narrows from the
successor's whole lifetime to the sub-millisecond match-to-unlink gap
and is not closable with JS fs primitives.

Adds deterministic adversarial tests: A/B overlap survival, missing,
malformed, and unreadable descriptors, same-pid foreign descriptor, and
listen-failure protection of a foreign descriptor alongside own-cleanup.
F1/F3 and the protected files byte-identical. tests/control 126/126
(real owner-helper binary included), full suite 2017/2017;
typecheck/lint/build/diff-check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ZN6c4sZ6k4RSNigL5CWxG
LogicDuke and others added 2 commits September 6, 2026 22:56
…ship

fix(control): preserve successor runtime descriptor
Decision 062 Amendment B (PR #85 F3): replace the localized icacls DACL
read with a single build-provenanced native OWNER + DACL security-descriptor
snapshot emitted as canonical SIDs only, so control-anchor authorization is
identical on any Windows locale. SYSTEM is recognized solely as S-1-5-18 and
the operator by exact canonical SID; a display name can never enter the
decision. F1 owner-only mode and its provenance/hash gate are preserved; F2
is untouched. The deferred P3 (operator effective-rights type/mask semantics)
is intentionally out of scope and not repaired here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KE5bkGWp2jPzaJaLvFhPPu
fix(control): make anchor ACL verification locale-independent
@LogicDuke
LogicDuke marked this pull request as ready for review September 7, 2026 05:57
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T06:01:26.329372Z aaa7ddc Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aaa7ddc4b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread package.json
"cockpit": "npm run build && node dist/cockpit-host/server.js",
"cockpit:live": "npm run build && node dist/runtime/live-cockpit.js",
"control": "npm run build && node dist/control/cli.js",
"helper:build": "node tools/control-owner/build.mjs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Build the mandatory helper in production launch scripts

On a clean Windows checkout, both npm run cockpit:live and npm run control execute only the TypeScript build, while the newly mandatory executable and owner-helper-provenance.js are produced only by this separate script. Consequently, defaultLoadProvenance() returns null and every normal production invocation disables the control channel with HELPER_PROVENANCE_MISSING unless the operator knows to run an undocumented extra build requiring MSVC first. Integrate the helper into the Windows production build/launch or package its generated artifacts.

Useful? React with 👍 / 👎.

Comment thread src/control/control-runtime.ts
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