pi-hermes-memory 0.3.0 → 0.3.1
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.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/store/content-scanner.ts +56 -1
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ Your Pi agent normally forgets everything when you close a session. This extensi
|
|
|
18
18
|
| **Context Fencing** | Memory blocks are wrapped in `<memory-context>` tags so the LLM never treats stored facts as user instructions |
|
|
19
19
|
| **Memory Aging** | Entries carry timestamps — consolidation knows which facts are stale and which are fresh |
|
|
20
20
|
| **Project Memory** | Per-project memory (`~/.pi/agent/<project>/MEMORY.md`) alongside your global memory |
|
|
21
|
+
| **Secret Detection** | API keys, tokens, SSH keys, and credential assignments are blocked from being persisted to memory |
|
|
21
22
|
|
|
22
23
|
## How It Works
|
|
23
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-hermes-memory",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Your Pi agent remembers everything across sessions — your preferences, your stack, your corrections, and even how it solved problems. Zero-config install, works immediately. Persistent memory + procedural skills + auto-correction detection + security-first content scanning.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -18,13 +18,46 @@ const MEMORY_THREAT_PATTERNS: Array<{ pattern: RegExp; id: string }> = [
|
|
|
18
18
|
{ pattern: /\$HOME\/\.ssh|~\/\.ssh/i, id: "ssh_access" },
|
|
19
19
|
];
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Secret detection patterns — checks for credentials, API keys, tokens, and
|
|
23
|
+
* environment variable leaks that should never be persisted to memory.
|
|
24
|
+
* Ported from pk-pi-hermes-evolve engine.ts scanForSecrets().
|
|
25
|
+
*/
|
|
26
|
+
const SECRET_PATTERNS: Array<{ pattern: RegExp; id: string; severity: "high" | "medium" }> = [
|
|
27
|
+
// API keys
|
|
28
|
+
{ pattern: /\bsk-ant-api\S{10,}\b/, id: "anthropic_api_key", severity: "high" },
|
|
29
|
+
{ pattern: /\bsk-or-v1-\S{10,}\b/, id: "openrouter_api_key", severity: "high" },
|
|
30
|
+
{ pattern: /\bsk-\S{20,}\b/, id: "openai_api_key", severity: "high" },
|
|
31
|
+
{ pattern: /\bAKIA[0-9A-Z]{16}\b/, id: "aws_access_key", severity: "high" },
|
|
32
|
+
// Tokens
|
|
33
|
+
{ pattern: /\bghp_\S{10,}\b/, id: "github_personal_token", severity: "high" },
|
|
34
|
+
{ pattern: /\bghu_\S{10,}\b/, id: "github_user_token", severity: "high" },
|
|
35
|
+
{ pattern: /\bxoxb-\S{10,}\b/, id: "slack_bot_token", severity: "high" },
|
|
36
|
+
{ pattern: /\bxapp-\S{10,}\b/, id: "slack_app_token", severity: "high" },
|
|
37
|
+
{ pattern: /\bntn_\S{10,}\b/, id: "notion_token", severity: "high" },
|
|
38
|
+
{ pattern: /\bBearer\s+\S{20,}\b/, id: "bearer_auth_token", severity: "high" },
|
|
39
|
+
// SSH keys
|
|
40
|
+
{ pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\sKEY-----/, id: "private_key_block", severity: "high" },
|
|
41
|
+
// Environment variable names that indicate secrets
|
|
42
|
+
{ pattern: /\bANTHROPIC_API_KEY\b/, id: "env_anthropic_key", severity: "medium" },
|
|
43
|
+
{ pattern: /\bOPENAI_API_KEY\b/, id: "env_openai_key", severity: "medium" },
|
|
44
|
+
{ pattern: /\bOPENROUTER_API_KEY\b/, id: "env_openrouter_key", severity: "medium" },
|
|
45
|
+
{ pattern: /\bGITHUB_TOKEN\b/, id: "env_github_token", severity: "medium" },
|
|
46
|
+
{ pattern: /\bAWS_SECRET_ACCESS_KEY\b/, id: "env_aws_secret", severity: "medium" },
|
|
47
|
+
{ pattern: /\bDATABASE_URL\b/, id: "env_database_url", severity: "medium" },
|
|
48
|
+
// Inline secret assignments (likely accidental paste)
|
|
49
|
+
{ pattern: /\bpassword\s*[=:]\s*\S{6,}\b/i, id: "password_assignment", severity: "medium" },
|
|
50
|
+
{ pattern: /\bsecret\s*[=:]\s*\S{6,}\b/i, id: "secret_assignment", severity: "medium" },
|
|
51
|
+
{ pattern: /\btoken\s*[=:]\s*\S{10,}\b/i, id: "token_assignment", severity: "medium" },
|
|
52
|
+
];
|
|
53
|
+
|
|
21
54
|
const INVISIBLE_CHARS = new Set([
|
|
22
55
|
'\u200b', '\u200c', '\u200d', '\u2060', '\ufeff',
|
|
23
56
|
'\u202a', '\u202b', '\u202c', '\u202d', '\u202e',
|
|
24
57
|
]);
|
|
25
58
|
|
|
26
59
|
/**
|
|
27
|
-
* Scan memory content for injection/exfiltration patterns.
|
|
60
|
+
* Scan memory content for injection/exfiltration patterns AND secret leaks.
|
|
28
61
|
* Returns an error string if blocked, or null if content is safe.
|
|
29
62
|
*/
|
|
30
63
|
export function scanContent(content: string): string | null {
|
|
@@ -42,5 +75,27 @@ export function scanContent(content: string): string | null {
|
|
|
42
75
|
}
|
|
43
76
|
}
|
|
44
77
|
|
|
78
|
+
// Check secret patterns
|
|
79
|
+
for (const { pattern, id, severity } of SECRET_PATTERNS) {
|
|
80
|
+
if (pattern.test(content)) {
|
|
81
|
+
return `Blocked: content looks like a ${severity}-severity credential or secret ('${id}'). Never persist API keys, tokens, or passwords to memory. Use an .env file or secrets manager instead.`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
45
85
|
return null;
|
|
46
86
|
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Scan content for secrets only (no threat patterns).
|
|
90
|
+
* Returns an array of matched secret IDs, or empty array if none found.
|
|
91
|
+
* Useful for non-blocking warnings (e.g., pre-fill checks in interviews).
|
|
92
|
+
*/
|
|
93
|
+
export function scanSecrets(content: string): string[] {
|
|
94
|
+
const found: string[] = [];
|
|
95
|
+
for (const { pattern, id } of SECRET_PATTERNS) {
|
|
96
|
+
if (pattern.test(content)) {
|
|
97
|
+
found.push(id);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return found;
|
|
101
|
+
}
|