Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,33 @@ Neither command needs a secret key. Balance checks take public keys:
- **Never** commit `.env` with secrets (already in `.gitignore`).
- **Never** put `S…` secret keys in `VITE_*` — they end up in public JS.
- Rotate any key that was pasted in chat or logs.

## Support log redaction & troubleshooting

Before attaching terminal transcripts, container logs, or browser exports to an
issue, pull request, or support channel, strip every credential, bearer token,
and pre-reveal secret listed below. Structured logger output from
`@sub-rosa/logging` automatically scrubs common secret keys (`secret`, `token`,
`password`, `privateKey`, `credential`, `cookie`, `authorization`, `apiKey`,
`mnemonic`, `seedPhrase`), `S…` Stellar secret seeds, PEM blocks, `Bearer` /
`Basic` headers, and URL credentials to `[REDACTED]`, but raw shell command
lines, unhandled crash dumps, and DevTools HAR files can still include them:

- **Keeper logs (`services/keeper`):** Remove `KEEPER_SECRET`, `OPERATOR_SECRET`,
and `BIDDER_SECRET` (`S…` Stellar secret seeds), provider-authenticated
`RPC_URL` or `STELLAR_RPC_URL` strings (basic-auth userinfo
`https://user:pass@…` or query parameters such as `?api_key=…` / `?token=…`),
and any unrevealed bid `value` or `nonce` prior to Drand round `R`.
- **Appraisal API logs (`services/appraisal-api`):** Remove
`FACILITATOR_SECRET`, `Authorization` (`Bearer` / `Basic`) headers, x402
payment headers (`X-Payment` / signed XDR payloads), and provider-keyed
`RPC_URL` endpoints.
- **SDK & relayer logs (`packages/sdk`):** Remove `STELLAR_SECRET_KEY`,
`OZ_CHANNELS_API_KEY`, session Ed25519 private keys, round auditor secret
keys, and unrevealed bid plaintext (`value`, `nonce`) before `open_reveal`
succeeds on-chain.
- **Browser & DevTools logs (`apps/web`):** Remove passkey/session key material
in `localStorage` or `sessionStorage`, `Cookie` and `Authorization` headers in
Network HAR exports, wallet seed phrases or `S…` secret keys, and local
unrevealed bid values/nonces before the round enters `Revealing`.

49 changes: 46 additions & 3 deletions scripts/check-deploy-docs.test.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Copyright (c) 2026 Sub Rosa contributors
import { execFileSync } from "node:child_process";
import { mkdirSync, mkdtempSync, copyFileSync, writeFileSync, rmSync } from "node:fs";
import { mkdirSync, mkdtempSync, copyFileSync, readFileSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, it } from "node:test";
import { fileURLToPath } from "node:url";
import assert from "node:assert/strict";

const SCRIPT_PATH = new URL("check-deploy-docs.mjs", import.meta.url).pathname;
const CWD = new URL("..", import.meta.url).pathname;
const SCRIPT_PATH = fileURLToPath(new URL("check-deploy-docs.mjs", import.meta.url));
const CWD = fileURLToPath(new URL("..", import.meta.url));

function runCheck(env = {}) {
return execFileSync("node", [SCRIPT_PATH], {
Expand Down Expand Up @@ -140,4 +141,46 @@ describe("check-deploy-docs", () => {
rmSync(tmpDir, { recursive: true, force: true });
}
});

it("documents safe support-log redaction across keeper, appraisal, SDK, and browser logs", () => {
const deployDoc = readFileSync(join(CWD, "docs", "DEPLOY.md"), "utf8");
const sectionIdx = deployDoc.indexOf("## Support log redaction & troubleshooting");
assert.ok(
sectionIdx !== -1,
"docs/DEPLOY.md must include '## Support log redaction & troubleshooting'",
);

const section = deployDoc.slice(sectionIdx);
for (const surface of [
"Keeper logs (`services/keeper`)",
"Appraisal API logs (`services/appraisal-api`)",
"SDK & relayer logs (`packages/sdk`)",
"Browser & DevTools logs (`apps/web`)",
]) {
assert.ok(
section.includes(surface),
`support-log redaction section must cover ${surface}`,
);
}

for (const field of [
"KEEPER_SECRET",
"OPERATOR_SECRET",
"BIDDER_SECRET",
"FACILITATOR_SECRET",
"STELLAR_SECRET_KEY",
"OZ_CHANNELS_API_KEY",
"Authorization",
"Cookie",
"localStorage",
"sessionStorage",
"nonce",
"[REDACTED]",
]) {
assert.ok(
section.includes(field),
`support-log redaction section must list ${field}`,
);
}
});
});