Skip to content

Latest commit

 

History

History
509 lines (372 loc) · 25.1 KB

README.zh.md

File metadata and controls

509 lines (372 loc) · 25.1 KB

Apollo CLI

English

apollo-cli 是 apollo 命令行工具的独立 Rust 仓库。

当前仓库覆盖 Apollo CLI v0 的第一批能力:

  • 顶层 v0 命令路由
  • 全局参数解析
  • 输出格式化基础
  • 非敏感 profile 配置
  • 运行时上下文解析
  • 凭据存储抽象和 auth 命令
  • user-token 身份与能力自检
  • 保守的脱敏基础能力
  • /openapi/v1/* 下的代表性 Apollo Portal OpenAPI 调用
  • 通过 apollo api 透传原始 OpenAPI 请求
  • 变更类命令的确认保护
  • 带 stale-plan 检查与 no-op 结果的保守配置 diff/apply
  • 发布创建、查询和回滚
  • 真实 Portal + H2 变更 smoke 覆盖
  • 本地开发流程和 CI 入口

这个包刻意保持自包含、可移动。它当前位于这个独立仓库中便于评审,但不会假设仓库特有环境,因此后续可以在不修改 Apollo 服务端的情况下拆分、vendored 或重新发布 crate。

本阶段不实现生成式 OpenAPI SDK 绑定、agent session、MCP 或服务端 schema 变更。

命令分组

  • auth
  • profile
  • app
  • env
  • namespace
  • config
  • release
  • api

代表性的 v0 命令:

apollo init
apollo profile add dev
apollo profile add prod --use
apollo app list
apollo app get sample-app
apollo env list --app sample-app
apollo namespace list --env DEV --app sample-app
apollo namespace get --env DEV --app sample-app application
apollo namespace create --env DEV --app sample-app app-settings --comment "app settings" --yes
apollo config list --env DEV --app sample-app
apollo config get --env DEV --app sample-app timeout
apollo config set --env DEV --app sample-app timeout 3000 --type 1 --yes
apollo config delete --env DEV --app sample-app timeout --yes
apollo config diff --env DEV --app sample-app --target-env FAT
apollo config apply --env DEV --app sample-app --target-env FAT --yes
apollo release list --env DEV --app sample-app
apollo release create --env DEV --app sample-app --title "release title" --yes
apollo release rollback --env DEV 123 --to-release-id 122 --yes
apollo api get /openapi/v1/apps
apollo api post /openapi/v1/apps/sample-app/appnamespaces --body '{"appId":"sample-app","name":"raw-settings","format":"properties","isPublic":false}' --yes

这些命令只使用已有的 Apollo Portal OpenAPI 端点。CLI 有意不使用已废弃的 Portal WebAPI 端点。

apollo namespace create 会先注册 AppNamespace,再在指定环境和 cluster 中创建 namespace。默认创建私有 AppNamespace。只有在 namespace 应该是公共 namespace 时才传 --public。文件类型 namespace 会根据 .json、.yml、.yaml、.xml 和 .txt 后缀推断格式;其他名称默认使用 properties。--comment 会存储在 AppNamespace 上。公共 AppNamespace 注册会发送 Apollo 的 appendNamespacePrefix=true 默认值;如果 namespace 名称必须按原样存储、不使用 Apollo 的公共 namespace 前缀行为,请传 --no-append-namespace-prefix。

注册 AppNamespace 时,Apollo 也可能在其他环境和 cluster 中自动创建 namespace 实例。在另一个环境创建同名 namespace 前,先用 namespace list 确认。CLI 会拒绝在指定 scope 中重复创建已有 namespace;示例应选用新名称,而不是默认已有的 application。Apollo 会校验包含组织前缀与格式后缀的最终名称,本次实测的 Portal 限制为 32 个字符。

apollo config set 会发送 Apollo 的 OpenItemDTO.type 字段。默认值为 0,表示字符串配置项。Apollo Portal 还使用 1 表示数字、2 表示布尔值、3 表示 JSON;这些值会在发送 OpenAPI 请求前由客户端校验。

全局参数

以下全局参数可以放在子命令之前或之后:

  • --profile
  • --server
  • --output json|table
  • --yes

--yes 表示在不显示交互提示的情况下显式批准一次 OpenAPI 变更请求。它不会跳过目标计划构建、参数校验、脱敏或操作信息输出。

--server 是 Portal 的基础 URL,需要包含部署时配置的 context path。例如 Portal 位于 http://127.0.0.1:8070/apollo 时,应使用 --server http://127.0.0.1:8070/apollo;CLI 会在其后拼接 /openapi/v1/*。遗漏 /apollo 会访问错误路径,可能返回 404。 Profile 选择 Portal 和鉴权配置;同一个 Portal 下的 Apollo 环境另用 --env DEV 或 --env PRO 选择。 名为 dev 的 profile 不会自动设置 --env。

资源 scope 与分页

Namespace、config 以及 release list/create 命令需要 --env 和 --app。默认 cluster 为 default; config 以及 release list/create 的默认 namespace 为 application。使用 --cluster 和 --namespace 选择其他 scope;namespace get 的 namespace 是位置参数。

config list 和 release list 每次只返回一页,可使用 --page(从 0 开始,默认 0)和 --size(默认 20)查询更多配置或发布记录。JSON 配置列表包含 data.content、data.page、 data.size 和 data.total。

对包含 / 或 \ 的 key,config get、config set 和 config delete 会自动使用 Apollo 的 encodedItems 端点,直接传入原始 key 即可,无需手工编码。

引导式初始化

首次使用时推荐执行 apollo init。它会创建 profile,将非敏感 profile 元数据写入 config.toml,并且可以通过凭据存储抽象保存 Apollo OpenAPI token。

对于支持 Portal 用户访问 token 的 Apollo 版本,交互式用户、AI agent 和个人自动化推荐使用 user-token 鉴权模式。

本地 Apollo assembly 测试示例:

apollo --output json init --store-token-in-file
apollo profile show
apollo env list --app sample-app

默认情况下,apollo init 会创建一个 local profile:

  • server = "http://127.0.0.1:8070"
  • 除非显式传入 --output,否则不持久化 output
  • auth_mode = "user-token"
  • 不配置 operator;user-token OpenAPI 请求使用 token 所属用户作为操作人
  • active_profile = "local"

可以用 apollo profile add 增加更多环境,避免手工编辑配置:

printf '%s\n' "$DEV_TOKEN" | apollo \
  --server https://apollo-dev.example.com \
  --output json \
  profile add dev \
  --token-stdin

apollo profile add prod --server https://apollo-prod.example.com --use
apollo profile add legacy --server https://apollo-legacy.example.com --auth-mode consumer-token --operator alice

profile add 默认保留已有且有效的 active profile;如果没有有效的 active profile,新建 profile 会自动成为 active profile。使用 --use 可以切换到新建 profile。已有 profile 会受到误替换保护;如果确实要替换,请传 --overwrite。

Profile 配置

CLI 将非敏感 profile 元数据存储在操作系统配置目录下的 config.toml 中:

  • macOS:~/Library/Application Support/apollo/config.toml
  • Linux:$XDG_CONFIG_HOME/apollo/config.toml 或 ~/.config/apollo/config.toml
  • Windows:%APPDATA%\apollo\config.toml

如需在隔离的 CI 或 smoke 环境中保存 config.toml 和文件型凭据,可将 APOLLO_CLI_HOME 设置为绝对目录。日常交互式使用仍建议保留平台默认路径。

配置文件会存储:

  • active_profile
  • profile 名称
  • profile server
  • profile output
  • profile auth_mode,取值为 user-token 或 consumer-token
  • 可选 operator
  • 可选凭据查找元数据,例如 backend/key 名称

Token 不属于受支持的配置 schema,CLI 有意不把 token 放进这里。建议使用 apollo init、apollo profile add 和 apollo auth login,而不是手工编辑这个文件。

如果缺少 auth_mode,CLI 会把该 profile 当作 consumer-token 处理,以兼容已有配置。

示例:

active_profile = "dev"

[profiles.dev]
server = "https://apollo-dev.example.com"
output = "table"
auth_mode = "user-token"

[profiles.dev.credential]
backend = "native"
key = "dev"

Profile 命令

  • apollo init
  • apollo profile add [name]
  • apollo profile list
  • apollo profile show
  • apollo profile use <name>

运行时上下文按以下顺序解析:

  1. 显式参数,例如 --profile、--server、--output
  2. 环境变量,例如 APOLLO_PROFILE、APOLLO_SERVER、APOLLO_OUTPUT
  3. active profile 配置
  4. 命令默认值

Auth 命令

  • apollo auth login
  • apollo auth login --token-stdin
  • apollo auth login --token-stdin --store-token-in-file
  • apollo auth status
  • apollo auth whoami
  • apollo auth capabilities
  • apollo auth logout

凭据存储使用内部 store 抽象,包含以下逻辑 provider:

  • native:默认凭据后端,通过 Rust keyring crate 使用操作系统凭据存储
  • env:通过 APOLLO_TOKEN 提供只读的 CI/headless provider
  • file:只有显式传 --store-token-in-file 时才启用的文件回退
  • 用于单元测试的内存 provider

Native 后端选择遵循底层操作系统凭据存储行为:

  • macOS:Keychain Services
  • Windows:Credential Manager
  • Linux:内核 keyring(keyutils,通过 keyring crate 的 linux-native feature 启用)
  • Linux headless/CI 或无法使用内核 keyring 的环境:使用 APOLLO_TOKEN,或显式选择文件回退

文件回退会把 token material 写到 config.toml 之外的 CLI 凭据目录中,并在 Unix 上使用受限文件权限。Profile 配置只存储非敏感凭据查找元数据。

Windows 当前不支持文件回退,因为尚未实现 Windows ACL 权限限制;请使用 native 凭据存储或 APOLLO_TOKEN。

OpenAPI 命令支持两种 token 模式:

  • user-token:推荐用于交互式用户、AI agent 和本地自动化。Token 以 apollo_pat_ 开头,并以 Authorization: Bearer <token> 形式发送。
  • consumer-token:用于兼容已有集成和旧版本 Apollo 部署。Token 会作为原始 Authorization: <token> header 值发送。

apollo init 和 apollo profile add 默认使用 user-token。配置旧版 consumer-token 凭据时请使用 --auth-mode consumer-token。变更类命令只在 consumer-token 模式下要求配置 operator;user-token 请求会使用所属 Portal 用户,并拒绝显式传入 --operator。

apollo env list、apollo namespace list、apollo namespace get、apollo config get、apollo config list、apollo config diff、apollo config apply 和 apollo release list 会读取 env、namespace 或配置项数据,这些数据的授权范围可能比 app 更窄。请在这些命令中使用 user-token 模式。旧版 consumer-token 模式无法从可用的 /openapi/v1/apps/authorized 响应中安全校验 env/namespace 级读取范围,因此 CLI 会拒绝这些 scoped-read 工作流,而不是只依赖 app 级可见性。

本地或 CI 使用时,APOLLO_TOKEN 优先级最高,并且永远不会写入磁盘:

APOLLO_TOKEN="$TOKEN" apollo --server http://localhost:8070 app list --output json

当 APOLLO_TOKEN 以 apollo_pat_ 开头时,CLI 会自动将其视为 user-token;否则使用 consumer-token 兼容模式。

apollo auth logout 会删除所选 profile 引用的凭据。它不能从父 shell 环境中删除 APOLLO_TOKEN。如果 APOLLO_TOKEN 仍然存在,logout 会提示环境凭据仍会继续生效;执行 unset APOLLO_TOKEN 可以禁用这个临时凭据。

交互式使用时,先配置 profile,再用隐藏输入保存 token:

apollo --profile dev auth login
apollo --profile dev app list

auth login 默认把 token 存到操作系统凭据存储。如果 native store 在交互式终端中不可用,CLI 会询问是否改用本地文件回退。

脚本或手工粘贴并回车的场景下,--token-stdin 会读取一行 token:

printf '%s\n' "$TOKEN" | apollo --profile dev auth login --token-stdin
apollo --profile dev auth login --token-stdin
printf '%s\n' "$LEGACY_CONSUMER_TOKEN" | apollo --profile legacy auth login --auth-mode consumer-token --token-stdin

登录后可使用 user-token 自检命令:

apollo --profile dev auth whoami
apollo --profile dev auth capabilities

这些命令会调用 /openapi/v1/user-tokens/current 和 /openapi/v1/user-tokens/current/capabilities。它们要求使用 user-token 鉴权模式,并且不会创建、轮转或撤销 token;用户 token 的创建仍然是 Portal 自助流程。

脱敏和错误

输出层会在渲染前对人类可读输出和 JSON 输出应用保守脱敏。类 token 字段、Authorization: Bearer ... header 和 consumer token ... 文本都会渲染为 [REDACTED]。

Config list/set 响应会脱敏配置 value,namespace list/get 会脱敏其中的配置 value,release list/create 会脱敏 configurations。config get 可返回指定 key 的 value,同时应用通用敏感字段脱敏。 原始 apollo api 响应使用通用敏感字段脱敏,不执行资源命令对配置 value 的整体脱敏。

结构化 JSON 错误包含:

  • code:稳定错误码
  • category:稳定错误分类
  • message:人类可读错误信息
  • 可选的非敏感详情,例如 command、profile、path 或 operation

当前错误分类:

  • authentication_failed
  • permission_denied
  • invalid_input
  • not_found
  • conflict
  • precondition_failed
  • network
  • server
  • confirmation_required
  • unsupported_operation

进程退出状态在以下层级保持稳定:

  • 0:成功
  • 1:运行期或操作失败,包括鉴权、校验、网络/服务端和确认失败
  • 2:命令行解析或用法错误

当自动化调用方需要比进程退出状态更具体的失败原因时,应使用结构化 JSON 中的 error.code 和 error.category。

变更安全

在执行内置 namespace、config、release 或 raw API 变更前,CLI 会根据选中的 profile/server 和命令目标构建一份脱敏操作计划。计划会按操作类型包含可用字段,例如 app、env、cluster、namespace、配置 key/数量、release ID,或经过净化的 raw OpenAPI method 和 path。计划不会包含配置值、请求 body、query 值、token 或 Authorization header。

在交互式 table 模式中,未传 --yes 的变更会把计划和默认拒绝的 [y/N] 提示写到 stderr。只有输入 y 或 yes 才会执行;输入 n、no、空行或遇到 EOF 都会拒绝。在非交互模式和 JSON 模式中,变更必须显式传入 --yes;否则 CLI 返回 confirmation_required,其 operation 字段包含脱敏计划。拒绝发生在任何 OpenAPI 请求发送之前。

namespace 创建只会在首次批准后发送只读预检请求。如果 Apollo 解析出的最终 namespace 名称发生变化,例如为公共 namespace 添加组织前缀,CLI 会展示解析后的计划,并在发送任何变更请求前再次要求批准。如果批准后选中的 profile、server 或输出模式发生变化,CLI 会在发送 OpenAPI 请求前中止,并要求调用方重新检查新的运行上下文。

传入 --yes 时,table 模式仍会在请求前输出计划。成功的 JSON 输出仍是一个完整 JSON 文档,并保留现有顶层 status 和 data 字段,同时新增顶层 operation 计划。

配置同步约定

config diff 和 config apply 采用保守合并约定:只存在于源端的 key 会被创建,源端 value 或 comment 不同的 key 会被更新,相同 key 保持不变,只存在于目标端的 key 会被保留。因此,空源端会得到成功的 no-op,而不会清空目标端。CLI 当前不提供 --prune;删除必须通过独立、显式的配置删除流程完成。如果某个 Portal 版本通过同步 diff 接口返回删除操作,CLI 会拒绝该计划,并且不会调用 items/synchronize。

table 和 JSON 输出都会给出源端与目标端 scope,以及 create、update、delete、unchanged 计数。JSON 约定还会返回 strategy: "merge" 和 targetOnlyBehavior: "preserve"。diff 结果、apply 计划和 apply 结果都不会包含配置 value。

单独执行的 config diff 仅供参考,不会生成可供后续调用消费的计划制品。config apply 会自行捕获完整分页的源端快照,用这份快照调用 items/diff,同时捕获完整分页的目标端状态,并根据返回的变更集生成详细变更计划。批准后,CLI 会重新读取目标端,并使用同一份已捕获的源端快照再次评估;如果目标端配置状态或评估结果发生变化,命令会返回 stale_plan,且不会发送同步请求。首次批准有意发生在这些预检读取之前,第二次详细批准则确认实际变更计数。如果 create、update 和 delete 计数均为零,命令会返回确定性的 data.result: "no-op" 成功结果,并且不会调用 items/synchronize;此时 unchanged 可以非零。

该 stale-plan 检查属于乐观、best-effort 防护。当前 Apollo items/synchronize OpenAPI 约定没有目标 revision、ETag 或条件写入前置条件,因此最终检查之后发生的目标端写入仍可能与同步竞争。要彻底消除这个窗口,需要先修改 Apollo OpenAPI contract,再由服务端在更新配置的同一原子操作中校验目标 revision。对写入互斥有严格要求的调用方,在当前 CLI 工作流之外仍需自行协调。

配置同步可以通过 --target-env 和 --target-cluster 选择目标环境或 cluster。config apply 要求源端和 目标端的 namespace 名称相同;不同的 --target-namespace 会在同步前被拒绝。

OpenAPI 行为

第一版 v0 实现使用一个小型通用 HTTP client,而不是生成式 SDK。这样可以让 CLI 与 Apollo 服务端仓库解耦,同时仍然保证所有内置资源命令都限定在 /openapi/v1/*。

路径和 payload 映射遵循当前 Apollo Portal OpenAPI contract,包括:

  • GET /openapi/v1/apps
  • GET /openapi/v1/envs
  • GET /openapi/v1/apps/{appId}/envclusters,用于 env list
  • GET /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces
  • GET|PUT|DELETE /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key}
  • POST /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/diff
  • POST /openapi/v1/apps/{appId}/appnamespaces 用于 AppNamespace 注册
  • POST /openapi/v1/namespaces
  • POST /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/synchronize
  • GET /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/active
  • POST /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases
  • PUT /openapi/v1/envs/{env}/releases/{releaseId}/rollback

变更类命令的确认和操作计划行为见变更安全。

可执行文件发布

手动运行发布 workflow 后,预编译的 apollo 可执行文件会发布到 GitHub Releases 页面:

平台 Rust target 压缩格式
Linux x86-64 x86_64-unknown-linux-gnu .tar.gz
Linux ARM64 aarch64-unknown-linux-gnu .tar.gz
macOS Intel x86_64-apple-darwin .tar.gz
macOS Apple 芯片 aarch64-apple-darwin .tar.gz
Windows x86-64 x86_64-pc-windows-msvc .zip

压缩包统一命名为 apollo-<tag>-<target>.<extension>,其中包含可执行文件、许可证以及中英文 README。每个 Release 还会提供 SHA256SUMS,并为全部上传的压缩包和 checksum 文件生成 GitHub 构建来源证明。

例如,可以使用 GitHub CLI 下载并校验一个版本:

version=v0.1.1
mkdir "apollo-${version}"
gh release download "${version}" \
  --repo apolloconfig/apollo-cli \
  --dir "apollo-${version}"
(cd "apollo-${version}" && sha256sum --check SHA256SUMS)
gh attestation verify \
  "apollo-${version}/apollo-${version}-x86_64-unknown-linux-gnu.tar.gz" \
  --repo apolloconfig/apollo-cli

macOS 的 checksum 校验命令请使用 shasum -a 256 -c SHA256SUMS。

维护者发布时,先把目标 package version 和更新后的 Cargo.lock 合并到默认分支。然后进入 Actions → Release → Run workflow,保持选择默认分支,并填写不带前导 v 的 SemVer。 也可以通过 GitHub CLI 启动同一条发布流程:

release_version=0.1.1 # 示例:替换为计划发布的 Cargo.toml 版本。
gh workflow run release.yml \
  --repo apolloconfig/apollo-cli \
  --ref main \
  -f version="${release_version}"

workflow 会拒绝格式错误、与 Cargo.toml 不一致、不是从默认分支启动,或者 tag/Release 已存在 的版本。随后重新执行格式化、Clippy 和测试,为五个原生 target 构建并冒烟验证可执行文件,生成 checksum 与构建来源证明。全部检查通过后,才会在本次 workflow 的精确 commit 上创建 v<version> tag,自动生成 release notes,核对草稿 Release 的完整附件集合并公开发布。版本中含有 SemVer 预发布后缀时,会发布为 prerelease。

发版前,维护者还必须在目标默认分支 commit 上运行 Actions → Apollo mutation smoke → Run workflow,并确认执行成功;该 workflow 也会每周定时运行。它使用固定 Apollo revision 构建 Portal、ConfigService、AdminService 和一次性 H2 数据库,再执行下文所述的真实变更约定。Apollo 固定 revision 保存在 scripts/mutation-smoke.sh 中,更新它必须作为代码变更接受 review。

变更 smoke 的发布前检查由维护者执行,release.yml 不会自动强制校验它。在版本或文档变更合并后, 应对最终默认分支 commit 再运行一次。发布版本必须未使用过;发布已有 tag 会被 release workflow 拒绝。

本地开发

构建 CLI:

cargo build

运行 help 输出:

cargo run -- --help

运行测试:

cargo test

使用本地 mock HTTP server 运行聚焦的 OpenAPI 命令集成测试:

cargo test --test openapi

从干净 checkout 运行可重复的真实 Portal 变更 smoke(需要 Git、curl、jq、awk、 sha256sum 或 shasum、JDK 17 和稳定版 Rust 工具链):

./scripts/mutation-smoke.sh

该命令会拉取固定 Apollo revision、构建并启动单进程 Portal + H2 assembly、构建 CLI、创建隔离的 APOLLO_CLI_HOME profile 和一次性 app/namespace,并基于真实服务端状态验证 config diff/apply、 缺少确认时拒绝、权限失败、release 创建/列表以及回滚。测试会确认保守合并保留目标端独有 key, 并比较 no-op 前后的完整目标状态。User token 和配置值只保存在权限为 0700 的临时目录中,失败 诊断会动态脱敏,assembly 进程与临时目录始终会被清理。若本地已有同一固定 commit 的干净 Apollo checkout,可以复用:

APOLLO_SMOKE_APOLLO_SOURCE=/absolute/path/to/apollo ./scripts/mutation-smoke.sh

如果本地运行了 Apollo Portal,也可以直接对它做 smoke test:

APOLLO_TOKEN="$TOKEN" cargo run -- --server http://localhost:8070 --output json env list --app sample-app
APOLLO_TOKEN="$TOKEN" cargo run -- --server http://localhost:8070 --output json app list
APOLLO_TOKEN="$USER_TOKEN" cargo run -- --server http://localhost:8070 --output json auth whoami

如果 Portal 部署在 /apollo 下,并包含 DEV、PRO 两个环境,请使用完整的基础 URL。 先将 Portal user token 放入 USER_TOKEN,再把 sample-app 替换为 app list 中可见的应用 ID:

export APOLLO_SERVER=http://127.0.0.1:8070/apollo
export APOLLO_TOKEN="$USER_TOKEN"
apollo_app=sample-app

target/debug/apollo --output json auth whoami
target/debug/apollo --output json auth capabilities
target/debug/apollo --output json app list
target/debug/apollo --output json env list --app "$apollo_app"
for apollo_env in DEV PRO; do
  target/debug/apollo --output json namespace list --env "$apollo_env" --app "$apollo_app"
  target/debug/apollo --output json config list --env "$apollo_env" --app "$apollo_app" --page 0 --size 20
  target/debug/apollo --output json release list --env "$apollo_env" --app "$apollo_app"
done

以上命令只读取服务端数据,token 仅保存在环境变量中。验证配置变更、同步、发布与回滚时, 应使用专门的测试 namespace,并在结束后清理。

格式化仓库:

cargo fmt

运行 lint:

cargo clippy --all-targets --all-features -- -D warnings

仓库结构

  • src/cli.rs:CLI 定义和参数解析
  • src/config.rs:profile 配置加载、保存和上下文解析
  • src/command.rs:顶层命令路由
  • src/credential.rs:凭据存储抽象和 provider
  • src/error.rs:结构化 CLI 错误模型
  • src/http.rs:通用 OpenAPI HTTP client 和路径 helper
  • src/output.rs:输出渲染抽象
  • src/redaction.rs:保守脱敏工具
  • tests/auth.rs:auth 命令和凭据行为的集成覆盖
  • tests/cli.rs:help、参数和结构化错误的集成覆盖
  • tests/openapi.rs:OpenAPI path、鉴权 header 和确认保护的集成覆盖
  • tests/profile.rs:profile 命令和上下文解析的集成覆盖
  • tests/redaction.rs:脱敏行为的集成覆盖
  • scripts/mutation-smoke.sh:固定 Apollo Portal + H2 变更 smoke 与状态断言