Skip to content

feat(agents): enforce trusted heartbeat source preflight - #5602

Open
Greg-Moskalenko wants to merge 2 commits into
block:mainfrom
Greg-Moskalenko:build/trusted-heartbeat-preflight-v2
Open

feat(agents): enforce trusted heartbeat source preflight#5602
Greg-Moskalenko wants to merge 2 commits into
block:mainfrom
Greg-Moskalenko:build/trusted-heartbeat-preflight-v2

Conversation

@Greg-Moskalenko

@Greg-Moskalenko Greg-Moskalenko commented Aug 11, 2026

Copy link
Copy Markdown

Summary

  • add a typed, owner-authoritative heartbeat preflight designation to managed agents, require it through the post-create update path once the agent pubkey exists, and preserve it through update, snapshot, restore, stop, delete, and rollback paths
  • run a trusted gateway capability before a designated heartbeat can reach the model, fail closed on missing, blocked, stale, malformed, or replayed source receipts, and keep expected preflight blocks from churning healthy ACP sessions
  • bind the macOS heartbeat harness to a protected installation path, exact executable identity, expected Developer ID team, hardened runtime, empty entitlements, and capability readback
  • harden release and signed-canary workflows so the exact ZIP/DMG artifact is verified before execution and remains bound through packaging and publication

The bug this addresses is structural: prompt text can ask an agent to call every source, but it cannot prove those calls happened before the agent reports a no-op. This change moves that decision to a pre-agent runtime gate and makes incomplete source coverage suppress the model turn.

Related issue

None found. I searched open issues and PRs for heartbeat preflight and source attestation. #4983 is related scoped native-access/delivery work, but it does not provide this source-receipt gate; #5533 concerns heartbeat thread guidance rather than source execution.

Key safety properties

  • designated runs require a fresh harness invocation ID and the exact configured gateway capability
  • the model sees only committed, sanitized gateway results after the preflight accepts them
  • a normal blocked preflight returns the claimed agent to the pool without a respawn, session loss, or crash-history mutation
  • helper descendants are terminated on every Unix terminal outcome; unsupported platforms reject the designation fail-closed
  • concurrent restore/update/start/stop/delete/rollback paths cannot register a stale or unprotected child
  • official builds require an executable-identity pin, the expected macOS TeamIdentifier, and an immutable source revision
  • the documented privileged install path uses a root-controlled temporary file, atomic replacement, ACL rejection, signature/runtime/entitlement checks, and final readback
  • macOS ACL inspection uses no unsafe Rust and fails closed on command, output, or decoding anomalies

Testing

  • just ci — passed on exact head 8589050c9c1285bfe1ef0a90b79650df9ce7bb7d
    • 4,605 desktop JavaScript tests passed
    • 2,416 Tauri library tests passed, plus all Tauri integration and terminal tests
    • 1,261 Flutter tests passed
    • Rust formatting and Clippy, desktop/web checks and production builds, and mobile analysis passed
  • focused heartbeat-preflight, Desktop trust-path, packaging-workflow, and macOS runtime checks passed during adversarial review
  • focused review regressions for ACL rejection and post-create designation passed
  • git diff --check — passed

Manual testing / screenshots

No new end-user UI is introduced, so screenshots are not applicable. A production acceptance run still requires the separately deployed trusted gateway, source credentials/helpers, and fresh signed source receipts; this PR deliberately fails closed until those are present.

Deferred follow-up

  • merge this change through the upstream maintainer review and protected CI path
  • deploy the trusted gateway and signed runtime from verified canonical releases
  • provision the isolated source credentials/helpers and resolve the required-source policy catalog
  • complete a fresh scheduled all-source run, restart, and replay-rejection run with accepted remote readback

Co-authored-by: Greg Moskalenko <greg1mosk@gmail.com>
Signed-off-by: Greg Moskalenko <greg1mosk@gmail.com>
@Greg-Moskalenko
Greg-Moskalenko requested a review from a team as a code owner August 11, 2026 21:19

@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: 939b524723

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

use std::os::unix::ffi::OsStrExt;

type Acl = *mut c_void;
unsafe extern "C" {

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 Remove the unsafe ACL FFI

This introduces an unsafe extern block and several unsafe calls for ACL inspection, despite the repository’s explicit prohibition on any unsafe code. Replace this implementation with a safe wrapper or command-based ACL inspection so the macOS heartbeat verification path complies with the project’s required safety invariant.

AGENTS.md reference: AGENTS.md:L114-L116

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 8589050c9. The macOS verifier no longer uses FFI or any unsafe code. It now performs fail-closed ACL inspection through /bin/ls -lde with a cleared environment, bounded output, strict status/stderr/UTF-8 checks, and an ACL regression test. The full just ci gate passes on this exact head.

};

// ── Pre-Phase 2: validate provider config BEFORE any side effects ────────
input.validate_heartbeat_preflight(&pubkey)?;

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 Expose the generated pubkey before validating its policy

When heartbeatPreflight is supplied during creation, the target pubkey is generated immediately above this call and is never exposed to the caller, but policy validation requires target_agent_pubkey to equal that newly generated value. A caller therefore cannot prepare a valid policy in advance, and retrying after failure generates another key, making the new create-time designation path effectively unusable; allocate or expose the key before accepting the policy, or require designation through the subsequent update path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 8589050c9. Create requests now reject a heartbeat designation before any side effect, the TypeScript create surface no longer exposes that field, and designation is required through update_managed_agent after creation returns the agent pubkey. The new boundary test and the full just ci gate pass on this exact head.

Require heartbeat designation through the post-create update path once the agent pubkey exists. Replace the macOS ACL FFI with fail-closed system ACL inspection so the trusted harness path contains no unsafe Rust.

Co-authored-by: Greg Moskalenko <greg1mosk@gmail.com>
Signed-off-by: Greg Moskalenko <greg1mosk@gmail.com>
@Greg-Moskalenko

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 8589050c9c

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

@Greg-Moskalenko

Copy link
Copy Markdown
Author

Current head 8589050 addresses both automated review findings and passes the full local just ci gate. Semgrep, zizmor, and DCO are green. The three fork workflows are still action_required; could a maintainer approve those workflows and review the current head?

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