Skip to content

fix(evaos): fail closed on incomplete staging signer#709

Merged
100yenadmin merged 1 commit into
evaos/beta-rc-20260612from
codex/v2136-staging-signer-fail-closed
Jul 15, 2026
Merged

fix(evaos): fail closed on incomplete staging signer#709
100yenadmin merged 1 commit into
evaos/beta-rc-20260612from
codex/v2136-staging-signer-fail-closed

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Pull Request

Description

PR #708 merged the v2.1.36 signed Mac-control and selected-binding contracts, but a post-merge exact-head review found one P2 gap: explicit staging canary mode with none of the four signer settings could still rewrite and restart the connector LaunchAgent before failing later.

This superseding one-commit fix makes explicit staging mode require the complete signer environment before any plist write or launchctl call. Non-staging connector startup remains unchanged.

Related Issues

Type of Change

  • fix - Bug fix (non-breaking change which fixes an issue)
  • feat - New feature (non-breaking change which adds functionality)
  • perf - Performance improvement
  • refactor - Code restructuring (no behavior change)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • docs - Documentation update

Atomic PR Checklist (Rule 1)

  • This PR contains exactly one feature or bug fix that cannot be further decomposed
  • The PR title follows Conventional Commit format: <type>(<scope>): <subject> in English

Local Checks (Rule 2)

  • bun run format / oxfmt --check - formatting passes
  • bun run lint - 0 errors
  • bunx tsc --noEmit - passes
  • bunx vitest run - 301 files passed, 1 skipped; 2,812 tests passed, 3 skipped
  • i18n validated - passes; no i18n-sensitive files changed
  • New or changed user-facing text uses i18n keys - N/A; no user-facing text changed
  • git diff --check - no whitespace errors

Coverage note: one optional full coverage run hit the pre-existing 10-second dynamic-import timeout in PreviewPanel.dom.test.tsx; that test passed immediately in isolation (3/3) and the ordinary full suite passed twice. This PR does not touch preview code or coverage configuration.

Runtime Verification

  • Verified on macOS as an installed signed/notarized app
  • Verified on Windows
  • Verified on Linux
  • I have performed a self-review of my own code

Source-level regression proof on macOS:

  • Merged base 5c86e8e91660772da5b1b6f49b43f2de3afee737: explicit staging mode with zero signer settings returned an empty environment.
  • Superseding head f92d45f984db29c132e65f458df85567f04186ca: the same input raises a sanitized incomplete-configuration error before plist or launchctl mutation.
  • Focused receipt connector test passes 2/2.

Agent Handoff

  • Source repos: canonical 100yenadmin/evaOS-GUI only.
  • Systems touched: v2.1.36 Workbench bundled Desktop Bridge source and its focused unit contract.
  • Modules/files:
    • resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py
    • tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts
  • Exact lineage:
  • Contracts Mac Access must inherit:
    • Workbench/connector ownership remains com.evaos.workbench and the existing bundled bridge for v2.1.36; this PR creates no standalone identity.
    • Selected-binding authority is broker-selected and must arrive through the ws-proxy callback; the connector/OpenClaw side must not mint caller authority.
    • ws-proxy supplies the signed execution context; OpenClaw and Desktop Bridge verify it.
    • The selected Mac connector signs the runtime receipt/public attestation.
    • Explicit staging mode is fail-closed: all four context/receipt signer settings are required before LaunchAgent mutation.
    • Production signer remains disabled; staging signer authority must remain isolated.
    • Candidate binding includes exact GUI source commit, vendored bridge source digest, app version/build, bundle identity, and active packaged connector process.
    • Runtime receipt route remains gateway-authenticated, POST-only, exact-route/strict-body, replay/expiry/binding checked, and sanitized.
    • Release proof keeps installed-app local-control canaries separate from signed proxy-runtime receipt proof; both are required.
  • Dependencies:
  • Non-goals: no packages/mac-access, no packages/mac-connector-core, no com.evaos.mac-access* identities, no standalone helper ownership/pairing, and no Workbench-as-client refactor.
  • Mutation boundary: source branch and PR only; no merge, tag, publication, distribution, runtime, or customer mutation.
  • Proof path: this PR checks; PR fix(evaos): require signed Mac-control runtime proof #708 review/thread history; v2.1.36 release evidence packet under the existing release-owner lane.
  • Rollback: revert f92d45f984db29c132e65f458df85567f04186ca; no data migration or external state rollback.
  • Mac Access: freeze architecture, identities, and connector-core boundary #699/docs(mac-access): freeze standalone connector architecture #707 refresh: safe to refresh contract analysis from this head after CI and current-head review are green; do not treat that refresh as permission to absorb Workbench ownership or as runtime/release proof.
  • Confidence gate:
    • Primitive canary
    • Scenario canary
    • Negative-path proof
    • Adversarial replay
    • Takeover packet

Screenshots

N/A. No UI change.

Additional Context

PR #708 is already merged. This PR exists solely to close the exact post-merge P2 without expanding into the separately owned Mac Access v0.1 implementation.

No merge, tag, release, or publication is requested by this PR.

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation for Mac-control canary configuration to reject incomplete environment settings.
    • Prevented launch attempts when signer configuration is incomplete, avoiding creation of invalid user settings.
  • Tests

    • Added coverage confirming incomplete staging configuration fails safely without launching processes or creating configuration files.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 520eab55-61d2-4d63-83cf-97c6576330da

📥 Commits

Reviewing files that changed from the base of the PR and between 5c86e8e and f92d45f.

📒 Files selected for processing (2)
  • resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py
  • tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Build Test (macos-arm64)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Name utility files using camelCase, such as formatDate.ts.
Prefix unused parameters with _.
Format code with Oxfmt using Prettier-compatible rules: inline single-element arrays that fit on one line, require trailing commas in multiline arrays and objects, and use single quotes for strings.

Files:

  • tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use strict TypeScript; do not use any and do not leave implicit returns.
Use the path aliases @/*, @process/*, and @renderer/*.
Prefer type over interface according to the Oxlint configuration.
Write code comments in English and use JSDoc for public functions.

Files:

  • tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest 4 for tests and maintain at least 80% coverage.

Files:

  • tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts
🪛 ast-grep (0.44.1)
tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFileSync } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🔇 Additional comments (2)
resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py (1)

3330-3332: LGTM!

tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts (1)

50-65: LGTM!


📝 Walkthrough

Walkthrough

The bridge now rejects incomplete Mac-control canary configuration, including empty environment sets. Tests cover the mode-only staging failure, absence of plist and launchctl side effects, and the existing successful staging flow.

Changes

Canary configuration validation

Layer / File(s) Summary
Strict environment validation and test coverage
resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py, tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts
The connector requires the complete canary environment key set. Tests verify that mode-only configuration raises RuntimeError without creating a plist or invoking launchctl, then validate the complete staging configuration.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested labels: evaos, area:native-companion, risk:security

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: staging signer startup now fails closed when configuration is incomplete.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/v2136-staging-signer-fail-closed

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

@100yenadmin

Copy link
Copy Markdown
Owner Author

@codex review exact head f92d45f; report only release-relevant P0-P2 findings. @copilot review exact head f92d45f. @coderabbitai review exact head f92d45f; report only release blockers.

@evaos-code-review-bot

evaos-code-review-bot Bot commented Jul 15, 2026

Copy link
Copy Markdown

evaOS review status: completed

PR: #709 - fix(evaos): fail closed on incomplete staging signer
Head: f92d45f984db29c132e65f458df85567f04186ca
Updated: 2026-07-15T10:15:14.387Z

evaOS review completed for this PR head.

Automation note: agents should wait for this comment to reach completed, stale_head, closed_or_merged_before_review, skipped, or failed before treating evaOS review as settled for this head. provider_deferred means evaOS still intends to retry.

PR URL: #709

Review URL: #709 (review)

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
git fetch origin f92d45f984db29c132e65f458df85567f04186ca --depth=5 2>&1 | tail -20
git checkout f92d45f984db29c132e65f458df85567f04186ca 2>&1 | tail -5
echo "---FILE---"
fd cli.py resources/evaos-beta/bridge/src/evaos_desktop_bridge/ 2>/dev/null
cat -n resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py | sed -n '1,400p'

Length of output: 23175


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n -i "staging\|signer" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py | head -80

Length of output: 319


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1750,1950p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 9446


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "CONNECTOR_MAC_CONTROL_CANARY_ENV_KEYS\|CONNECTOR_MAC_CONTROL_CANARY_MODE_ENV_KEY\|CONNECTOR_MAC_CONTROL_CANARY_MODE\b\|_mac_control_canary\|incomplete_configuration\|_write_connector_plist\|launchctl" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 4183


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '3310,3400p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py
echo "---write_connector_plist calls---"
grep -n "_write_connector\|def _write_plist\|plistlib.dump\|plist_path.write\|def _connector_plist\|def _launchctl_start\|_connector_service_start\b" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 3675


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '3260,3315p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py
echo "---callers of _ensure_connector_plist / start---"
grep -n "_ensure_connector_plist\|def _connector_service_status\|def _connector_service_start\|connector_service.start\|_ensure_connector_plist(" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 2735


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "_ensure_connector_user_plist" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 408


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '2100,2170p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py
echo "---"
sed -n '2745,2762p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 3481


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "_run_public_connector_service\|except RuntimeError\|except Exception as exc" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py | head -60

Length of output: 734


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1010,1070p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 2933


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "^def entrypoint\|^def main\|def _dispatch\|def run_cli" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 337


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '766,915p' resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 6834


🏁 Script executed:

#!/bin/bash
set -euo pipefail
fd evaosDesktopBridgeReceipt.test.ts
cat -n tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts | sed -n '1,200p'

Length of output: 9153


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "CONNECTOR_SYSTEM_PLIST" resources/evaos-beta/bridge/src/evaos_desktop_bridge/cli.py

Length of output: 434


Only read via _connector_plist_path() (status lookup); no separate write path. Fix is scoped correctly — single write path (_ensure_connector_user_plist) is gated.

@100yenadmin Reviewed exact head f92d45f984db29c132e65f458df85567f04186ca. No release blockers found.

Verification of the fail-closed fix:

  • _connector_mac_control_canary_environment() (Line 3323) raises RuntimeError with a sanitized message (missing key names only — never values) when EVAOS_MAC_CONTROL_CANARY_MODE=staging is set but any of the four signer keys are absent.
  • This call is inlined inside _connector_plist_payload()'s dict comprehension (Line 3336), so the exception fires before the payload dict is even constructed.
  • _ensure_connector_user_plist() (Line 3287) builds that payload before calling CONNECTOR_USER_PLIST.write_bytes(...) — so the exception blocks the write.
  • _launchctl_start() (Line 2752) calls _ensure_connector_user_plist() first, before bootout/bootstrap/kickstart — so the exception blocks all three launchctl invocations too.
  • The exception surfaces through _run_public_connector_servicemain()'s generic exception handler (~Line 858), which converts it into a sanitized command_failed JSON error envelope rather than crashing/leaking a raw traceback.
  • Confirmed there's only one plist-write path (CONNECTOR_USER_PLIST); CONNECTOR_SYSTEM_PLIST is read-only in this file, so there's no bypass route around the new gate.
  • The added test tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts (Lines 9-112) covers all four combinations (no signer, mode-only, full signer, partial signer) and explicitly asserts the error message doesn't leak a provided key value — matches the code behavior.

Non-staging startup paths are untouched (mode != CONNECTOR_MAC_CONTROL_CANARY_MODE short-circuits to {} at Line 3326), consistent with the PR's stated scope.

No P0-P2 findings to report.

✅ Action performed

Review finished.

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.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: f92d45f984

ℹ️ 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".

@coderabbitai coderabbitai Bot added area:native-companion Native macOS companion boundary evaos evaOS public beta R&D work risk:security Security, auth, secrets, permission risk labels Jul 15, 2026

@evaos-code-review-bot evaos-code-review-bot 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.

Walkthrough

PR: #709 - fix(evaos): fail closed on incomplete staging signer
Head: f92d45f984db29c132e65f458df85567f04186ca into evaos/beta-rc-20260612. Review event: COMMENT.
Provider: GLM/Z.ai through ZCode (zcode-glm, zcode, model GLM-5.2).

Estimated review effort: 1/5 (~12 min)

Changed Files

File Status Churn Purpose Risk
tests/unit/evaos/evaosDesktopBridgeReceipt.test.ts modified +15/-1 Test coverage Low

Review Signal

No validated inline findings.
Dropped findings before posting: 0. High-severity findings: 0.

Risk Taxonomy

No finding categories.

Validation and Proof

1 required validation/proof recommendation(s) selected from changed files.

  • required: TypeScript/web build or CI proof - Runtime TypeScript/web files or package/config files changed. Proof: npm run build; typecheck; focused Vitest; green GitHub check.
    Proof status: sufficient - PR metadata mentions acceptable proof for each required validation recommendation.
    Profile validation hints: Do not ask for broad local suites when remote CI or fast-smoke proof is the right gate.
    Profile proof expectations: Look for focused app smoke, packaged resource checks, or CI artifact proof when relevant.

Related Context

Related issues/PRs: #708, #699, #707, #236, #349.
Suggested labels: tests.
Suggested reviewers: none from current metadata.

Review Settings Preview

  • Profile: assertive
  • Enabled sections: Review summary (inline_review); Walkthrough (inline_review); Changed-files table (walkthrough); Effort estimate (walkthrough); Related issues/PRs (walkthrough); Suggested labels (suggestion_only); Review status comment (sticky_status)
  • Path instructions: apps/eva-desktop-mac/** - Check macOS identity, helper path, TCC identity, and packaged resource shape risk.
  • Path instructions: scripts/** - Treat release, packaging, and artifact-shape changes as high risk.
  • Label suggestions: workbench, macos, regression-hardening
  • Reviewer suggestions: none
  • Suggestion behavior: suggestions only; labels and reviewers are not auto-applied.
  • Roadmap-only settings: auto-apply labels; auto-request reviewers; required status checks

Pre-merge checklist

  • Inline comments target current RIGHT-side diff lines.
  • No secret-like content survived into posted inline comments.
  • REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
  • Required behavior proof is present or not applicable.
  • Labels and reviewers are suggestions only; the bot did not auto-apply them.

@100yenadmin

Copy link
Copy Markdown
Owner Author

评审结论

✅ 通过 — 已审查精确 head f92d45f

  • 修复范围严格限定为显式 staging 模式的完整 signer 配置校验及对应回归测试;未引入 Mac Access 提取、独立 identity 或 helper ownership。
  • mode-only 与 partial-signer 输入会在 plist 写入及 launchctl 调用前失败;非 staging 启动行为不变。
  • 最新 PR Checks 全绿:macOS build/install smoke、unit、coverage、code quality、OpenClaw plugin contract、i18n、release script。
  • CodeRabbit 已批准;Codex 与 evaOS exact-head review 均无 P0-P2;review threads 为 0;GitHub 状态 CLEAN / APPROVED。
  • 本结论只证明 source checkpoint merge-ready,不构成 signed/notarized installed-app、isolated-staging、live Mac-control、RC 或发布证明。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:native-companion Native macOS companion boundary evaos evaOS public beta R&D work risk:security Security, auth, secrets, permission risk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant