source-package.json — Approval-Gated Mail

From version 0.2.1 of Approval-Gated Mail, shown publicly by its creator. 9.9 KiB · SHA-256 d826ef4fd366fed92a28ec9da350ddd2a26850ab1cbe0924d148086121a6d983.

{"schema_version":1,"runtimes":[{"name":"python","versions":["3.10"]}],"dependencies":[],"operations":[{"kind":"read","description":"Approval-Gated Mail 0.2.1: List recent mailbox messages (recent subcommand).","target_restrictions":["Graph: account from --user, --from, or M365_DEFAULT_USER; Gmail: account that authorized the stored token"]},{"kind":"read","description":"Search mailbox messages by keyword (search subcommand).","target_restrictions":["Graph: account from --user, --from, or M365_DEFAULT_USER; Gmail: account that authorized the stored token"]},{"kind":"read","description":"Search mailbox messages by sender (from subcommand).","target_restrictions":["Graph: account from --user, --from, or M365_DEFAULT_USER; Gmail: account that authorized the stored token"]},{"kind":"read","description":"Read one message by ID, including its body (read subcommand).","target_restrictions":["Only the caller-supplied message ID"]},{"kind":"read","description":"Read every message in one conversation, oldest to newest (thread subcommand).","target_restrictions":["Only the caller-supplied conversation ID"]},{"kind":"read","description":"List attachment metadata only; Gmail fields excludes body.data. Gmail full read/thread responses can carry inline attachment data; attachment parts are discarded, never shown or saved.","target_restrictions":["Only the caller-supplied message ID"]},{"kind":"read","description":"Read a bounded sent-record collection: exact subject and supplied recipient sets; Gmail also requires SENT and exact RFC Message-ID. No delivery proof.","target_restrictions":["Graph: account from --user, --from, or M365_DEFAULT_USER; Gmail: account that authorized the stored token"]},{"kind":"create","description":"Create one local Markdown file from a message (save subcommand); never replace an existing path or symlink.","target_restrictions":["Only the exact local OUTPUT_PATH argument in an existing parent directory; refused before token request if path exists or is a symlink"]},{"kind":"send","description":"Send a new message after explicit caller approval (send subcommand without a reply target).","target_restrictions":["Only after --approve matches the SHA-256 digest printed by --dry-run for the method, full URL, and exact JSON body","Only the recipients, subject, and body explicitly supplied by the caller"]},{"kind":"send","description":"Send a reply to an existing message after explicit caller approval (send subcommand with --reply-to-message-id).","target_restrictions":["Only after --approve matches the SHA-256 digest printed by --dry-run for the method, full URL with reply message ID, and exact JSON body","Only the caller-supplied reply message ID"]},{"kind":"read","description":"Read Gmail reply-target metadata during reply dry-run and live recheck; preview may refresh the access token.","target_restrictions":["Only the caller-supplied reply message ID; one read-only GET during dry-run","A refresh may POST once to oauth2.googleapis.com and update the selected local token store"]},{"kind":"create","description":"Create a Gmail server-side draft after exact digest approval (draft subcommand).","target_restrictions":["Only the approved RFC 5322 content and Gmail account","--approve and --message-id must match the dry-run digest and RFC 5322 Message-ID"]},{"kind":"create","description":"Store a Gmail OAuth token during auth login or refresh by any authenticated Gmail command, in Keychain or a private file.","target_restrictions":["Only Keychain service approval-gated-mail-gmail or GMAIL_TOKEN_FILE/default local path"]},{"kind":"modify","description":"Revoke a Gmail OAuth grant and delete its locally stored token (auth revoke).","target_restrictions":["Only the current account's grant and matching local token store"]},{"kind":"read","description":"Inspect locally stored Gmail authorization status without printing tokens.","target_restrictions":["Only the stored Gmail token in the configured local store (Keychain account default)"]},{"kind":"read","description":"Read caller-selected --body-file as local message body text, not attachment bytes.","target_restrictions":["Only the caller-supplied --body-file path"]},{"kind":"read","description":"Before live Gmail send or draft, search for the approved Message-ID to refuse replays.","target_restrictions":["GET users/me/messages with q=rfc822msgid:<message-id> and includeSpamTrash=true; any match refuses the POST"]},{"kind":"read","description":"Read Gmail users/me/profile emailAddress in send/draft preview and immediately before each Gmail API write with the same write token.","target_restrictions":["Normalized address is shown and digest-bound; missing or changed identity refuses; existing readonly/compose scopes permit getProfile"]}],"authorization":{"mode":"other","scopes":["Mail.Read","Mail.Send","https://www.googleapis.com/auth/gmail.readonly","https://www.googleapis.com/auth/gmail.compose"],"credential_requirements":["Graph: M365_TENANT_ID, M365_CLIENT_ID, M365_CLIENT_SECRET or --config PATH","Gmail: user-owned GMAIL_CLIENT_FILE Desktop OAuth JSON and delegated auth login","MAIL_PROVIDER or --provider selects graph/gmail; GMAIL_DEFAULT_USER only sets Gmail From; GMAIL_TOKEN_STORE and GMAIL_TOKEN_FILE select storage","Fake Graph: M365_MAIL_FAKE_TRANSPORT with M365_MAIL_ALLOW_FAKE=1; fake Gmail: GMAIL_FAKE_TRANSPORT with GMAIL_ALLOW_FAKE=1","Fake Keychain runner for tests only: GMAIL_FAKE_SECURITY_RUNNER=1 and GMAIL_ALLOW_FAKE_SECURITY=1"]},"network":{"domains":["graph.microsoft.com","login.microsoftonline.com","gmail.googleapis.com","oauth2.googleapis.com"],"destinations":["Graph mailbox selected by --user, --from, or M365_DEFAULT_USER","If the user's environment sets HTTPS_PROXY, or a macOS or Windows system proxy applies, requests are tunnelled through that user-chosen proxy; TLS still terminates at the declared hosts with verified certificates","Gmail API mailbox selected by the signed-in Google account","Google OAuth token, refresh, and revoke endpoint","accounts.google.com consent URL is printed only; the CLI never fetches that host or opens a browser","Local 127.0.0.1 random-port OAuth listener loops until a valid callback or the 180 s timeout","urllib honors HTTPS_PROXY/https_proxy and NO_PROXY/no_proxy plus macOS/Windows system proxies; TLS terminates at declared hosts"]},"safety":{"read_only_by_default":true,"dry_run_supported":true,"consequential_writes_require_authorization":true,"validation_controls":["save refuses an existing path or symlink before token request and creates a new file with O_CREAT|O_EXCL, plus O_NOFOLLOW and 0600 on POSIX","send --dry-run renders the Graph method, full URL, exact JSON body, and SHA-256 approval digest without token request or network call","Graph live send requires the digest before token request; Gmail preview/live reads the profile; --approved is rejected","checked_remote_url restricts every request, including redirects, to graph.microsoft.com and login.microsoftonline.com","Graph send excludes baseline IDs and polls for exact subject and recipient sets; Gmail send reads its returned ID and checks SENT plus RFC Message-ID; neither proves delivery","Gmail OAuth uses PKCE S256, random state checked by constant-time comparison, a timed 127.0.0.1 callback loop, and a guarded token endpoint","Gmail dry-run creates a random Message-ID; live send and draft require --message-id and a digest over normalized profile account, POST method, URL, raw message, and reply target","Gmail replies read target metadata in dry-run and live mode; changed Message-ID, References, Subject, or threadId refuses","/usr/bin/security -i uses list-form subprocess with timeout; hex-encoded secret enters one stdin command, never argv; account and service names are validated","POSIX token files use 0600, no symlinks, and exclusive creation or atomic replacement; Windows relies on user-profile ACLs without POSIX mode checks","Gmail fake transport and fake token runner require two environment gates and print stderr warnings","Gmail host guard rechecks every redirect; accounts.google.com is a browser destination only","Injected fake Keychain runner requires both test-only environment gates and a stderr warning; tests never call real /usr/bin/security","Gmail search and sender queries reject quotes and backslashes because Gmail does not document escaping inside q phrases","Gmail 4xx send and draft failures are refusals; 5xx, timeout, and connection failures report outcome unknown with the Message-ID","Any authenticated Gmail command may refresh the access token and rewrite its selected local token store","Keychain writes require matching find-generic-password read-back; reads treat exit 44 as missing; other failures raise","Gmail From is set by --from or GMAIL_DEFAULT_USER; neither selects the account used for API reads"],"target_restrictions":["Graph: account from --user, --from, or M365_DEFAULT_USER; Gmail: account that authorized the stored token","Only the exact local path supplied to save's OUTPUT_PATH argument","Only the exact recipients, subject, and body explicitly supplied to send","Gmail only accesses the signed-in account and explicit message/thread identifiers","Gmail draft and send use only approved content","Gmail token writes use the selected local store","Gmail --from and GMAIL_DEFAULT_USER only set the From header","Bundled tests create synthetic files in system temp; hygiene reads only package files"]},"tests":{"files":["tests/test_m365_mail.py","tests/test_gmail_mail.py"],"fixtures":"synthetic_only","provenance":"creator","evidence":["Creator-authored stdlib unittest suite invoking the CLI as a subprocess against a fake Graph transport fixture","Covers recent, search, from, read, thread, attachments, save, verify-sent, send, reply, and send --dry-run with no real network calls","Asserts Graph --dry-run makes zero HTTP requests with an empty fake transport","Gmail synthetic fixtures cover OAuth, token storage, query escaping, paging, MIME, reply digest, draft, and profile-bound synthetic dry-run","Tests create synthetic files in system temp; hygiene reads only package files"]}}

License: MIT (read it).

MITMIT License

Copyright (c) 2026 Zero Width Lab

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Back to the listing