From 45404ef7538405f8f5dcf3aec61735558eac8554 Mon Sep 17 00:00:00 2001 From: Rob Zolkos Date: Sun, 20 Sep 2026 12:43:38 -0400 Subject: [PATCH 1/2] Guide Codex through sandboxed Keychain auth --- skills/embed_test.go | 24 ++++++++++++++++++++++++ skills/hey/SKILL.md | 6 ++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/skills/embed_test.go b/skills/embed_test.go index 842e68dc..ce56eac8 100644 --- a/skills/embed_test.go +++ b/skills/embed_test.go @@ -33,3 +33,27 @@ func TestHeySkillReusesAuthenticationForUnattendedAgents(t *testing.T) { } } } + +func TestHeySkillRetriesMacOSKeychainAccessWithoutBroadEscalation(t *testing.T) { + data, err := FS.ReadFile("hey/SKILL.md") + if err != nil { + t.Fatal(err) + } + content := string(data) + + for _, want := range []string{ + "On macOS under Codex", + "retry `hey auth status --json` once with elevated sandbox permission", + "one read-only command", + "normal approval flow", + "rerun only the exact `hey` command the user requested", + "separate one-command approval", + "Never run the macOS `security` command", + "never disable the sandbox globally", + "never set `HEY_NO_KEYRING=1`", + } { + if !strings.Contains(content, want) { + t.Errorf("embedded HEY skill does not contain %q", want) + } + } +} diff --git a/skills/hey/SKILL.md b/skills/hey/SKILL.md index 5d5b313f..23cc4d71 100644 --- a/skills/hey/SKILL.md +++ b/skills/hey/SKILL.md @@ -119,7 +119,7 @@ CLI for HEY: mailboxes, labels, collections, email threads, contacts, replies, c **MUST follow these rules:** 1. **Choose the right structured output** — use `--jq ''` to filter or extract fields and `--json` for the full response. Never pipe to an external `jq`; `--jq` is built in and implies `--json`. -2. **Reuse stored authentication** — run the requested data command; it uses stored credentials and refreshes expiring OAuth tokens automatically. If it returns an auth error, report the task as blocked. Use `hey auth status --json` when an explicit authentication check is needed. Never run `hey auth login` unattended; use it only for interactive recovery with the user present. +2. **Reuse stored authentication** — run the requested data command; it uses stored credentials and refreshes expiring OAuth tokens automatically. If it returns an auth error, follow the one-command macOS/Codex retry in [Authentication](#authentication) before you report the task as blocked. Use `hey auth status --json` when an explicit authentication check is needed. Never run `hey auth login` unattended; use it only for interactive recovery with the user present. 3. **HTML output** is available via `--html` for commands that return HTML content 4. **Linked mail accounts share one login** — use `hey account list --json`, then `--account ` when a task must target one account 5. **Local HEY configuration requires human trust** — never run `hey config trust-local` without the user's explicit approval @@ -851,7 +851,9 @@ error. Data commands use the credentials HEY already stores and refresh expiring OAuth tokens automatically. Run the requested data command without a login preflight. Use `hey auth status --json` when the user asks for authentication status or when an explicit authentication check helps diagnose a failure; it reports whether credentials are available without changing them. -If a data command returns exit code 3 with `"code": "auth"`, report that authentication is required and the task is blocked. Tell the user to run `hey auth login`; do not run it for them unattended. +If a data command returns exit code 3 with `"code": "auth"`, authentication is unavailable to that process. On macOS under Codex, the sandbox can hide credentials that the HEY CLI stores in Keychain. Before reporting the task as blocked, use the harness's normal approval flow to retry `hey auth status --json` once with elevated sandbox permission. Limit the escalation to this one read-only command. If it reports that authentication is available, rerun only the exact `hey` command the user requested through a separate one-command approval. If the status check still reports an authentication error, tell the user to run `hey auth login`; do not run it for them unattended. + +Never run the macOS `security` command to read Keychain contents, print or copy credentials, or move credentials into a file; never disable the sandbox globally; never set `HEY_NO_KEYRING=1` as an authentication workaround. Piped, machine-output and non-TTY commands do not prompt for sign-in. When an agent harness runs commands under a PTY, set `HEY_NONINTERACTIVE=1` so a missing login returns the same actionable auth error instead of opening an interactive prompt. From bd93cff8f067ac7b0c1aecbd027dbb6278482efc Mon Sep 17 00:00:00 2001 From: Rob Zolkos Date: Sun, 20 Sep 2026 12:54:27 -0400 Subject: [PATCH 2/2] Handle unauthenticated status explicitly --- skills/embed_test.go | 4 ++++ skills/hey/SKILL.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/skills/embed_test.go b/skills/embed_test.go index ce56eac8..db6bea97 100644 --- a/skills/embed_test.go +++ b/skills/embed_test.go @@ -48,7 +48,11 @@ func TestHeySkillRetriesMacOSKeychainAccessWithoutBroadEscalation(t *testing.T) "normal approval flow", "rerun only the exact `hey` command the user requested", "separate one-command approval", + "`data.authenticated` is `true`", + "`data.authenticated` is `false` or the status command fails", "Never run the macOS `security` command", + "print or copy credentials", + "move credentials into a file", "never disable the sandbox globally", "never set `HEY_NO_KEYRING=1`", } { diff --git a/skills/hey/SKILL.md b/skills/hey/SKILL.md index 23cc4d71..273c5def 100644 --- a/skills/hey/SKILL.md +++ b/skills/hey/SKILL.md @@ -851,7 +851,7 @@ error. Data commands use the credentials HEY already stores and refresh expiring OAuth tokens automatically. Run the requested data command without a login preflight. Use `hey auth status --json` when the user asks for authentication status or when an explicit authentication check helps diagnose a failure; it reports whether credentials are available without changing them. -If a data command returns exit code 3 with `"code": "auth"`, authentication is unavailable to that process. On macOS under Codex, the sandbox can hide credentials that the HEY CLI stores in Keychain. Before reporting the task as blocked, use the harness's normal approval flow to retry `hey auth status --json` once with elevated sandbox permission. Limit the escalation to this one read-only command. If it reports that authentication is available, rerun only the exact `hey` command the user requested through a separate one-command approval. If the status check still reports an authentication error, tell the user to run `hey auth login`; do not run it for them unattended. +If a data command returns exit code 3 with `"code": "auth"`, authentication is unavailable to that process. On macOS under Codex, the sandbox can hide credentials that the HEY CLI stores in Keychain. Before reporting the task as blocked, use the harness's normal approval flow to retry `hey auth status --json` once with elevated sandbox permission. Limit the escalation to this one read-only command. If the response's `data.authenticated` is `true`, rerun only the exact `hey` command the user requested through a separate one-command approval. If `data.authenticated` is `false` or the status command fails, report the task as blocked and tell the user to run `hey auth login`; do not run it for them unattended. Never run the macOS `security` command to read Keychain contents, print or copy credentials, or move credentials into a file; never disable the sandbox globally; never set `HEY_NO_KEYRING=1` as an authentication workaround.