Skip to content

D62 — Authenticated post-start Autoflow control channel - #84

Draft
LogicDuke wants to merge 20 commits into
mainfrom
feature/d062-post-start-control-channel
Draft

D62 — Authenticated post-start Autoflow control channel#84
LogicDuke wants to merge 20 commits into
mainfrom
feature/d062-post-start-control-channel

Conversation

@LogicDuke

Copy link
Copy Markdown
Owner

Decision 062 implementation.

Authority:

  • Adds the first genuine post-start Autoflow control path.
  • Exposes exactly OPEN_HUMAN_GATE.
  • No generic WorkflowEvent submission.
  • No generic apply(event).
  • No CLOSE_REQUESTED production source.
  • No Git/GitHub/provider/Policy/repository mutation authority.
  • Cockpit remains GET-only/read-only.

Security boundary:

  • Deployment-anchored Windows control store.
  • Runtime/CLI fail-closed verification.
  • Unpredictable per-process named pipe.
  • Mutual HMAC-SHA256 authentication.
  • 4-byte big-endian bounded framing.
  • Required official AgentBridge control CLI.
  • Runtime subprocess authority restricted to absolute System32 whoami.exe and read-only icacls.exe queries only.

Validation before commit:

  • Fresh independent implementation validation: PASS_D062_INDEPENDENT_VALIDATION
  • Focused D062 tests: 96/96
  • Full repository suite: 1987/1987
  • Typecheck: PASS
  • Lint: PASS
  • Build: PASS
  • git diff --check: PASS

Exact validated candidate:

  • base: edaad85
  • head: 2b00c91
  • patch SHA256: 32c6f485f689d997a2195e944ac47e31c30cd8e28168913ebcdf2fb7832772b1
  • patch bytes: 133644
  • files: 21

Deployment remains separately gated.
No ACL provisioning or runtime cutover is part of this PR.

@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 8f12de5b-5bbf-49bd-b9c2-df79a2352316


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.

@LogicDuke
LogicDuke marked this pull request as ready for review September 6, 2026 11:19
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 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-08T13:53:10.077953Z 30fc85e 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: 2b00c91c52

ℹ️ 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 src/control/control-store.ts Outdated
}

// 3. Anchor ACL (read-only).
const icacls = await runProcess(icaclsPath(systemRoot), [anchorPath]);

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 Verify the control-directory owner

When the anchor is owned by another local account but its current DACL lists only the runtime operator and SYSTEM, this verification succeeds because the plain icacls <anchor> output is used only to inspect ACEs and the owner is never queried. A Windows object owner can change its DACL, so that account can subsequently grant itself access, read the descriptor token, and authenticate to the control channel; verify that the owner is also the runtime operator or SYSTEM before accepting the anchor.

Useful? React with 👍 / 👎.

Comment thread src/control/control-runtime.ts Outdated
pipePath,
close: (): Promise<void> =>
new Promise<void>((resolvePromise) => {
removeDescriptorFile(anchorPath, deps.descriptorDeps);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Delete only this server's descriptor

When two runtime instances overlap, the newer instance replaces the fixed descriptor file, but shutting down the older instance unconditionally removes that newer descriptor here. The newer pipe remains live yet the official CLI can no longer discover it; this also occurs during a normal start-before-stop restart. Associate cleanup with the descriptor this handle published and avoid removing the file if it now identifies another process/channel.

Useful? React with 👍 / 👎.

Comment thread src/control/control-store.ts Outdated
Comment on lines +279 to +281
if (/processed\s+\d+\s+files/i.test(line)) {
sawSummary = true;
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept localized successful icacls output

On a non-English Windows installation, icacls localizes its success-summary text, so this English-only regex does not recognize the footer. The footer is then passed to parseAce, which returns null, causing every otherwise valid anchor to be rejected as ACL_UNREADABLE and disabling the control channel. Determine command success from the already-checked exit status or parse the output without requiring an English sentence.

Useful? React with 👍 / 👎.

@LogicDuke
LogicDuke marked this pull request as draft September 6, 2026 11:37
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
LogicDuke and others added 18 commits September 6, 2026 19:29
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
…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
…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
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H47bxbCApT9gJMxkTMkBhf
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H47bxbCApT9gJMxkTMkBhf
…prerequisite

PR93 P2 — document hardened control anchor prerequisite
…-provision

PR92 P2 — add explicit control provisioning step
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_013y7H4Sgp9MxM9WQG4yTBH8
…tection

PR92 P2 — detect required MSVC workload
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_013y7H4Sgp9MxM9WQG4yTBH8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147CEMLP35K39BzWMhPoEgg
…fecycle

D062 — coherent control launch lifecycle reconstruction
…ion) into feature/d062-post-start-control-channel
@LogicDuke
LogicDuke marked this pull request as ready for review September 8, 2026 13:44

@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: 30fc85e195

ℹ️ 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 on lines +462 to +464
if (ace.inherited) {
return { ok: false, reason: CONTROL_ANCHOR_REJECTION.INHERITED_PRINCIPAL };
}

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 Require file-inheritable ACEs before storing the token

When the anchor has direct operator/SYSTEM ACEs without OBJECT_INHERIT_ACE, this check accepts it, but the newly created descriptor does not inherit those restrictions and instead receives the process token's default DACL; mode: 0o600 does not establish an equivalent Windows DACL. If that default DACL includes another local principal, that account can read the token and authenticate to the control pipe. Capture the ACE propagation flags and require suitable file inheritance, or explicitly create and verify a restricted descriptor DACL.

Useful? React with 👍 / 👎.

Comment on lines +212 to +217
/** A canonical OWNER + DACL snapshot as parsed from the native `--acl` helper. */
export interface AclSnapshot {
readonly ownerSid: string;
/** `false` iff the object has a NULL DACL (grants everyone — fail closed). */
readonly daclPresent: boolean;
readonly aces: readonly AclSnapshotAce[];

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 Require the anchor DACL to be protected

The snapshot records whether the DACL is present and which ACEs it currently contains, but not the SE_DACL_PROTECTED control bit. An anchor with direct operator/SYSTEM ACEs but inheritance still enabled therefore passes; if an account able to modify an unverified parent later adds an inheritable ACE, Windows can propagate it into the anchor after startup, allowing that account to read the descriptor token while the server continues using it. Include and validate the protected-DACL state before accepting the anchor.

Useful? React with 👍 / 👎.

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