Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
42 changes: 42 additions & 0 deletions app/src/features/share/shareContent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,48 @@ describe('redactSensitive', () => {
expect(redactSensitive('mail jane.doe@example.com now')).toContain('[email]');
});

// The last-resort rule requires an upper-case character so it does not fire on
// prose. Everything below is lower-case + digits, so it reached the card intact
// until these patterns were added. Each string is a shape-accurate dummy.
//
// The Slack ones are assembled from parts on purpose: written as one literal they
// match GitHub's Slack-token detector well enough that push protection rejects the
// commit, which would block this file for anyone pushing it.
const slackToken = (prefix: string, ...rest: string[]) => [prefix, ...rest].join('-');

test.each([
['slack bot token', slackToken('xoxb', '123456789012', '987654321098', 'abcdefghijklmnop')],
['slack user token', slackToken('xoxp', '987654321098', '123456789012', 'zyxwvutsrqponmlk')],
['gitlab personal access token', 'glpat-abcdefghij1234567890'],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
['huggingface token', 'hf_abcdefghijklmnopqrstuvwxyz1234'],
])('scrubs an all-lower-case %s', (_label, secret) => {
const out = redactSensitive(`saved ${secret} for you`);
expect(out).toContain('[redacted]');
expect(out).not.toContain(secret);
});

test.each([
['slack', 'https://hooks.slack.com/services/T00000000/B00000000/abcdefghijklmnopqrst'],
[
'discord',
'https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz012345',
],
])('scrubs a %s webhook URL, which carries its secret in the path', (_label, url) => {
expect(redactSensitive(`posting to ${url} now`)).not.toContain(url);
});

test('survives stripMarkdown running first, as buildFallbackHeadline runs it', () => {
// stripMarkdown removes `_`, so a pattern that insisted on it would never match.
const head = buildFallbackHeadline('Done. Saved hf_abcdefghijklmnopqrstuvwxyz1234 for you.');
expect(head).not.toContain('abcdefghijklmnopqrstuvwxyz');
expect(head).toContain('[redacted]');
});

test('does not fire on ordinary lower-case prose', () => {
const clean = 'renamed the folder to archive and moved twelve files into it';
expect(redactSensitive(clean)).toBe(clean);
});

test('is idempotent and leaves clean prose untouched', () => {
const clean = 'Summarised three months of emails in twelve seconds';
expect(redactSensitive(clean)).toBe(clean);
Expand Down
13 changes: 13 additions & 0 deletions app/src/features/share/shareContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ const REDACTIONS: ReadonlyArray<{ re: RegExp; with: string }> = [
{ re: /\bBearer\s+[A-Za-z0-9._-]{12,}\b/gi, with: '[redacted]' },
// AWS access key ids.
{ re: /\bAKIA[0-9A-Z]{16}\b/g, with: '[redacted]' },
// Vendor-prefixed credentials whose body is lower-case and digits only. The
// last-resort rule below cannot reach these: it requires an upper-case letter so
// it does not fire on prose, and an all-lower-case token slips straight past it.
// The `_` is optional because `stripMarkdown` strips emphasis characters before
// this runs, so `hf_abc…` arrives here as `hfabc…`.
{ re: /\b(?:xox[abeprs]|xapp)-[A-Za-z0-9-]{10,}/g, with: '[redacted]' },
{ re: /\bglpat-[A-Za-z0-9_-]{16,}/g, with: '[redacted]' },
{ re: /\bhf_?[a-z0-9]{20,}\b/g, with: '[redacted]' },
// Webhook URLs carry the secret in the path, so the whole URL has to go.
{
re: /\bhttps?:\/\/(?:hooks\.slack\.com|discord(?:app)?\.com\/api\/webhooks)\/[^\s"'`)]+/gi,
with: '[redacted]',
},
// Long opaque hex runs (>= 32 chars) that look like secrets, not prose.
{ re: /\b[A-Fa-f0-9]{32,}\b/g, with: '[redacted]' },
// Long opaque base64/base64url runs (>= 24 chars) that mix upper/lower/digit,
Expand Down
Loading