Canonical secrets policy for agents + best-effort redaction
deploy / deploy (push) Canceled after 0s

- /security.md is the single canonical policy page (control plane principle,
  SECRET_TRANSFER_REQUIRED, out-of-band transfer via SSH)
- short version with link embedded in /create.md, room .md, llms.txt, landing,
  MCP create tool response; docs updated
- redactSecrets() applied on input to messages, questions, resolutions,
  contracts and room brief/goal/participant instructions (best-effort: PEM
  keys, JWTs, common token prefixes, password/token/secret assignments)
This commit is contained in:
2026-09-06 21:49:15 +03:00
parent bb0eb6979e
commit fde1ae152f
11 changed files with 162 additions and 9 deletions
+25 -1
View File
@@ -1,6 +1,6 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { RendezvousService, Store, RendezvousError } from '../src/index.js';
import { RendezvousService, Store, RendezvousError, redactSecrets } from '../src/index.js';
function makeService(): { svc: RendezvousService; dbPath: string } {
const dbPath = `:memory:`;
@@ -186,6 +186,30 @@ test('join: creator auto-joined, invitee reports once and idempotently', () => {
assert.equal(again.joined_at, ts);
});
test('redactSecrets strips obvious secret values (best-effort)', () => {
const input = [
'db password: hunter2secret123',
'token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N65IWDpmNfXQ',
'key sk-abcdefabcdefabcdefabcdef',
'-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAsecret\n-----END RSA PRIVATE KEY-----',
'ok: the db password lives in vault prod/db, deliver via scp',
].join('\n');
const out = redactSecrets(input);
assert.ok(!out.includes('hunter2secret123'), 'password value must be redacted');
assert.ok(!out.includes('eyJhbGciOi'), 'JWT must be redacted');
assert.ok(!out.includes('sk-abcdefabcdef'), 'prefixed token must be redacted');
assert.ok(!out.includes('MIIEpAIBAAKCAsecret'), 'private key must be redacted');
assert.ok(out.includes('[REDACTED'), 'redaction marker present');
// safe discussion is untouched
assert.ok(out.includes('lives in vault prod/db'), 'name/source discussion kept');
// and redaction is applied on the way into a room
const { svc } = makeService();
const created = createTwoPartyRoom(svc);
const msg = svc.postMessage(created.room_id, created.participants[0].token, 'api_key: supersecretvalue99');
assert.ok(!msg.content.includes('supersecretvalue99'));
assert.ok(msg.content.includes('[REDACTED'));
});
test('only addressee or author can resolve a question', () => {
const { svc } = makeService();
const created = createTwoPartyRoom(svc);