关于 gpc-security
gpc-security 是面向 GPC 用户的安全技能,涵盖凭据保护、轮换、审计日志和 CI/CD 安全实践。它还提供密钥泄露处置、最小权限建议及敏感信息脱敏方面的操作指引。
主要功能
- 01说明凭据存储位置
- 02指导服务账号密钥轮换
- 03检查 JSON Lines 审计日志
- 04提供 CI/CD 密钥管理建议
- 05说明泄露密钥的处置步骤
- 06介绍最小权限与敏感信息脱敏
适用场景
- 01在 CI/CD 中安全配置服务账号凭据
- 02轮换服务账号密钥
- 03检查 GPC 命令的审计记录
- 04密钥泄露后执行应急处理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yasserstudio/ gpc-skills --skill gpc-security安装后在 Claude Code 中输入/gpc-security确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/credential-storage.mdkey-rotation.mdruntime-security.mdscripts/detect_gpc.mjs详细介绍
gpc-security
GPC 的凭据管理、审计日志和安全最佳实践。
适用场景
- 保护服务账号密钥和凭据
- 设置凭据轮换
- 审查审计日志以满足合规要求
- 处理遭到泄露的服务账号密钥
- 保护 CI/CD 流水线中的 GPC
- 了解 GPC 存储敏感数据的位置
所需输入
- 已安装并完成身份验证的 GPC —
gpc auth status - 服务账号密钥文件 — 用于轮换流程
- CI/CD 平台访问权限 — 用于更新密钥
流程
0. 凭据存储位置
GPC 会将凭据存储在适合相应平台的安全位置:
| 数据 | 位置 | 安全性 |
|---|---|---|
| OAuth 令牌 | OS 密钥链(macOS/Linux/Windows) | OS 管理的加密 |
| 令牌缓存 | ~/.cache/gpc/tokens/ | 文件权限(0600) |
| 用户配置 | ~/.config/gpc/config.json | 文件权限 |
| 项目配置 | .gpcrc.json | 受版本控制(不含机密!) |
| 审计日志 | ~/.config/gpc/audit.log | JSON Lines,仅追加 |
XDG 覆盖变量: XDG_CONFIG_HOME、XDG_CACHE_HOME、XDG_DATA_HOME
阅读: references/credential-storage.md,了解详细的存储架构和安全模型。
1. 服务账号密钥安全
切勿将密钥提交到 git
# .gitignore
*.json.key
*-sa.json
service-account*.json
play-store-key.json
在 CI 中使用环境变量
# GitHub Actions — key stored as secret
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SA_KEY }}
切勿将密钥存储在以下位置:
.gpcrc.json(受版本控制)- Dockerfile 或 docker-compose 文件
- 提交到 git 的 Shell 脚本
- CI 配置文件(即使看起来是私有的)
2. 密钥轮换
定期轮换服务账号密钥(建议:每 90 天一次)。
# 1. Create new key in Google Cloud Console
# IAM & Admin → Service Accounts → Keys → Add Key
# 2. Test new key locally
gpc auth login --service-account /path/to/new-key.json
gpc doctor
# 3. Update CI secrets with new key
# GitHub: Settings → Secrets → PLAY_SA_KEY → Update
# GitLab: Settings → CI/CD → Variables → PLAY_SA_KEY → Update
# 4. Verify CI works with new key
# Trigger a test pipeline
# 5. Delete old key in Google Cloud Console
# IAM & Admin → Service Accounts → Keys → Delete old key
# 6. Clear local token cache
rm -rf ~/.cache/gpc/tokens/
阅读: references/key-rotation.md,了解自动轮换模式和多环境策略。
3. 审计日志
GPC 会以 JSON Lines 格式将所有命令记录到 ~/.config/gpc/audit.log:
# View recent audit entries
tail -20 ~/.config/gpc/audit.log | jq .
# Filter by command
cat ~/.config/gpc/audit.log | jq 'select(.command == "releases upload")'
# Filter by app
cat ~/.config/gpc/audit.log | jq 'select(.app == "com.example.app")'
# Filter failures
cat ~/.config/gpc/audit.log | jq 'select(.success == false)'
# Filter by date range
cat ~/.config/gpc/audit.log | jq 'select(.timestamp >= "2025-03-01")'
审计条目结构
{
"timestamp": "2025-03-09T14:30:00.000Z",
"command": "releases upload",
"app": "com.example.app",
"args": { "track": "beta", "file": "app-release.aab" },
"user": "[email protected]",
"success": true,
"durationMs": 12340
}
4. 机密信息脱敏
GPC 会自动对所有输出中的敏感数据进行脱敏:
- 绝不记录服务账号 JSON 内容
- 详细输出中绝不显示访问令牌
- 错误消息中绝不包含私钥
--json输出会对凭据字段进行脱敏- Webhook 负载会在发送到 Slack/Discord/自定义端点之前通过
redactSensitive()脱敏(v0.9.80+) - 身份验证错误消息会对看起来像粘贴凭据的长输入进行脱敏(v0.9.80+)
- 传递给
gpc purchases orders review-refund的--pending-refund-token不会出现在--notifyWebhook 消息和插件钩子数据中(v1.0.0-rc.1+) - ADC 令牌缓存会按凭据来源使用基于哈希的键,以防止多个账号混淆(v0.9.80+)
- 项目
.gpcrc.json无法自行批准插件——仅信任用户配置中的approvedPlugins(v0.9.80+)
5. 最小权限
仅授予每个服务账号所需的权限:
仅上传服务账号
Play Console 权限:
- 查看应用信息
- 管理测试(适用于内部/Alpha/Beta 测试)
- 发布到生产环境(仅在需要时)
只读监控服务账号
Play Console 权限:
- 查看应用信息
- 查看财务数据(用于报告)
# Verify what a service account can do
gpc auth status --json | jq '.email'
# Then check that email's permissions in Play Console
6. 处理遭到泄露的密钥
如果服务账号密钥泄露:
# 1. IMMEDIATELY delete the compromised key in Google Cloud Console
# IAM & Admin → Service Accounts → Keys → Delete
# 2. Create a new key
# Same page → Add Key → JSON
# 3. Update all locations using the key
gpc auth login --service-account /path/to/new-key.json
# 4. Update CI secrets
# All platforms using the old key
# 5. Clear token cache
rm -rf ~/.cache/gpc/tokens/
# 6. Review audit log for unauthorized actions
cat ~/.config/gpc/audit.log | jq 'select(.timestamp >= "LEAK_DATE")'
# 7. Review Google Cloud audit logs
# Cloud Console → IAM & Admin → Audit Logs
7. CI/CD 安全模式
GitHub Actions
# npm publish: OIDC via Trusted Publisher (v0.9.77+, no stored NPM_TOKEN)
permissions:
id-token: write # Required for OIDC token exchange with npm
# Google Play service account: encrypted secret
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SA_KEY }}
# Restrict to specific branches
if: github.ref == 'refs/heads/main'
# Use environments for approval gates (staged publishing uses this)
environment: production
机密信息扫描
# Check if keys are in git history
git log --all --full-history -p -- '*.json' | grep -l '"private_key"'
# If found, rotate immediately and clean git history
验证
gpc auth status显示预期的服务账号邮箱gpc doctor通过所有检查.gpcrc.json不包含任何机密信息或密钥路径- 正在写入
~/.config/gpc/audit.log中的审计日志 - CI 机密已加密,且不会显示在日志中
- 轮换后已删除旧密钥
故障模式/调试
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
| 密钥文件已提交到 git | 未加入 .gitignore | 将其加入 .gitignore;立即轮换密钥 |
| 轮换后令牌缓存仍为旧状态 | 缓存中仍有旧令牌 | 删除 ~/.cache/gpc/tokens/ |
| 未写入审计日志 | 配置目录不可写 | 检查 ~/.config/gpc/ 的权限 |
| 不知道服务账号邮箱 | 未检查密钥 | gpc auth status --json | jq '.email' |
| CI 日志中显示凭据 | 将密钥作为参数传入 | 使用环境变量,切勿使用 CLI 参数 |
| 每次执行命令都会弹出钥匙串提示 | 未授予 macOS 钥匙串访问权限 | 在提示中点击“始终允许” |
8. 供应链防护(v0.9.77+)
GPC 使用 15 层防御措施,防范依赖项和发布供应链攻击:
| 层 | 功能 |
|---|---|
| 受信任发布者(OIDC) | npm 发布通过 GitHub OIDC 进行身份验证——任何地方都不会存储长期有效的 NPM_TOKEN |
| 分阶段发布 | CI 对软件包进行分阶段处理;维护者通过 2FA 审批后,软件包才会在 npm 上发布 |
| 删除 NPM_TOKEN | GitHub 密钥中不存储 npm 令牌——OIDC 是唯一的身份验证方式 |
.npmrc 中的 min-release-age=7 | 阻止发布未满 7 天的软件包 |
pnpm-lock.yaml | 固定确切版本,避免意外升级 |
| Socket.dev CI 扫描 | 每个 PR 都运行 socket ci,发现严重警报时阻止合并 |
| Socket.dev GitHub App | 对有风险的依赖项变更添加行内 PR 评论 |
CI 中的 pnpm audit | 发现高危 CVE 时阻止 PR(仅限生产依赖项) |
| GitHub Actions SHA 固定 | 所有 14 个 Action 引用均固定到提交哈希,而非可变标签 |
| SBOM(CycloneDX) | 每次 npm 发布时生成并归档软件物料清单 |
| CODEOWNERS | 安全敏感路径需要明确审核 |
| Dependabot | 每周创建更新 PR(仅限直接依赖项,按组归类 Actions) |
| Socket CLI 包装器 | 扫描每次本地 npm install 和 npx |
| CodeQL | 每次推送时进行静态分析 |
| GitHub 密钥扫描 | 阻止包含 200+ 种密钥模式的推送 |
GPC 只有 4 个运行时依赖项:google-auth-library、commander、protobufjs、yauzl。所有 API 调用都使用 Node.js 内置的 fetch。
配置:仓库根目录下的 socket.yml 控制 Socket.dev 警报规则。.npmrc 控制 min-release-age。.github/CODEOWNERS 控制审核要求。发布工作流使用 pnpm release-staged 和 OIDC 身份验证。
9. 安全审计状态(v0.9.80 + v0.9.82)
v0.9.80 deepsec 重新扫描:在修复 v0.9.80 安全问题后,对整个代码库进行了 deepsec 审计。结果:没有发现新问题。v0.9.74 审计中此前跟踪的所有问题均已解决。
Webhook 脱敏(v0.9.80):通过 --webhook-url 向 Slack、Discord 和自定义端点发送的 Webhook 负载现在会在发送前进行脱敏。敏感字段会在负载离开进程前被移除。此措施适用于所有 gpc watch 违规事件以及其他所有 Webhook 发送路径。
google-auth-library 升级(v0.9.82):google-auth-library 已升级到 10.7.0。此升级解决了唯一剩余的已跟踪生产环境审计问题:brace-expansion 的传递依赖漏洞。GPC 现在没有任何生产环境审计问题。
9a. GPC GitHub Action 安全性
GPC GitHub Action(yasserstudio/gpc-action)是一个运行在 Node 24 上的 TypeScript Action,具有以下安全特性:
- 已验证的二进制文件:它会从 GPC GitHub 发布版本下载独立的
gpc二进制文件,并在每次运行时(包括命中缓存时)根据 Action 本身提交的校验和检查其 SHA-256,而不只是依赖发布版本中可变的checksums.txt。GPC 默认版本已固定:截至 Action v1.1.4,为 1.0.0-rc.2。gpc-version: latest或未固定的版本会改用发布版本中的校验和,并显示警告。 - 凭据:身份验证使用通过
service-account-json传入的服务账号 JSON 密钥。请将其存储为加密密钥;目前没有 OIDC 或无密钥选项。 - 内置预检门禁:Action 会在上传前运行
gpc preflight,扫描失败时会阻止发布(preflight: false可跳过此步骤)。 - Node 24 运行时:与当前 GPC CLI CI 矩阵保持一致。
用法:
- uses: yasserstudio/gpc-action@v1
with:
service-account-json: ${{ secrets.GPC_SERVICE_ACCOUNT }}
package-name: com.example.app
release-files: app/build/outputs/bundle/release/app-release.aab
track: beta
10. 开发者验证
Google 的 Android 开发者验证将于 2026 年 9 月开始强制实施(BR、ID、SG、TH):
gpc verify # Status, deadlines, resources
gpc verify --open # Open verification page in browser
gpc verify --json # Machine-readable output
gpc verify checklist 会逐项检查完整的准备情况清单(截至 v0.9.96 共 11 项,每一项都可以通过提示词引导完成)——参见 gpc-setup。gpc doctor 包含验证检查。gpc status 会显示页脚提醒。gpc preflight 会在扫描后显示提醒。
11. 签名密钥验证(v0.9.75+)
验证本地签名密钥是否与 Play 签名证书匹配:
gpc doctor --verify # Show Play cert fingerprint
gpc doctor --verify --keystore release.keystore --store-pass $PW # Compare local vs Play
如果指纹不匹配,说明你使用的分发密钥与 Play 使用的密钥不同。请在 Play Console 中注册该密钥,以避免在 2026 年 9 月 30 日之后被阻止安装。
12. 使用可自托管 Cloud KMS 密钥的 Play App Signing(v0.9.96+)
gpc app-signing enroll 和 gpc app-signing rotate 涵盖了 Google 通过 API 提供的唯一 Play App Signing 流程:使用可自托管的 Google Cloud KMS 密钥注册,以及轮换该密钥。
这不是常规流程。 标准的 Play App Signing 使用 Google 生成或管理的密钥,完全无法通过 API 设置——请在 Play Console 中操作。只有在合规、监管或政策要求迫使你将密钥保存在自己的 Cloud KMS 实例中时,才使用这些命令。
# Enroll an app already published to Open testing or Production
gpc app-signing enroll \
--app com.example.app \
--existing-app \
--kms-key projects/acme/locations/global/keyRings/play/cryptoKeys/signing/cryptoKeyVersions/1
# Enroll an app not yet published (Google requires the certificate here)
gpc app-signing enroll \
--app com.example.app \
--new-app \
--kms-key projects/acme/locations/global/keyRings/play/cryptoKeys/signing/cryptoKeyVersions/1 \
--cert ./signing-cert.pem \
--upload-cert ./upload-cert.pem
# Rotate to a new Cloud KMS key
gpc app-signing rotate \
--app com.example.app \
--kms-key projects/acme/locations/global/keyRings/play/cryptoKeys/signing/cryptoKeyVersions/2 \
--cert ./new-signing-cert.pem \
--lineage ./lineage.bin \
--reason ROUTINE_KEY_UPGRADE
运行任一命令前,请了解以下安全特性:
--cert和--upload-cert仅接受 PEM 证书。 将私钥传给任何文件参数都会导致用法错误(退出码 2),且不会发送任何内容。私钥绝不会离开你的计算机,签名密钥本身也始终保留在 Cloud KMS 中,不会被上传。- 在调用任一子命令之前,先向 Play 授予该密钥版本的 Decrypt 和 Sign IAM 权限。Google 会在服务端验证这些权限;如果未授予,调用将失败并返回 Play API 错误(退出码 4)。
enroll必须且只能指定--new-app/--existing-app中的一个;两者都不指定或同时指定都会导致用法错误。--new-app还需要--cert。rotate仅适用于已使用可自托管密钥注册的应用(Google 管理密钥的轮换需通过 Play Console 操作),并需要提供由apksigner rotate生成的签名证书谱系文件作为轮换证明。- 必须提供
--reason,并且会在本地拒绝KEY_ROTATION_REASON_UNSPECIFIED。可接受的值:COMPROMISED_KEY、USE_STRONGER_KEY、USE_SAME_KEY_FOR_MULTIPLE_APPS、ROUTINE_KEY_UPGRADE、OTHER。 - CI 中不会显示确认提示。 这两个命令仅会在交互式终端中打印警告并显示提示;在 CI、非 TTY、使用
--no-interactive、设置GPC_NO_INTERACTIVE或使用全局--yes时,它们会直接继续。如果你希望人工介入,请在自己的流水线中设置门禁。--dry-run会预览请求,但不会发送。
验证
gpc auth status显示预期的服务账号电子邮件地址gpc doctor通过所有检查.gpcrc.json不包含任何机密或密钥路径- 正在写入
~/.config/gpc/audit.log中的审计日志 - CI 密钥已加密,且不会显示在日志中
- 轮换后已删除旧密钥
相关技能
- gpc-setup — 初始身份验证和配置
- gpc-user-management — 管理团队访问权限
- gpc-ci-integration — 安全配置 CI/CD 流水线
- gpc-troubleshooting — 调试身份验证错误