ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

gog CLI Agent 安全自动化实战指南:认证、只读读写与命令守卫

2026/9/16 20:55:10 拓冰建站 浏览量
gog CLI Agent 安全自动化实战指南:认证、只读读写与命令守卫 gog CLI Agent 安全自动化实战指南认证、只读读写与命令守卫【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcligog 是运行在终端里的 Google Workspace 客户端为脚本、CI 与 AI Agent 提供了显式账号路由、机器可读输出与多层安全护栏。本文以仓库中的 Agent Skill 文档 为骨架结合 CLI 根标志定义、命令守卫实现、稳定退出码 与 安全配置文件 等源码系统讲解 Agent 场景下的安全读写、认证排障与自动化集成方案。读完你将在自己的 Agent 或脚本中安全地落地 gog包括非交互式认证、只读任务约束、JSON 投影与命令白名单/黑名单。为什么 Agent 需要专门的 gog 使用方式内置的 Google 连接器功能不够、Shell 自动化需要稳定 JSON、或在行动前需要检查本地 Google 认证状态时就可以使用gog。与人类在终端里交互式操作不同Agent 面对的核心约束是输出必须可解析人类靠颜色与表格Agent 靠 JSON 与稳定退出码交互必须可终止认证或 keyring 弹窗在无人值守时会让流程挂死因此要用--no-input让失败显式化误操作必须可拦截读命令与写命令混在一起时需要--readonly、--gmail-no-send、--dry-run与--force等运行时护栏来界定 Agent 的权限边界。gog的 CLI 入口在 cmd/gog/main.go所有子命令实现集中在 internal/cmd/OAuth 与密钥环相关逻辑在 internal/googleauth/、internal/authclient/ 与 internal/secrets/。机器输出、非交互行为、稳定退出码、命令守卫与不可信内容包裹untrusted-content wrapping在整个 CLI 上统一生效。Fast Path五分钟跑通 Agent 环境在接入任何工作流之前先用以下命令确认版本、认证状态与命令面gog --version gog auth list --check --json --no-input gog auth doctor --check --json --no-input GOG_HELPagent gog --help gog schema --jsongog auth list --check --json --no-input非交互式列出所有账号并逐一检查令牌有效性输出 JSONgog auth doctor --check --json --no-input对认证链做端到端诊断详见下文“认证诊断”一节GOG_HELPagent gog --help让根帮助输出一份紧凑的自动化契约与常用只读配方。从源码看help_printer.go 通过读取GOG_HELP环境变量切换帮助模式agent与fullagent模式不展开子命令并注入自动化提示命令本身的行为完全不变gog schema --json输出命令语法、稳定退出码与生效中的安全状态供 Agent 自行发现能力。实现见 internal/cmd/schema.go。面向 Agent 的 JSON 输出投影--fields 是 --select 的别名很多 Agent 习惯用--fields表达“只要这些字段”。gog将其作为全局--select的别名处理——除非某个命令自己定义了 API 字段掩码field mask语义的--fields此时保留该命令自身的含义。从 arg_rewrite.go 可以看到参数解析阶段会先判断该命令在当前上下文是否有本地fields标志没有才把--fields改写成全局--select。--results-only 与点路径选择--results-only在--select投影之前先剥掉外层信封envelope直接输出主结果。其底层实现在 internal/outfmt/outfmt.go优先取results键否则排除nextPageToken、next_cursor、has_more、count、dry_run等元信息键再按已知结果数组名files、threads、messages、events、contacts等或唯一数组候选来定位主结果。使用时的三个关键点列表场景要选“条目相对”字段例如--results-only --select id作用于每个列表项点路径不会穿过嵌套数组广播--select items.id什么都选不到点路径只在对象层级间下钻不会自动遍历数组未匹配的字段会被省略投影是尽力而为的白名单不存在的字段直接丢弃。gog --readonly --account userexample.com drive ls --max 10 --json --results-only --select id,name不可信内容包裹--json --wrap-untrustedGoogle 内容邮件正文、聊天消息、文档文本对 Agent 而言是不可信输入可能携带注入 Agent 指令的内容。读取时优先使用gog --readonly --account userexample.com gmail search newer_than:7d --json --wrap-untrusted--wrap-untrusted会在 JSON/raw 输出的文本字段外套上外部不可信内容标记实现入口见 root.go 与 api.go 对outfmt.WrapUntrustedContent的调用并支持GOG_WRAP_UNTRUSTED1环境变量默认开启root_untrusted_test.go 对标志与环境变量两种路径均有测试覆盖。输出纪律人类提示与进度信息应写入 stderrstdout 只承载数据。Agent 解析时只信任 stdout 的 JSON。安全规则Agent 的红线清单Skill 文档对 Agent 给出了一系列硬性规则逐条落地如下规则说明禁止打印敏感凭据不输出访问令牌、刷新令牌、OAuth client secret 与 keyring 口令keyring 环境传递若GOG_KEYRING_PASSWORD由 Shell 启动文件或服务环境提供使用匹配的 Shell/入口点启动让 gog 非交互解锁文件 keyring绝不打印该值校验服务环境headless/service Agent 必须验证服务环境而非仅登录 ShellGOG_KEYRING_BACKENDfile、GOG_KEYRING_PASSWORD、HOME必须出现在启动 gog 的进程中非交互失败自动化一律加--no-input让认证/keyring 提示显式失败而不是挂起先演练支持--dry-run的命令先跑演练别名noop、preview见 root.go只读约束不得变更 Google 数据的任务加--readonlyroot.go运行时阻断变更类 API 请求auth add 时也仅请求只读 OAuth scope仅在用户明确批准的精确写入时才移除破坏性命令破坏性命令要求--force别名yes、assume-yes未获明确批准绝不添加默认不发送除非任务就是发信否则使用--gmail-no-send或环境变量GOG_GMAIL_NO_SEND1共享环境加固共享 Agent 环境优先使用烘焙进二进制的 readonly/agent-safe 版本见 docs/safety-profiles.md运行时命令守卫--enable-commands / --disable-commands除了全局--readonly还可以用命令前缀白名单/黑名单收紧 Agent 能调用的子命令支持点路径gog --readonly --enable-commands gmail.search,gmail.get --gmail-no-send \ --account userexample.com gmail search from:exampleexample.com --json gog --enable-commands drive.ls,docs.cat --disable-commands drive.delete \ --account userexample.com drive ls --max 10 --json实现上enabled_commands.go 在命令解析后、进入任何 handler 前执行enforceEnabledCommands/enforceDisabledCommands白名单是前缀匹配drive.ls会命中drive.ls及其子命令黑名单同样按点路径前缀拦截别名如docs.page-layout的docs.set-page-layout也会被识别。被拦截时返回 usage 级错误例如command gmail.send is not enabled (set --enable-commands or --enable-commands-exact to allow it) command drive.delete is disabled (blocked by --disable-commands)更精确的管控可搭配--enable-commands-exact精确匹配父命令不会放行子命令。--enable-commands、--disable-commands、--gmail-no-send、--readonly等都有对应的环境变量默认值如GOG_READONLY、GOG_GMAIL_NO_SEND定义见 root.go。稳定退出码让 Agent 按状态码分支Agent 不需要解析人类可读的 stderr 来判断成败。exit_codes.go 定义了全 CLI 统一的稳定退出码并被gog schema --json暴露给自动化语义退出码ok成功0error通用失败1usage用法/解析错误2empty_results结果为空3auth_required需认证4not_found未找到5permission_denied权限不足6rate_limited限流/配额7retryable可重试8config配置缺失如凭据缺失10orphaned11cancelledSIGINT/Ctrl-C130退出码由 HTTP 状态与 Google API 错误 reason 映射而来401 →auth_required404 →not_found403 区分配额类 reasonrateLimitedExceeded、quotaExceeded等与权限拒绝429 →rate_limited5xx 与超时 →retryable。AuthAgent 视角的认证生命周期OAuth 设置部分需要交互Agent 可以检查与诊断但浏览器同意consent通常由真人完成。标准流程gog auth credentials list gog auth add userexample.com --services all-user --force-consent gog auth remove userexample.com重新认证时的 scope 保持默认对既有 human/user OAuth 重新认证的策略是保持原有的宽服务访问。重新认证前先运行gog auth list --check --json --no-input检查该账号既有的services列表。替换过期或吊销的令牌时不要静默收窄 scope除非用户明确要求更窄的范围否则优先--services all-user --force-consent。--force-consent与--services的实现见 auth_add.go。窄 scope 只适用于一次性/测试账号、特定服务的 bot 账号、用户明确请求、或受控的安全实验。日常安全性应通过--enable-commands、--disable-commands、--gmail-no-send、dry-run 与账号选择在命令执行时约束而不是通过给持久用户认证缩 scope 来实现。服务账号的边界服务账号仅适用于 Workspace主要服务于 Admin、Groups、Keep 与域级授权domain-wide delegation流程它们无法解决消费者gmail.com的 OAuth。通过真实入口点做认证诊断对 OpenClaw/systemd 等场景重启服务后要通过实际 Agent 入口点运行诊断而不是在交互 Shell 里验证openclaw agent --agent main --message \ Run: gog auth doctor --check --no-input gog gmail search newer_than:1d --max 1 --json如果 Shell 里gog auth doctor正常、而服务环境里失败并报keyring.password说明服务/Agent 环境本身缺GOG_KEYRING_PASSWORD或HOME等变量应修复环境而非重新认证。auth doctor的实现入口在 auth_doctor.go对 keyring 口令不匹配会给出明确提示如“make every GOG_KEYRING_PASSWORD definition match, then re-rungog auth doctor --check”。浏览器驱动式重新认证Agent 全程可跑通当 Agent 能驱动一个已登录的浏览器时可以端到端完成整个流程consent 仍然发生在真实浏览器中任何步骤都不会绕过它。第一步把 CLI 端跑在独立的 tmux 会话里使其跨越命令边界存活tmux -L gog-auth new-session -d -s auth -x 200 -y 50 tmux -L gog-auth send-keys -t auth \ gog auth add userexample.com --services all-user --force-consent --timeout 15m Enter第二步用-J捕获 consent URLtmux -L gog-auth capture-pane -t auth -p -J -S - \ | grep -oE https://accounts\.google\.com[^ ] | tail -1 $url_file-J是强制项没有它capture-pane会按 pane 宽度硬折行返回 URL。被截断的 consent URL 不会大声失败——Google 只会渲染Invalid OAuth Request/Invalid response_type: missing看起来像客户端配置错误会让你朝错误的方向排查。使用前先确认捕获到的 URL 里包含response_type。第三步安全地把 URL 交给浏览器写入 mode-0600 的文件后按文件引用交给浏览器见$browser-use绝不 echo 到终端。追加login_hintuserexample.com可以跳过账号选择器消除一整类“选错账号”的风险。第四步应对未验证应用的插页。当 OAuth client 处于未验证/testing 状态时最多会遇到两个插页Google hasnt verified this app.——Continue是旁边低强调度的链接视觉上最显眼的按钮是Back to safety点错就会中止流程。两者之间还有一个开发者信息控件占据 Tab 顺序所以要刻意数焦点步数而不是猜。Youre signing back in to app—— 确认显示的账号就是目标账号然后Continue。第五步读懂超时与重试。listener 强制执行--timeout超时后 tmux pane 只是回到 Shell 提示符所以“什么都没发生”的流程往往不是浏览器问题而是 listener 过期。重新驱动浏览器前先读 pane并重启 CLI 端而不是复用陈旧的 URL。尽快完成浏览器端操作把 navigate 与 activate 批量做掉而不是来回往返。跨主机注意浏览器不必跑在 CLI 所在主机上。回调目标是http://localhost:port所以两台机器分离时先在本机把该端口从浏览器主机转发到 listener 所在主机再打开 URL并先确认转发已生效。浏览器保持在与目标 Google 会话所在 profile 的主机上。如果 tmux 索要文件 keyring 口令从该主机的登录环境login shell取来粘贴同样不要打印。第六步验证账号与 scope 广度gog auth list --check --json --no-input确认目标账号报告 valid且保留了预期的 services 列表。一次“登录成功但悄悄收窄了 scope”的重新认证本质上是失败的。Common Reads只读读取配方以下是 Skill 文档提供的常用只读配方全部显式指定账号、加--readonly、输出 JSON 并包裹不可信内容gog --readonly --account userexample.com gmail search newer_than:3d --max 10 --json --wrap-untrusted gog --readonly --account userexample.com gmail get messageId --sanitize-content --json --wrap-untrusted gog --readonly --account userexample.com gmail thread get threadId --sanitize-content --json --wrap-untrusted gog --readonly --account userexample.com calendar events --today --json --wrap-untrusted gog --readonly --account userexample.com drive ls --max 20 --json --wrap-untrusted gog --readonly --account userexample.com docs cat documentId --json --wrap-untrusted gog --readonly --account userexample.com sheets get spreadsheetId Sheet1!A1:D20 --json --wrap-untrusted gog --readonly --account userexample.com contacts list --max 20 --json --wrap-untrustedGmail 正文检查优先用--sanitize-content对邮件内容做净化去除原始 payload 中的注入面除非用户明确需要 raw payload。相关测试见 gmail_sanitize_test.go。Writes受控写入写入前的三要素写操作前先确认三件事目标账号、对象 ID、精确的变更。优先选用支持--dry-run的命令并在验证后清理一次性的 live-test 对象命名加明确临时前缀用后删除或移入回收站。gog --account userexample.com docs write documentId --append --text ... gog --account userexample.com docs write documentId --tab Data --markdown --replace --file data.md gog --account userexample.com docs update documentId --tab Data --markdown --file block.md gog --account userexample.com docs update documentId --tab Data --replace-range START:END --text replacement gog --account userexample.com docs update documentId --tab Data --markdown --replace-range START:END --file block.md gog --account userexample.com sheets update spreadsheetId Sheet1!A1 --values-json [[hello]] gog --account userexample.com sheets batch-update spreadsheetId --data-json updates.json gog --account userexample.com drive upload ./file.txt --parent folderId --jsonGoogle Docs 标签页tab写入策略用docs list-tabs documentId --json先发现 tab 标题/ID再定位目标 tabdocs write --markdown --replace --tab tab整 tab 的格式化替换docs update --markdown --tab tab格式化插入/追加不替换整个 tabdocs update --replace-range START:END精确的纯文本范围替换加--markdown则把该精确范围替换为格式化 markdownSTART:END是 Google Docs 的 UTF-16 API 范围索引必须从docs cat --raw、docs raw或其他documents.get读回结果解析不要猜测索引--replace-range与--index互斥。Gmail 写入的注意点gmail batch delete是永久删除消息且要求更宽的https://mail.google.com/OAuth scope优先gmail trash。确需永久删除时严格按gog打印的精确重新授权命令执行大范围 Sheets 写入优先sheets batch-update而不是循环sheets update它在一次 Sheets API 请求里发送多个值范围且支持内联 JSON 或file输入普通 Gmail 回复应使用一等命令而不是用gmail send手工拼回复 MIMEgog --account userexample.com gmail reply messageId --body-file reply.txt gog --account userexample.com gmail reply-all messageId --body-file reply.txt \ --bcc introducerexample.com --remove former-participantexample.comgmail reply/gmail reply-all会继承主题、默认引用原文、保留显示名与内嵌图片--to/--cc/--bcc是增量放置或移动语义用--no-quote省略原文。Discovery不猜 flag查文档与 schema用生成式命令文档与 schema 替代猜测gog service --help gog service command --help gog schema service command --json仓库内的配套资料docs/index.md总索引docs/commands/README.md全部命令文档入口docs/agent-skills.mdAgent Skills 安装与内置工作流inbox-triage、meeting-prep、save-attachments、drive-audit、weekly-digest、contacts-cleanup 等docs/safety-profiles.md安全 profile 与锁死 flaglocked flags机制。对应源码路径CLI 入口点cmd/gog/命令实现internal/cmd/OAuth/keyringinternal/googleauth/、internal/authclient/、internal/secrets/生成式命令文档docs/commands/。进阶烘焙安全二进制Safety ProfilesSkill 文档特别提示共享 Agent 环境应优先使用烘焙进二进制的 readonly 或 agent-safe 版本。与运行时守卫不同安全 profile 把命令策略编译进二进制无法用 flag、环境变量、配置文件或 Shell 参数在运行时改变详见 docs/safety-profiles.md。./build-safe.sh safety-profiles/agent-safe.yaml -o bin/gog-agent-safe ./build-safe.sh safety-profiles/readonly.yaml -o bin/gog-readonlybuild-safe.sh会校验 YAML、生成内嵌 profile 的internal/cmd/safety_profile_baked_gen.go、以-tags safety_profile构建、跑--version冒烟测试后删除生成文件。普通go build不带 profile因此标准gog二进制完全不受影响。预设 profile 位于仓库 safety-profiles/safety-profiles/agent-safe.yaml允许读取、搜索、草稿、打标、归档、整理文件等低风险可恢复动作阻止发送、删除、共享变更、Admin 操作与 auth 写入safety-profiles/readonly.yaml仅允许读/列表/搜索/get 类命令safety-profiles/full.yaml放开一切主要供冒烟测试或构建与标准版命令面一致的-safe二进制。运行时检查顺序docs/safety-profiles.md显式 deny 规则优先allow 规则放行匹配命令若 profile 含 allow 规则则其余全部拦截。所以bin/gog-readonly --enable-commands gmail.send gmail send ...依然会被拦截——烘焙策略先于运行时白名单被检查错误以 exit code 2 在进入任何 handler/Google API 调用之前返回。schema命令在这些 profile 下依然可用方便 Agent 发现命令面、退出码与生效中的安全策略被拦截的命令不会出现在父级帮助菜单与gog schema输出中。小结Agent 接入 gog 的最小检查清单gog --versiongog auth doctor --check --json --no-input确认环境明确账号每条 API 命令都带--account只读任务一律--readonly读 Google 内容一律--json --wrap-untrusted正文加--sanitize-content自动化一律--no-input先--dry-run演练写任务锁定账号、对象 ID、精确变更用--force时确认这正是用户要求的变更默认不发送邮件--gmail-no-send发送仅限任务本身按稳定退出码分支internal/cmd/exit_codes.go不解析人类 stderr共享环境用烘焙的 agent-safe/readonly 二进制兜底。【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考