fix(ce-demo-reel): prevent secrets in recorded demos (#664)
Some checks failed
CI / pr-title (push) Has been cancelled
CI / test (push) Has been cancelled
Release PR / release-pr (push) Has been cancelled
Release PR / publish-cli (push) Has been cancelled

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trevin Chow
2026-04-23 21:52:52 -07:00
committed by GitHub
parent 75cf4d603d
commit 9ddcd22aee
5 changed files with 47 additions and 7 deletions

View File

@@ -14,6 +14,18 @@ If real product usage is impractical (requires API keys, cloud deploy, paid serv
Never generate fake or placeholder image/GIF URLs. If upload fails, report the failure.
## Never Record Secrets
Recordings must never contain credentials — not in commands, output, URL bars, or on-screen UI. If the demo needs a credential, set it before the recording starts, outside the recorded region.
**Core principle:** secrets should affect the environment, not the visible transcript. Hidden *real* setup beats visible *fake* setup — fake setup breaks the demo and still leaks the secret's shape.
- **Plan it out of frame.** Route every surface where a secret could appear (env exports, CLI flag values, command output, auth headers, URL params, DevTools, config pages) out of the recorded region. Use VHS `Hide`/`Show`; invoke CLIs via env vars, not secret flag values; stay on user-facing pages. Show the authenticated result, not the auth step.
- **Do not substitute placeholders inside the recording.** Typing a fake `sk-xxxxx` produces a misleading artifact; recapture with the real credential set out of frame instead. Two specific failures:
- Re-exporting a fake value visibly (`export API_KEY=REDACTED`) overwrites the real env var, so the demo breaks (401, `Unauthorized`, `0 credits remaining`, empty output). You leak the variable name *and* ship a broken product.
- Planning to blur or crop later. Assume anything shown is leaked; recapture is the only remediation.
- **Scan before upload.** Look for `sk-`, `ghp_`, `ghs_`, `xoxb-`, `Bearer `, `Authorization:`, `?token=`, `api_key=`, long hex/base64 near credential-sounding labels, or visible `.env` contents. If any appear, discard and recapture. Never blur or crop.
## Arguments
Parse `$ARGUMENTS`:

View File

@@ -84,6 +84,12 @@ agent-browser screenshot [RUN_DIR]/frame-01-initial.png
- Wait 2-3 seconds after navigation for the page to settle
- Capture the full viewport (sidebar, header give reviewers context)
**Keep secrets out of frame:**
- Do not open DevTools, the Network panel, or Application/Storage -- these expose auth headers, cookies, session storage, and tokens in plain view
- Skip pages that display raw credentials (unmasked API-key settings, OAuth consent screens, `.env` viewers, billing/payment detail)
- Check the URL bar before each screenshot -- if it carries a session token or credential query param (`?access_token=`, `?api_key=`, `#id_token=`), navigate to the clean canonical URL first
- Prefer a demo account or seeded fixture data over a real logged-in account when the screenshot will include account identifiers that are themselves sensitive
## Step 3: Stitch into GIF
Use the capture pipeline script to normalize frame dimensions, stitch with two-pass palette, and auto-reduce if over 10 MB:
@@ -100,8 +106,10 @@ python3 scripts/capture-demo.py stitch --duration 2.0 [RUN_DIR]/demo.gif [RUN_DI
**If stitching fails:** Fall back to static screenshots tier using the individual PNGs already captured. If no PNGs were captured, report the failure.
## Step 4: Cleanup
## Step 4: Secrets Scan and Cleanup
After successful GIF creation, remove individual PNG frames. Keep only the final GIF for upload.
Before uploading, inspect the final GIF for any credential material visible on-screen. If any appears, discard the GIF and recapture with the offending page or state routed out of frame. Do not upload, do not blur.
After a clean GIF is confirmed, remove individual PNG frames. Keep only the final GIF for upload.
Proceed to `references/upload-and-approval.md`.

View File

@@ -33,6 +33,11 @@ All checks passed
- 3-5 frames is ideal -- enough to tell the story, not so many the GIF is huge
- Strip unicode characters that silicon's default font can't render (checkmarks, fancy arrows)
**Never write secrets into the demo text:**
- Do not paste real credentials, API keys, tokens, or session IDs into any frame, even if copied from a real run
- Do not substitute fake-looking credentials like `sk-xxxxxxxxx` either -- that produces a misleading artifact. Instead, rewrite the command to use an env var whose *name* appears without a value (e.g., `your-cli --api-key "$API_KEY"`), or demonstrate a different command that doesn't take a secret
- If a sample output line would include a token, error trace with auth header, or other credential, edit that line out or pick a different scenario -- do not render it
## Step 2: Split into Frame Files
Split the demo content on `---` lines into separate text files, one per frame:

View File

@@ -7,6 +7,8 @@ Capture individual PNG screenshots. No animation, no stitching.
**Label:** "Screenshots"
**Required tools:** Varies (agent-browser for web, silicon for CLI, or native screenshot)
**Secrets rule applies here too.** For browser captures, do not open DevTools, do not screenshot URLs carrying tokens, and avoid pages that display unmasked credentials. For CLI captures, render output that was already free of credentials — no env-var dumps, no `--api-key` flag values, no auth headers in error traces. Scan each PNG before uploading; if anything credential-like appears, discard and recapture.
## Capture by Project Type
### Web app or desktop app (agent-browser available)

View File

@@ -15,6 +15,7 @@ Before generating a .tape file, determine:
- **Expected output** -- What the terminal should show when the command succeeds.
- **Terminal dimensions** -- Wide enough for the longest output line, tall enough to avoid scrolling.
- **Timing** -- Target 5-10 seconds total. Enough sleep after each command for output to render.
- **Secret exposure points** -- Any step that could surface a credential: env exports, `source .env`, `printenv`/`env`/`set`, CLIs with `--api-key`/`--token` flags, verbose/debug flags, commands that echo tokens in output or error traces, shell prompts with env-interpolated `$VAR` segments. Set real credentials inside a `Hide` block at the top of the `.tape`, run `clear` at the end of the block to flush the buffer, then `Show`. Use a clean `HOME` (`export HOME=$(mktemp -d)`) inside `Hide` so personal dotfiles, cached CLI tokens, and env-interpolated prompts can't leak.
## Step 2: Generate .tape File
@@ -29,16 +30,23 @@ Set Height 500
Set Theme "Catppuccin Mocha"
Set TypingSpeed 40ms
# Hide boring setup
# Hidden prelude: clean HOME, set real secrets, any setup that would leak.
# These commands execute for real but never appear in the GIF.
# `clear` at the end flushes the buffer so Show starts on a clean screen.
Hide
Type "export HOME=$(mktemp -d)"
Enter
Type "export API_KEY='real-secret-value'"
Enter
Type "cd /path/to/project"
Enter
Sleep 500ms
Type "clear"
Enter
Show
# The demo
# Visible demo: commands consume the env set above, but never re-export,
# echo, or print it. Show the feature working -- not the auth mechanism.
Type "your-cli-command --flag value"
Sleep 500ms
Enter
Sleep 3s
@@ -46,6 +54,8 @@ Sleep 3s
Sleep 2s
```
**Why this shape:** success of the visible command is itself evidence the credential was set — no need to show the auth step. Never add a visible `export SECRET=...` with a fake value: it leaks the variable name and breaks the demo.
**Key .tape directives:**
- `Output [path]` -- Where to write the GIF (must be first line)
- `Set FontSize [14-18]` -- Larger for readability
@@ -79,7 +89,10 @@ Read the generated GIF to verify:
1. Commands are visible and readable
2. Output renders completely (not cut off)
3. The feature being demonstrated is clearly shown
4. No secrets, credentials, or sensitive paths are visible
**Secrets scan (hard gate):** Scan the GIF for credential material. If any appears, discard and re-record with the leaking step wrapped in `Hide`/`Show` or replaced. Do not upload, do not blur.
**Drift check:** A broken visible command — `401 Unauthorized`, `Invalid API key`, `0 credits remaining`, empty output where data was expected — usually means a visible `export SECRET=...` after `Show` overwrote the real env. Fix the `.tape` so secrets are set in `Hide` only, never re-exported, and re-record.
If quality is poor, revise the .tape file and re-record.