Skip to content

feat(gmail): add --gmail-no-send flag to block send operations#454

Open
veteranbv wants to merge 2 commits intosteipete:mainfrom
veteranbv:feat/gmail-no-send
Open

feat(gmail): add --gmail-no-send flag to block send operations#454
veteranbv wants to merge 2 commits intosteipete:mainfrom
veteranbv:feat/gmail-no-send

Conversation

@veteranbv
Copy link

@veteranbv veteranbv commented Mar 16, 2026

Motivation

gmail.modify is the right OAuth scope for an agent that needs to read, label,
and create drafts, but it also permits send. Google provides no scope that
grants modify-level access without send capability. This means there is no way
to give an AI agent read/label/draft access while maintaining a hard block on
send.

A prompt-level guardrail is not sufficient: if safety instructions are compacted
away during a long session, an agent operating on gmail.modify could send
email on behalf of the user. The block needs to live in the binary itself, below
the instruction layer, where context compaction cannot reach it.

Closes #453

Summary

  • Add --gmail-no-send global flag and GOG_GMAIL_NO_SEND env var
  • Add gmail_no_send config key (gog config set gmail_no_send true) for
    persistent global blocking without env vars
  • Add per-account send blocking via gog config no-send set/remove/list,
    stored as no_send_accounts in config.json
  • Block all four send paths: send, gmail send, gmail drafts send,
    gmail autoreply
  • Global enforcement in Execute() using the same pattern as
    enforceEnabledCommands (post-parse, pre-Run(), exit code 2)
  • Per-account enforcement in each send command's Run() after account
    resolution via requireAccount()
  • Error messages identify the blocking source (flag, config key, or account)

Precedence: CLI flag > env var > config key > per-account config > default (allow).

Test plan

  • TestIsGmailSendCommand -- unit coverage for all send and non-send
    command strings
  • TestGmailNoSendBlocksViaCLI -- integration test: all four send paths
    blocked via --gmail-no-send
  • TestGmailNoSendAllowsNonSendCommands -- non-send commands pass through
  • TestGmailNoSendEnvVar -- GOG_GMAIL_NO_SEND=1 blocks send
  • TestGmailNoSendNotSetAllowsSend -- without flag, send is not blocked
  • TestGmailNoSendConfigGlobal -- gmail_no_send: true in config blocks
  • TestGmailNoSendConfigGlobalAllowsNonSend -- config global does not
    block non-send commands
  • TestGmailNoSendGlobalOverridesPerAccount -- flag wins over per-account
  • TestCheckAccountNoSend_Blocked -- per-account blocks matching account
  • TestCheckAccountNoSend_Allowed -- per-account allows non-matching
  • TestCheckAccountNoSend_NoConfig -- absent config does not block
  • Config unit tests: IsNoSendAccount, SetNoSendAccount,
    ListNoSendAccounts (with nil map, case insensitivity, empty email)
  • go test ./... -- full suite passes, no regressions
  • make lint -- clean

Add a CLI-layer kill switch (--gmail-no-send / GOG_GMAIL_NO_SEND=1)
that blocks all send operations in the gmail command group, regardless
of OAuth scopes.

gmail.modify is the right scope for an agent that needs to read, label,
and create drafts, but it also permits send. Google provides no scope
that grants modify-level access without send capability. This flag gives
agent operators a hard invariant: deploy gog with GOG_GMAIL_NO_SEND=1
and send is impossible, full stop, regardless of what the agent is told
or forgets.

Blocked paths: send, gmail send, gmail drafts send, gmail autoreply.
Enforced centrally in Execute() using the same pattern as
enforceEnabledCommands — post-parse, pre-Run(), exit code 2.
Extend the global --gmail-no-send flag with per-account control and a
persistent config key, based on community feedback from @codefly.

Per-account: gog config no-send set/remove/list manages a
no_send_accounts map in config.json. The check runs in each send
command's Run() after account resolution, since account identity
isn't known until requireAccount() resolves aliases and defaults.

Global config key: gog config set gmail_no_send true persists the
global block in config.json without requiring an env var or CLI flag.

Precedence: CLI flag > env var > config key > per-account > default.

Also fixes the env var handling to use the envBool/boolString pattern
(matching JSON and Plain flags) so that GOG_GMAIL_NO_SEND="" doesn't
cause a Kong parse error.
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.

feat(gmail): add --gmail-no-send flag for agent safety

1 participant