/** * [ref]([ref])—— **密钥形 env 剥除的留痕面**(core D1 `scrubSecretEnv` 的可观测半场)。 * * ## 它解决的问题 * `scrubSecretEnv` 是本仓两条 shell/子进程腿的**安全默认**:模型可驱动的 shell(`inheritEnv:"scrub"`)与 * git 子进程(钩子/凭证助手)拿到的 env 里,`*_KEY`/`*_TOKEN`/`*_SECRET`/`*_PASSWORD`… 一律先丢掉。 * 两处都以**单参形**调用,于是「这一次到底丢了哪些 key、按哪条规则(suffix-rule / exact-name)、置信度多少」 * **零留痕** —— 部署方既证明不了保护生效过,也发现不了它悄悄不生效了(词表漂移 / 一个新的密钥命名法从 * 规则的缝里穿过去 / 某条腿被改成 `inheritEnv:"all"`)。core 早就把收集口开好了(`findings?: * SecretEnvFinding[]`,d.ts 原话:the VALUE is never carried — this record is meant to be loggable), * 缺的只是本仓这半场。本模块就是那半场,**不是**一个新的执法面:它一个字节也不改变剥除行为。 * * ## 形(照 `fail-open.ts` 的仓内先例) * 1. **计数(逐次)** —— `secret_env_scrubbed_total{site,kind,confidence}`; * 2. **结构化披露(每 site×key 一次)** —— 首次在某条腿上丢掉某个 key 时一条 `info`,之后同 key 只走计数。 * 不是「每 site 一次」:一个**新**的密钥形 key 后来才出现(部署加了一个凭证)时,那才是最该看见的一行。 * 值永不进任何一件(core 的 finding 本身就不携带值)。 * * ## 为什么是进程级自由函数而不是注入 * 与 `recordFailOpen` 同因:两个调用点都在**没有 logger/metrics 句柄**的深处 * (`plugins/remote-env-host.ts` 的 `mergeEnv` 全文零观测通道;`project-memory.ts` 的 `git()` 是个自由函数)。 * 装配层用 {@link installSecretEnvScrubRecorder} 把句柄接上,装配之前命中的次数不会丢(计数照常累加, * install 时一次性补进 metrics),披露行则在下一次命中时补发(未成功披露的 key 不进 `disclosed` 集)。 */ import { type SecretEnvFinding } from "@sema-agent/core"; import type { Logger } from "./logger.js"; import type { Metrics } from "./metrics.js"; /** 登记过的剥除现场。闭集:未登记的 site 传不进 {@link recordSecretEnvScrub}(编译期拒,同 FAIL_OPEN_TAGS 纪律)。 */ export declare const SECRET_ENV_SCRUB_SITES: { readonly "server.remote-env-host.inherit-scrub": "模型可驱动的 host shell 继承 env(`inheritEnv:\"scrub\"` 默认腿)——这条腿上的一次泄漏等于把编排器的脑钥/仓库令牌交给模型选的命令"; readonly "server.project-memory.git-subprocess": "project-memory 读仓叙事时的 git 子进程 env —— 仓内的钩子/凭证助手会以本进程身份运行"; }; /** 词表键推导的闭集类型。 */ export type SecretEnvScrubSite = keyof typeof SECRET_ENV_SCRUB_SITES; interface Sink { logger?: Logger; metrics?: Metrics; } /** * 记一次剥除。**总不抛** —— 观测本身绝不能变成故障(同 `recordFailOpen` / reapers 的判据)。 * `findings` 为空(这一次没丢任何 key)时什么也不做:那不是事件,是常态。 */ export declare function recordSecretEnvScrub(site: SecretEnvScrubSite, findings: readonly SecretEnvFinding[]): void; /** 装配层把 logger/metrics 接上(main.ts,与 `installFailOpenRecorder` 同一处)。装配前累计的次数在此补进 metrics。 */ export declare function installSecretEnvScrubRecorder(deps: Sink): void; /** 已留驻的「现场×键」条数(测试/诊断读面)。恒 ≤ {@link DISCLOSED_CAP}。 */ export declare function secretEnvScrubDisclosedSize(): number; /** 本进程各桶的累计次数(测试/诊断读面)。 */ export declare function secretEnvScrubCounts(): ReadonlyMap; /** 测试用重置(进程级状态在同一个 vitest worker 里跨用例存活)。 */ export declare function resetSecretEnvScrubRecorderForTest(deps?: Sink): void; export {}; //# sourceMappingURL=secret-env-scrub.d.ts.map