diff --git a/skills/ocx/SKILL.md b/skills/ocx/SKILL.md index cba29e7dd9..dea52e4414 100644 --- a/skills/ocx/SKILL.md +++ b/skills/ocx/SKILL.md @@ -90,6 +90,13 @@ starring would be useful, say so and let the user decide. The same boundary covers the session-gated `/api/codex-prompt` writes: read them with `ocx inspect codex-prompt`, and leave the writes to the dashboard. +## Secret-bearing commands + +**Do not run `ocx access key create`.** Its one-time response contains the new plaintext +data-plane credential, and command output can enter the agent transcript. Ask the user to create +the key themselves in a terminal outside the agent session and confirm only the new key id before +continuing with inspection or removal commands. Never ask the user to paste the key into chat. + ## Destructive verbs `storage trash restore` and `storage policy run` refuse without `--yes` (exit 2, nothing sent). diff --git a/skills/ocx/references/03_recipes.md b/skills/ocx/references/03_recipes.md index a6294b277e..e3d687f763 100644 --- a/skills/ocx/references/03_recipes.md +++ b/skills/ocx/references/03_recipes.md @@ -93,20 +93,27 @@ Read `accounts[]`. Two things to respect: `providers[]` and `models[]` carry `estimatedCostUsd`. Costs are estimates; `estimateReasons` in the log rows tells you why (for example `usage_estimated`, `expected_price_overlay`). -## 5. Rotate an access key and confirm it went quiet +## 5. Prepare an access-key rotation without exposing the new key ```bash ocx access key list --json -ocx access key create rotated --json # the plaintext key is in THIS response only +``` + +Creating a key returns its one-time plaintext credential. **Do not run the create command from an +agent session:** terminal output can enter the model transcript. Ask the user to create the key +themselves in a separate terminal and report only the new key id, never the key itself. + +After the user confirms that the replacement is configured, remove the old key: + +```bash ocx access key remove --yes --json ocx access key list --json # the old id is gone; check usage on the rest ``` -Note the argument style: `create ` and `remove ` are **positionals**, not `--label` and -`--id`. `remove` also refuses without `--yes`. +Note the argument style: `remove ` is positional, not `--id`, and refuses without `--yes`. The list carries per-key usage, so a key whose count stops advancing is genuinely unused. The -plaintext key appears once, in the `create` response, and is never retrievable again. +replacement key's plaintext is never retrievable after creation. An `ambiguous` footer on the list means two configured keys share an id, so per-key totals do not exist for them — do not attribute usage to either. diff --git a/tests/skill-ocx.test.ts b/tests/skill-ocx.test.ts index 37edcfb168..3d84deeb39 100644 --- a/tests/skill-ocx.test.ts +++ b/tests/skill-ocx.test.ts @@ -146,6 +146,14 @@ describe("the consent boundary is stated, not implied", () => { } }); + test("agent-facing instructions never invoke the plaintext access-key creation command", () => { + const skill = readFileSync(SKILL, "utf8"); + const recipes = read("references/03_recipes.md"); + expect(skill).toContain("Do not run `ocx access key create`"); + expect(recipes).not.toMatch(/^\s*ocx access key create\b/m); + expect(recipes).toContain("never the key itself"); + }); + test("destructive verbs are documented as requiring --yes", () => { const skill = readFileSync(SKILL, "utf8"); const recipes = read("references/03_recipes.md");