Skip to content

macOS: flow do breaks Automation grant on every upgrade due to hash-based ad-hoc codesign identifier #70

@anshulsao

Description

@anshulsao

Summary

flow do calls osascript to spawn an iTerm tab. macOS TCC keys Apple Events permission on the calling binary's code-signing identifier. Because flow ships unsigned and macOS applies ad-hoc signing with the default identifier scheme — flow-<sha1-of-binary>every release produces a new identifier, so any previously-granted Automation permission becomes invalid on upgrade.

Result: flow do silently fails with Not authorised to send Apple events to iTerm. (-1743) after each upgrade until the user re-grants Automation. Because TCC doesn't always show a prompt for headless callers, the only recovery is manual intervention in System Settings → Privacy & Security → Automation.

Reproduction

  1. On macOS, install any version of flow.
  2. Run flow do <slug>; grant Automation when macOS prompts. Tab spawns.
  3. Upgrade flow to a new release (any version bump that changes the binary).
  4. Run flow do <slug> again.

Expected: tab spawns. Actual: error: osascript failed: ... Not authorised to send Apple events to iTerm. (-1743).

Root cause

$ codesign -dvv $(which flow)
Identifier=flow-555549445d3eb9e0bbce3434fd1ba6512765a843   ← SHA-1 of binary
Signature=adhoc

The trailing hash changes every build. macOS sees alpha.18's flow-555549... as a different app from alpha.15's flow-<otherHash>, so the old TCC grant doesn't apply. TCC also doesn't reliably prompt for binaries without an Info.plist / bundle ID — it sometimes records a silent denial.

Confirmed by tracing flow's osascript invocation through a PATH shim: the AppleScript is identical to a manual osascript call from any shell, but the same script run via flow's exec fails while the manual call succeeds, because Claude.app (the parent terminal here) HAS the iTerm Automation grant, but flow-<hash> does not.

Fix

Pin a stable codesign identifier at build time:

codesign --force --identifier cloud.facets.flow --sign - dist/flow

(Or the equivalent in goreleaser / your release pipeline.) Once flow ships with a fixed identifier, the user grants Automation once and upgrades preserve it.

Workaround for affected users today

codesign --force --identifier cloud.facets.flow --sign - $(which flow)

…then re-grant Automation → iTerm in System Settings. Works, but the user must re-run after every flow skill update / binary refresh.

Environment

  • flow v0.1.0-alpha.18
  • macOS (Apple Silicon, ad-hoc signature, no Info.plist)
  • Calling context: Claude Code session forking flow via Bash

Why this matters

For users like me running the pr-watch playbook, an upgrade silently breaks the entire PR-review pipeline — tasks land in backlog, the monitor marks them error:rc=2 in pr-watch-state.db, and nothing recovers until manual intervention. Stable codesign identity removes the entire failure mode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions