Skip to content

fix(orchestration): enforce Run-scoped dispatch inspection - #14900

Open
bbingz wants to merge 1 commit into
stablyai:mainfrom
bbingz:fix/14898-dispatch-show-run-scope
Open

bbingz wants to merge 1 commit into
stablyai:mainfrom
bbingz:fix/14898-dispatch-show-run-scope

Conversation

@bbingz

@bbingz bbingz commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

A terminal in Run A could name a task from Run B and read Run B's dispatch metadata. Latest main still reproduces this: the byte-identical 12-case oracle passes only 2 cases. This PR makes the host verify the real caller and scope the lookup to the caller's Run (or exact settled Dispatch), so foreign and nonexistent tasks look the same.

Root cause

orchestration.dispatchShow looked up a task/dispatch by task ID before establishing caller authority. A caller-supplied terminal handle was also insufficient on its own because it could be spoofed, stale, or reminted across a runtime restart.

Fix

  • Attest terminal callers with launch token, pane, process incarnation, and host/runtime identity before any Task or Dispatch lookup.
  • Let coordinators inspect only their bound Run.
  • Let settled workers inspect only their exact persisted Dispatch identity.
  • Return dispatch: null for both foreign and absent reads; return the same task_not_found shape for foreign and absent preambles.
  • Keep trusted identity-free presentation limited to local Electron IPC and authenticated paired-runtime presentation.
  • Use compound (task_id, task.run_id) lookup for trusted presentation so a mismatched persisted Task/Dispatch row cannot cross Runs.
  • Route CLI, renderer, lifecycle, paired/headless, and legacy settlement call paths through the authoritative host boundary.

This is deliberately bounded Run isolation on one host. It is not remote privilege escalation, file access, or credential exposure.

Why this boundary

Authorization lives at the authoritative Run-scoped database/RPC lookup rather than in CLI presentation. Caller-supplied handles grant no authority, and invalid evidence fails before lookup. Empty/not-found semantics match neighboring read APIs while avoiding an existence oracle.

No RPC method, required field, result shape, or stream opcode changes. The existing caller field remains additive and optional, consistent with docs/reference/remote-wire-compatibility.md.

Deterministic reproduction

Oracle blob: 098dc85e769309181b9e9d8e3479210bdefba2a0

pnpm exec vitest run --config config/vitest.config.ts \
  src/main/runtime/rpc/methods/orchestration-dispatch-show-run-scope.test.ts

The same 12-case oracle covers same-Run success, cross-Run/absent equivalence, foreign/absent preambles, unknown caller/no Run, malformed and stale evidence with zero lookups, persisted Task/Dispatch Run mismatch, settled Dispatches, caller rebind, mixed-version omission, independent concurrent callers, and unchanged persisted records.

Build Result
Latest origin/main 6ee265e579 + test-only oracle 2/12 passed, 10 failed
Candidate 478880cd94 12/12 passed
Candidate with caller-attestation hardening disabled 5/12 passed, 7 failed

A real paired/headless Electron journey also creates two independent Runs with real terminal identities: same-Run dispatch-show succeeds, Run A cannot observe Run B, and host persistence remains unchanged.

Validation

  • Focused authority/CLI/neighbor suite after merging latest main: 141/141 passed.
  • Rebuilt Electron E2E batch: 7/7 passed (paired/headless isolation, missing-worker recovery, both legacy restart contracts, low-level release, compiled-CLI settlement, worker visibility).
  • pnpm lint: passed, including 86 reliability gates and the max-lines ratchet.
  • pnpm typecheck:cli and pnpm typecheck:node: passed. The full renderer typecheck remains blocked by unrelated latest-main fixture errors in src/renderer/src/components/tab-bar/open-tab-search-retention.test.ts.
  • git diff --check: clean.

One neighboring retirement/resume E2E consistently reaches and passes the trusted dispatch read, then times out later mounting a fallback terminal. The unmodified spec fails identically at the same PaneManager line on latest main; both candidate close modes were run independently and reproduce that unrelated existing failure.

Compatibility and risk

  • macOS validation is complete; the implementation contains no path, shell, provider-specific, or stream-opcode behavior and retains Windows/Linux/SSH/folder-workspace paths.
  • New CLI clients preflight orchestration.dispatch-show-run-scope.v1 and fail closed before sending the request to an older host that would drop the caller field. New hosts advertise this capability; old clients/hosts remain outside the fixed authority contract until updated.
  • New hosts support old clients through existing attested compatibility evidence when the optional caller field is absent.
  • Added work is bounded to caller attestation plus scoped indexed lookup; there is no filesystem, network, terminal-list, or polling fanout.

Review

Three independent GPT-5.6 Luna reviews completed clean final rounds:

  1. authorization boundary, information disclosure, and adversarial cross-Run access;
  2. RPC/wire compatibility, SSH/paired/headless/cross-platform behavior;
  3. test non-vacuity, races, regression risk, performance, and scope.

Validated findings fixed: compound trusted-presentation lookup, raw identity-free lifecycle callers, reliability wording, zero-lookup proof including the legacy lookup, and explicit trusted renderer IPC in worker visibility E2E. The old-host preflight finding was validated and fixed with an explicit runtime capability fence; it now fails closed before the caller-scoped read is sent. CodeRabbit's Windows-invalid /tmp/repo fixture finding is resolved.

Fixes #14898. Related: #14891, #14892, and STA-4459.

Checklist

  • Non-draft and unmerged
  • Current with main
  • Automated red/green/disabled proof
  • Paired/headless and lifecycle E2E evidence
  • Cross-platform, SSH, folder-workspace, and mixed-version behavior audited
  • Independent review findings validated and addressed

AI disclosure

OpenAI Codex assisted with reproduction, implementation, review, and validation. The final diff and evidence were inspected before handoff.

@coderabbitai

coderabbitai Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

orchestration dispatch-show now authenticates caller identity and scopes task and dispatch lookup to the caller’s current Run. Trusted desktop IPC and trusted renderer paths retain identity-free presentation access. CLI and worker settlement flows pass terminal handles for caller scoping. Runtime capability checks reject unsupported versions before requests are sent. Database stores support Run and caller-identity lookup. Tests and reliability gates cover isolation, rebinding, attestation, compatibility, and presentation flows.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation addresses issue #14898 by authenticating callers and enforcing Run-scoped or exact-Dispatch lookup with indistinguishable foreign and absent results.
Out of Scope Changes check ✅ Passed The production, compatibility, test, E2E, and reliability-gate changes directly support Run-scoped dispatch authorization and its validation.
Description check ✅ Passed The description clearly covers the problem, fix, scope, linked issue, testing, compatibility, risks, review, and AI disclosure.
Title check ✅ Passed The title clearly and concisely describes the main change: enforcing Run-scoped dispatch inspection.

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 78c4bf49-1f9c-4a17-9a80-38a39f7eb4ac

📥 Commits

Reviewing files that changed from the base of the PR and between e4e54a1 and c8b46454f4fe006d2394963fad3ca93e609775e0.

📒 Files selected for processing (8)
  • src/cli/handlers/orchestration-dispatch-show-scope.test.ts
  • src/cli/handlers/orchestration-lifecycle-rejection.test.ts
  • src/cli/handlers/orchestration-worker-settlement.ts
  • src/cli/handlers/orchestration.test.ts
  • src/cli/handlers/orchestration.ts
  • src/cli/specs/orchestration.ts
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts
  • src/main/runtime/rpc/methods/orchestration.ts
💤 Files with no reviewable changes (1)
  • src/cli/handlers/orchestration.test.ts

Included review availability: Your plan includes up to 10 reviews per rolling hour; 7 remain after this review.

@bbingz

bbingz commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Jinwoo-H Jinwoo-H changed the title fix(orchestration): scope dispatch-show to caller Run fix(orchestration): enforce Run-scoped dispatch inspection Aug 16, 2026
@Jinwoo-H

Copy link
Copy Markdown
Contributor

Final owner validation on 478880cd94 (merged with origin/main@1e63cfef06): the byte-identical oracle 098dc85e769309181b9e9d8e3479210bdefba2a0 is 2/12 on latest main → 12/12 candidate → 5/12 with attestation hardening disabled. Post-merge validation is 141/141 focused tests, 7/7 rebuilt Electron journeys, plus clean lint, typecheck, reliability manifest, max-lines ratchet, and diff check.

Three independent Luna review scopes finished clean after validated fixes for trusted-presentation compound lookup, identity-free lifecycle callers, zero-lookup proof, and renderer IPC coverage. The completed-worker retirement spec's later PaneManager mount failure reproduces unchanged on latest main; both candidate close modes first passed the new trusted dispatch read, so it is documented as a pre-existing neighboring failure rather than masked here. The PR remains non-draft and unmerged; CI on this pushed head is the remaining gate.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/runtime/orca-runtime.ts (1)

13311-13338: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a short comment explaining the remint gate.

The reminting block (deriving a fresh handle from claimedPaneKey, then adopting it only when the reminted authority's paneKey matches) has no inline explanation. Every other non-obvious block in this file carries a one-line // Why: comment. Static analysis also flags this segment's complexity as high.

Add a brief // Why: comment stating that the remint is safe because launchTokenHash is still checked against whichever terminal ends up resolved, so a caller cannot widen its authority by supplying an arbitrary claimedPaneKey. Consider extracting the remint lookup into a small private helper (e.g., resolveRemintedOrchestrationTerminal(claimedPaneKey)) to keep verifyOrchestrationCompatibilityCaller itself shorter.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a831c3c1-bb4f-480e-919e-c84f61f5a680

📥 Commits

Reviewing files that changed from the base of the PR and between 0cc1f02babb1a19388be6df1a8b65b5f3eaa8605 and 478880cd946af7f799506ec07a0d9806ba5b6adc.

📒 Files selected for processing (20)
  • config/reliability-gates.jsonc
  • src/main/ipc/runtime.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/orchestration-compatibility-authority.test.ts
  • src/main/runtime/orchestration/db.ts
  • src/main/runtime/rpc/core.ts
  • src/main/runtime/rpc/dispatcher.ts
  • src/main/runtime/rpc/methods/orchestration-check.test.ts
  • src/main/runtime/rpc/methods/orchestration-dispatch-show-run-scope.test.ts
  • src/main/runtime/rpc/methods/orchestration-manual-dispatch-release.test.ts
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts
  • src/main/runtime/rpc/methods/orchestration.ts
  • tests/e2e/completed-worker-retirement-resume.spec.ts
  • tests/e2e/orchestration-dispatch-presentation.ts
  • tests/e2e/orchestration-dispatch-show-run-isolation.spec.ts
  • tests/e2e/orchestration-legacy-worker-missing-terminal-recovery.spec.ts
  • tests/e2e/orchestration-legacy-worker-restart-recovery.spec.ts
  • tests/e2e/orchestration-low-level-dispatch-release.spec.ts
  • tests/e2e/orchestration-worker-settlement-release-cli.spec.ts
  • tests/e2e/orchestration-worker-terminal-visibility.spec.ts

Included review availability: Your plan includes up to 10 reviews per rolling hour; 6 remain after this review.

@bbingz

bbingz commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@Jinwoo-H

Copy link
Copy Markdown
Contributor

Owner revalidation on rebased head 5527d66d43 (base origin/main@6ee265e579):

  • Fixed the validated mixed-version finding: orchestration.dispatchShow now preflights orchestration.dispatch-show-run-scope.v1 and fails closed before an older host can drop callerTerminalHandle.
  • Fixed the worker-settlement read regression by forwarding receipt.fromHandle; the manual context-only test now explicitly models trusted desktop IPC.
  • Strengthened malformed-caller zero-lookup and queued concurrent-caller coverage.
  • Validation: 12/12 deterministic isolation oracle; 798 orchestration/CLI tests; paired/headless isolation E2E passed; CLI and Node typechecks passed; git diff --check passed. Full renderer typecheck still has unrelated latest-main fixture errors in src/renderer/src/components/tab-bar/open-tab-search-retention.test.ts.
  • Three independent gpt-5.6-luna reviewers completed the final round: CLEAN, with all findings validated and addressed.

PR remains non-draft, open, unmerged, and current with main.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f02edb61-3b69-4070-a53d-fd371f95a920

📥 Commits

Reviewing files that changed from the base of the PR and between 6ee265e and 5527d66d4324751f77156e566deab9c7338caf84.

📒 Files selected for processing (30)
  • config/reliability-gates.jsonc
  • src/cli/handlers/orchestration-dispatch-show-scope.test.ts
  • src/cli/handlers/orchestration-worker-settlement.ts
  • src/cli/handlers/orchestration.test.ts
  • src/cli/handlers/orchestration.ts
  • src/cli/runtime-client.test.ts
  • src/cli/runtime/client.ts
  • src/cli/specs/orchestration.ts
  • src/main/ipc/runtime.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/orchestration-compatibility-authority.test.ts
  • src/main/runtime/orchestration/db/dispatch-context/dispatch-context-store.ts
  • src/main/runtime/orchestration/db/tasks/task-store.ts
  • src/main/runtime/rpc/core.ts
  • src/main/runtime/rpc/dispatcher.ts
  • src/main/runtime/rpc/methods/orchestration-check.test.ts
  • src/main/runtime/rpc/methods/orchestration-dispatch-show-run-scope.test.ts
  • src/main/runtime/rpc/methods/orchestration-manual-dispatch-observation.test.ts
  • src/main/runtime/rpc/methods/orchestration-manual-dispatch-release.test.ts
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts
  • src/main/runtime/rpc/methods/orchestration.ts
  • src/shared/protocol-version.ts
  • tests/e2e/completed-worker-retirement-resume.spec.ts
  • tests/e2e/orchestration-dispatch-presentation.ts
  • tests/e2e/orchestration-dispatch-show-run-isolation.spec.ts
  • tests/e2e/orchestration-legacy-worker-missing-terminal-recovery.spec.ts
  • tests/e2e/orchestration-legacy-worker-restart-recovery.spec.ts
  • tests/e2e/orchestration-low-level-dispatch-release.spec.ts
  • tests/e2e/orchestration-worker-settlement-release-cli.spec.ts
  • tests/e2e/orchestration-worker-terminal-visibility.spec.ts
💤 Files with no reviewable changes (1)
  • src/cli/handlers/orchestration.test.ts
🚧 Files skipped from review as they are similar to previous changes (20)
  • src/main/runtime/rpc/methods/orchestration-check.test.ts
  • src/main/runtime/rpc/core.ts
  • src/cli/specs/orchestration.ts
  • src/cli/handlers/orchestration.ts
  • tests/e2e/completed-worker-retirement-resume.spec.ts
  • src/main/runtime/rpc/methods/orchestration-manual-dispatch-release.test.ts
  • src/main/runtime/rpc/dispatcher.ts
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts
  • tests/e2e/orchestration-legacy-worker-missing-terminal-recovery.spec.ts
  • tests/e2e/orchestration-legacy-worker-restart-recovery.spec.ts
  • src/cli/handlers/orchestration-dispatch-show-scope.test.ts
  • tests/e2e/orchestration-worker-terminal-visibility.spec.ts
  • src/main/runtime/orca-runtime.ts
  • config/reliability-gates.jsonc
  • src/main/runtime/orchestration-compatibility-authority.test.ts
  • tests/e2e/orchestration-dispatch-presentation.ts
  • src/main/runtime/rpc/methods/orchestration.ts
  • src/main/ipc/runtime.ts
  • src/main/runtime/rpc/methods/orchestration-dispatch-show-run-scope.test.ts
  • tests/e2e/orchestration-low-level-dispatch-release.spec.ts

Included review availability: Your plan includes up to 10 reviews per rolling hour; 4 remain after this review.

Comment thread src/cli/runtime/client.ts
@@ -41,7 +42,7 @@ export class RuntimeClient {
private readonly remotePairing: PairingOffer | null
private readonly environmentSelector: string | null
private readonly remoteCompat: RemoteRuntimeCompatGate
private orchestrationContractCheck: Promise<void> | null = null
private orchestrationContractCheck: Promise<RuntimeStatus> | null = null

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not cache the dispatch-show capability preflight.

orchestrationContractCheck can describe a previous runtime instance. If the host changes after this cache is populated, orchestration.dispatchShow can reach an older host without checking ORCHESTRATION_DISPATCH_SHOW_SCOPE_RUNTIME_CAPABILITY. That host can drop callerTerminalHandle and restore the cross-Run disclosure path.

Run a fresh status.get capability check for each orchestration.dispatchShow call. Keep the cache for mutations if needed. Add a regression test that replaces a compatible host with an older host between two calls from the same RuntimeClient.

Proposed fix
 private async ensureOrchestrationContractCompatible(
   timeoutMs: number,
   requireDispatchShowScope = false
 ): Promise<void> {
-  if (!this.orchestrationContractCheck) {
-    this.orchestrationContractCheck = this.checkOrchestrationContractCompatibility(timeoutMs)
-  }
-  const status = await this.orchestrationContractCheck
+  const status = requireDispatchShowScope
+    ? await this.checkOrchestrationContractCompatibility(timeoutMs)
+    : await (this.orchestrationContractCheck ??=
+        this.checkOrchestrationContractCompatibility(timeoutMs))
   if (requireDispatchShowScope) {

Also applies to: 77-81, 198-207

@nwparker nwparker removed the P1 label Aug 19, 2026
@bbingz

bbingz commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the revalidation. Per your ownership of #14900, I’m leaving the branch untouched and will not rebase or push; the remaining gate is CI on 5527d66d4324751f77156e566deab9c7338caf84.

@bbingz

bbingz commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Acknowledged the unresolved capability-preflight security finding on the current head 5527d66d4324751f77156e566deab9c7338caf84. Per the maintainer handoff already recorded on this PR, I am leaving #14900 untouched: no rebase, code changes, or push from my side. Jinwoo-H owns the remaining security review and CI gate.

@bbingz

bbingz commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Acknowledged on the current head 5527d66d4324751f77156e566deab9c7338caf84. This is a security/auth finding; Jinwoo-H owns #14900 and its remaining review/CI gate. Per the maintainer handoff, I am leaving the branch untouched (no code changes, rebase, or push) and will not self-dismiss the finding.

@bbingz
bbingz force-pushed the fix/14898-dispatch-show-run-scope branch from 5527d66 to 02c35e2 Compare September 20, 2026 11:55
@bbingz

bbingz commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

@Jinwoo-H a correction I owe you. On 09-20 a branch refresh of mine ported your validated series (13 commits ending at 5527d66d43) onto main's restructured orchestration files and squashed it into one commit, 02c35e27b7, under my name with no co-author credit. That went against my 08-21 note that I wouldn't push here. The squash carries the same change set moved to the new file paths, and your original series still exists. If you want your commits back, either re-split onto current main or as a Co-authored-by trailer, tell me which and I'll do it. I won't push anything here until you say.

This branch has not been deployed

No deployments
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.

[Bug]: orchestration.dispatchShow returns another Run's dispatch context without a caller check

5 participants