@theronap/cortex-mcp 0.9.44 → 0.9.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,35 +0,0 @@
1
- import { test, expect } from 'bun:test'
2
- import { decideSend, loadSendAllowlist, phoneKey } from './imessage_send.mjs'
3
-
4
- const allow = loadSendAllowlist('+18015551234, mom@example.com')
5
-
6
- test('draft-by-default: no send flag → draft, never sends (D3)', () => {
7
- const d = decideSend({ recipient: '+18015551234', message: 'hi', send: false, allowlist: allow, confirmSecret: null })
8
- expect(d.action).toBe('draft')
9
- })
10
-
11
- test('allowlisted recipient + send:true → send (D10)', () => {
12
- expect(decideSend({ recipient: '+1 (801) 555-1234', message: 'hi', send: true, allowlist: allow, confirmSecret: null }).action).toBe('send')
13
- expect(decideSend({ recipient: 'MOM@example.com', message: 'hi', send: true, allowlist: allow, confirmSecret: null }).action).toBe('send')
14
- })
15
-
16
- test('off-list recipient + send:true, no secret → BLOCKED (D10 prompt-injection guard)', () => {
17
- const d = decideSend({ recipient: '+19998887777', message: 'hi', send: true, allowlist: allow, confirmSecret: null })
18
- expect(d.action).toBe('blocked')
19
- })
20
-
21
- test('off-list recipient sends only with the correct out-of-band confirm secret', () => {
22
- expect(decideSend({ recipient: '+19998887777', message: 'hi', send: true, confirm: 'wrong', allowlist: allow, confirmSecret: 'sesame' }).action).toBe('blocked')
23
- expect(decideSend({ recipient: '+19998887777', message: 'hi', send: true, confirm: 'sesame', allowlist: allow, confirmSecret: 'sesame' }).action).toBe('send')
24
- })
25
-
26
- test('empty recipient/message is blocked', () => {
27
- expect(decideSend({ recipient: '', message: 'hi', send: true, allowlist: allow, confirmSecret: null }).action).toBe('blocked')
28
- expect(decideSend({ recipient: '+18015551234', message: ' ', send: true, allowlist: allow, confirmSecret: null }).action).toBe('blocked')
29
- })
30
-
31
- test('phoneKey + allowlist normalization', () => {
32
- expect(phoneKey('+1 (801) 555-1234')).toBe('8015551234')
33
- expect(allow.has('8015551234')).toBe(true)
34
- expect(allow.has('mom@example.com')).toBe(true)
35
- })
@@ -1,88 +0,0 @@
1
- import { test, expect } from 'bun:test'
2
- import { redactSecrets } from './redact.mjs'
3
-
4
- // The 2026-06-22 finding: a Claude Code login token (sk-ant-oat01-…) was sitting inlined
5
- // in a Stop-hook command and could ride a transcript tail to the org. Capture must never
6
- // transmit a credential. These assert known secret shapes are stripped — and that ordinary
7
- // prose / record UUIDs are left intact (no false positives that would mangle real content).
8
-
9
- test('redacts an Anthropic OAuth (Claude Code login) token', () => {
10
- const s = 'CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-oyo53qZ8m_WSrYZU8rrpWrxmgtbO1T8hSOhhpicMqeZ4Ixtwzbj0qwb in the hook'
11
- const out = redactSecrets(s)
12
- expect(out).not.toContain('sk-ant-oat01-oyo53qZ8m')
13
- expect(out).toContain('[REDACTED:anthropic-oauth]')
14
- })
15
-
16
- test('redacts a range of credential shapes', () => {
17
- const cases = [
18
- ['sk-ant-api03-' + 'a'.repeat(40), 'anthropic-key'],
19
- ['sk-proj-' + 'b'.repeat(40), 'openai'],
20
- ['sk-' + 'c'.repeat(40), 'openai'],
21
- ['ghp_' + 'd'.repeat(36), 'github'],
22
- ['github_pat_' + 'e'.repeat(30), 'github-pat'],
23
- ['AKIA' + 'ABCDEFGHIJKLMNOP', 'aws-akid'],
24
- ['AIza' + 'f'.repeat(35), 'google'],
25
- ['xoxb-' + '1234567890-abcdef', 'slack'],
26
- ['eyJ' + 'a'.repeat(20) + '.' + 'b'.repeat(20) + '.' + 'c'.repeat(20), 'jwt'],
27
- ]
28
- for (const [secret, tag] of cases) {
29
- const out = redactSecrets(`token: ${secret} end`)
30
- expect(out).toContain(`[REDACTED:${tag}]`)
31
- expect(out).not.toContain(secret)
32
- }
33
- })
34
-
35
- test('redacts a Bearer token but keeps the scheme', () => {
36
- const out = redactSecrets('Authorization: Bearer abcdef0123456789ABCDEFxyz')
37
- expect(out).toBe('Authorization: Bearer [REDACTED]')
38
- })
39
-
40
- test('redacts a PEM private key block', () => {
41
- const out = redactSecrets('-----BEGIN RSA PRIVATE KEY-----\nMIIE...\n-----END RSA PRIVATE KEY-----')
42
- expect(out).toContain('[REDACTED:private-key]')
43
- expect(out).not.toContain('MIIE')
44
- })
45
-
46
- test('leaves ordinary prose and record UUIDs untouched', () => {
47
- const prose = 'Fixed the ingest latency; record 5203eacd-321b-43f7-bae2-4d6e7cae96ab landed in ~0.3s.'
48
- expect(redactSecrets(prose)).toBe(prose)
49
- })
50
-
51
- // The 2026-07-02 finding: a grep of ~/.codex/hooks.json printed the live CORTEX_TOKEN (a bare
52
- // UUID — no pattern above catches those) into a transcript. The inline form is gone from hooks
53
- // (capture self-resolves now), but transcripts can still carry config lines from ANY tool read.
54
- test('redacts CORTEX_TOKEN in env-assignment and TOML/JSON forms', () => {
55
- const uuid = 'ee0455d0-49bd-4141-984d-ece9311f9407'
56
- const cases = [
57
- `CORTEX_TOKEN=${uuid} npx -y @theronap/cortex-mcp@latest capture`, // legacy hook command
58
- `"CORTEX_TOKEN": "${uuid}"`, // ~/.claude.json
59
- `CORTEX_TOKEN = "${uuid}"`, // config.toml
60
- ]
61
- for (const s of cases) {
62
- const out = redactSecrets(s)
63
- expect(out).toContain('[REDACTED:cortex-token]')
64
- expect(out).not.toContain(uuid)
65
- }
66
- })
67
-
68
- test('redacts generic secret-shaped env assignments', () => {
69
- const out = redactSecrets('export SUPABASE_SERVICE_SECRET=abcDEF0123456789xyz && run')
70
- expect(out).toBe('export SUPABASE_SERVICE_SECRET=[REDACTED:env] && run')
71
- const out2 = redactSecrets('MY_API_KEY: "0123456789abcdef0123"')
72
- expect(out2).toContain('[REDACTED:env]')
73
- })
74
-
75
- test('generic env pattern leaves short placeholders and prose intact', () => {
76
- const cases = [
77
- 'set YOUR_TOKEN=xxx in the env', // short placeholder value
78
- 'the CORTEX_TOKEN is stored in ~/.claude.json', // prose, no assignment value
79
- 'record 5203eacd-321b-43f7-bae2-4d6e7cae96ab', // bare UUID, no key name
80
- ]
81
- for (const s of cases) expect(redactSecrets(s)).toBe(s)
82
- })
83
-
84
- test('handles empty / non-string input safely', () => {
85
- expect(redactSecrets('')).toBe('')
86
- expect(redactSecrets(null)).toBe(null)
87
- expect(redactSecrets(undefined)).toBe(undefined)
88
- })
@@ -1,39 +0,0 @@
1
- import { describe, it, expect } from 'bun:test'
2
- import { planOrgInstall } from './skills.mjs'
3
-
4
- describe('planOrgInstall — the collision + validity gate', () => {
5
- it('installs valid served skills', () => {
6
- const { install, skipped } = planOrgInstall(
7
- [{ name: 'deploy-runbook', body_md: '---\nname: deploy-runbook\n---\nbody' }],
8
- ['cortex-log', 'cortex-context'],
9
- )
10
- expect(install).toEqual([{ name: 'deploy-runbook', source: '---\nname: deploy-runbook\n---\nbody' }])
11
- expect(skipped).toEqual([])
12
- })
13
- it('bundled core skills win name collisions (org can never shadow cortex-log)', () => {
14
- const { install, skipped } = planOrgInstall(
15
- [{ name: 'cortex-log', body_md: 'evil override' }],
16
- ['cortex-log'],
17
- )
18
- expect(install).toEqual([])
19
- expect(skipped[0]).toMatchObject({ name: 'cortex-log' })
20
- })
21
- it('drops invalid names (path tricks, uppercase, empty) and empty bodies', () => {
22
- const { install, skipped } = planOrgInstall(
23
- [
24
- { name: '../escape', body_md: 'x' },
25
- { name: 'UPPER', body_md: 'x' },
26
- { name: 'ok-name', body_md: ' ' },
27
- { name: '', body_md: 'x' },
28
- { name: 'fine', body_md: 'x' },
29
- ],
30
- [],
31
- )
32
- expect(install).toEqual([{ name: 'fine', source: 'x' }])
33
- expect(skipped.length).toBe(4)
34
- })
35
- it('tolerates a malformed served list', () => {
36
- expect(planOrgInstall(null, []).install).toEqual([])
37
- expect(planOrgInstall([null, {}, { name: 'a' }], []).install).toEqual([])
38
- })
39
- })