diff --git a/docs/secrets.md b/docs/secrets.md index aaa4c20e5..d2de3adea 100644 --- a/docs/secrets.md +++ b/docs/secrets.md @@ -17,16 +17,16 @@ secrets: - **Environment variables** whose names match common secret patterns (`KEY`, `SECRET`, `TOKEN`, `PASSWORD`, `PASS`, `AUTH`, `CREDENTIAL`, `PRIVATE`, `OAUTH`) with values >= 8 characters - **`secrets.yml` files** (see below) -2. Outbound text messages to the LLM have secret values replaced with deterministic placeholders like `#AB12#`. +2. Outbound text messages to the LLM have secret values replaced with deterministic placeholders like `#AB12#`, `#AB12:L#`, or `#GITHUBTOKEN_AB12:L#`. 3. Session context is deep-walked and obfuscation placeholders are restored when building display/resume context. Replace-mode substitutions are one-way and are not restored. Two modes control what happens to each secret: -| Mode | Behavior | Reversible | -| --------------------- | ------------------------------------------------------- | -------------------------------------------- | -| `obfuscate` (default) | Replaced with deterministic placeholder `#[A-Z0-9]{4}#` | Yes (deobfuscated in display/resume context) | -| `replace` | Replaced with deterministic same-length string | No (one-way) | +| Mode | Behavior | Reversible | +| --------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------- | +| `obfuscate` (default) | Replaced with deterministic placeholder `#[A-Z0-9]{4}(?::[ULCM])?#`, optionally name-prefixed | Yes (deobfuscated in display/resume context) | +| `replace` | Replaced with deterministic same-length string | No (one-way) | ## secrets.yml @@ -43,13 +43,14 @@ Project entries override global entries with matching `content`. Each entry in the array has these fields: -| Field | Type | Required | Description | -| ------------- | ---------------------------- | -------- | ------------------------------------------------- | -| `type` | `"plain"` or `"regex"` | Yes | Match strategy | -| `content` | string | Yes | The secret value (plain) or regex pattern (regex) | -| `mode` | `"obfuscate"` or `"replace"` | No | Default: `"obfuscate"` | -| `replacement` | string | No | Custom replacement (replace mode only) | -| `flags` | string | No | Regex flags (regex type only) | +| Field | Type | Required | Description | +| -------------- | ---------------------------- | -------- | ------------------------------------------------------------- | +| `type` | `"plain"` or `"regex"` | Yes | Match strategy | +| `content` | string | Yes | The secret value (plain) or regex pattern (regex) | +| `mode` | `"obfuscate"` or `"replace"` | No | Default: `"obfuscate"` | +| `replacement` | string | No | Custom replacement (replace mode only) | +| `flags` | string | No | Regex flags (regex type only) | +| `friendlyName` | string | No | Sanitized model-visible label for obfuscate-mode placeholders | ### Examples @@ -67,6 +68,29 @@ Each entry in the array has these fields: replacement: "********" ``` +#### Friendly names + +`friendlyName` adds semantic context to reversible obfuscation placeholders without exposing the secret value: + +```yaml +- type: plain + content: github_pat_abc123def456 + friendlyName: GitHub Token +``` + +This produces placeholders shaped like `#GITHUBTOKEN_AB12:L#`. The friendly name is sanitized to uppercase letters and digits, capped at 32 characters, and omitted if it sanitizes to an empty value. Invalid optional `friendlyName` metadata does not disable the secret entry; the secret still obfuscates with an unlabeled placeholder. + +The hash base is derived from the case-folded secret value, so casing variants share a hash with a case hint suffix: + +| Hint | Meaning | +| ---- | -------------------------------------------- | +| `:U` | all cased ASCII letters are uppercase | +| `:L` | all cased ASCII letters are lowercase | +| `:C` | first cased ASCII letter uppercase, rest lower | +| `:M` | mixed ASCII casing | + +`friendlyName` on regex entries labels the configured regex entry, not the matched value. Keep regex labels broad enough to be true for every match. + #### Regex secrets ```yaml diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index ce58d520d..b742d8f3d 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added `friendlyName` support for hidden secrets so model-visible placeholders can carry sanitized semantic labels, content-derived hashes, and case hints while preserving exact deobfuscation ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). + ## [16.0.1] - 2026-06-15 ### Breaking Changes