moltblock 0.4.0 → 0.6.0
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 → README.md} +96 -1
- package/dist/agents.d.ts +4 -4
- package/dist/agents.js +30 -16
- package/dist/cli.js +6 -1
- package/dist/code-verifier.d.ts +13 -0
- package/dist/code-verifier.js +21 -0
- package/dist/composite-verifier.d.ts +21 -0
- package/dist/composite-verifier.js +42 -0
- package/dist/config.d.ts +57 -2
- package/dist/config.js +121 -46
- package/dist/domain-prompts.d.ts +21 -0
- package/dist/domain-prompts.js +33 -0
- package/dist/entity-base.d.ts +37 -0
- package/dist/entity-base.js +87 -0
- package/dist/graph-runner.d.ts +11 -1
- package/dist/graph-runner.js +15 -4
- package/dist/improvement.d.ts +1 -1
- package/dist/improvement.js +21 -9
- package/dist/index.d.ts +10 -3
- package/dist/index.js +16 -4
- package/dist/policy-verifier.d.ts +29 -0
- package/dist/policy-verifier.js +90 -0
- package/dist/risk.d.ts +13 -0
- package/dist/risk.js +63 -0
- package/dist/verifier-interface.d.ts +24 -0
- package/dist/verifier-interface.js +4 -0
- package/package.json +3 -2
- package/skill/SKILL.md +103 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PolicyVerifier: rule-based verifier that catches dangerous patterns without an LLM call.
|
|
3
|
+
*/
|
|
4
|
+
// --- Built-in deny rules ---
|
|
5
|
+
const BUILTIN_RULES = [
|
|
6
|
+
// Destructive commands
|
|
7
|
+
{ id: "cmd-rm-rf", description: "Recursive force delete", target: "artifact", pattern: "\\brm\\s+-rf\\b", action: "deny", category: "destructive-cmd", enabled: true },
|
|
8
|
+
{ id: "cmd-rm-r", description: "Recursive delete", target: "artifact", pattern: "\\brm\\s+-r\\s+/", action: "deny", category: "destructive-cmd", enabled: true },
|
|
9
|
+
{ id: "cmd-drop-table", description: "SQL DROP TABLE", target: "artifact", pattern: "\\bDROP\\s+(TABLE|DATABASE)\\b", action: "deny", category: "destructive-sql", enabled: true },
|
|
10
|
+
{ id: "cmd-truncate", description: "SQL TRUNCATE", target: "artifact", pattern: "\\bTRUNCATE\\s+TABLE\\b", action: "deny", category: "destructive-sql", enabled: true },
|
|
11
|
+
{ id: "cmd-dd", description: "Raw disk write (dd)", target: "artifact", pattern: "\\bdd\\s+if=", action: "deny", category: "destructive-cmd", enabled: true },
|
|
12
|
+
{ id: "cmd-chmod-777", description: "World-writable permissions", target: "artifact", pattern: "\\bchmod\\s+777\\b", action: "deny", category: "destructive-cmd", enabled: true },
|
|
13
|
+
{ id: "cmd-mkfs", description: "Filesystem creation", target: "artifact", pattern: "\\bmkfs\\b", action: "deny", category: "destructive-cmd", enabled: true },
|
|
14
|
+
// Sensitive file paths
|
|
15
|
+
{ id: "path-ssh", description: "SSH directory access", target: "both", pattern: "~?\\/?\\.ssh\\/", action: "deny", category: "sensitive-path", enabled: true },
|
|
16
|
+
{ id: "path-etc-passwd", description: "/etc/passwd access", target: "both", pattern: "\\/etc\\/passwd\\b", action: "deny", category: "sensitive-path", enabled: true },
|
|
17
|
+
{ id: "path-etc-shadow", description: "/etc/shadow access", target: "both", pattern: "\\/etc\\/shadow\\b", action: "deny", category: "sensitive-path", enabled: true },
|
|
18
|
+
{ id: "path-dotenv", description: ".env file access", target: "artifact", pattern: "\\.(env|env\\.local|env\\.production)\\b", action: "deny", category: "sensitive-path", enabled: true },
|
|
19
|
+
{ id: "path-id-rsa", description: "Private key file", target: "both", pattern: "\\bid_rsa\\b|\\bid_ed25519\\b", action: "deny", category: "sensitive-path", enabled: true },
|
|
20
|
+
{ id: "path-credentials", description: "Credentials file", target: "both", pattern: "\\bcredentials\\.(json|yaml|yml|xml)\\b", action: "deny", category: "sensitive-path", enabled: true },
|
|
21
|
+
// Hardcoded secrets
|
|
22
|
+
{ id: "secret-api-key", description: "Hardcoded API key pattern", target: "artifact", pattern: "(api[_-]?key|apikey)\\s*[=:]\\s*[\"'][A-Za-z0-9_\\-]{20,}", action: "deny", category: "hardcoded-secret", enabled: true },
|
|
23
|
+
{ id: "secret-password", description: "Hardcoded password", target: "artifact", pattern: "(password|passwd|pwd)\\s*[=:]\\s*[\"'][^\"']{4,}", action: "deny", category: "hardcoded-secret", enabled: true },
|
|
24
|
+
{ id: "secret-private-key", description: "Private key material", target: "artifact", pattern: "-----BEGIN\\s+(RSA|EC|DSA|OPENSSH)?\\s*PRIVATE\\s+KEY-----", action: "deny", category: "hardcoded-secret", enabled: true },
|
|
25
|
+
{ id: "secret-token", description: "Hardcoded token/secret", target: "artifact", pattern: "(secret|token)\\s*[=:]\\s*[\"'][A-Za-z0-9_\\-]{20,}", action: "deny", category: "hardcoded-secret", enabled: true },
|
|
26
|
+
// Data exfiltration
|
|
27
|
+
{ id: "exfil-curl-post", description: "curl POST request", target: "artifact", pattern: "\\bcurl\\s+.*-X\\s*POST\\b", action: "deny", category: "exfiltration", enabled: true },
|
|
28
|
+
{ id: "exfil-wget", description: "wget to HTTP", target: "artifact", pattern: "\\bwget\\s+http", action: "deny", category: "exfiltration", enabled: true },
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Rule-based policy verifier. Checks artifacts and tasks against deny/allow rules.
|
|
32
|
+
* Allow rules in the same category override deny rules.
|
|
33
|
+
*/
|
|
34
|
+
export class PolicyVerifier {
|
|
35
|
+
name = "PolicyVerifier";
|
|
36
|
+
rules;
|
|
37
|
+
constructor(customRules) {
|
|
38
|
+
this.rules = [...BUILTIN_RULES];
|
|
39
|
+
if (customRules) {
|
|
40
|
+
this.rules.push(...customRules);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async verify(memory, context) {
|
|
44
|
+
const artifact = memory.finalCandidate || "";
|
|
45
|
+
const task = context?.task ?? memory.task ?? "";
|
|
46
|
+
const violations = [];
|
|
47
|
+
const allowedCategories = new Set();
|
|
48
|
+
// First pass: collect allowed categories
|
|
49
|
+
for (const rule of this.rules) {
|
|
50
|
+
if (!rule.enabled || rule.action !== "allow")
|
|
51
|
+
continue;
|
|
52
|
+
const text = this.getTargetText(rule.target, artifact, task);
|
|
53
|
+
const regex = new RegExp(rule.pattern, "i");
|
|
54
|
+
if (regex.test(text)) {
|
|
55
|
+
allowedCategories.add(rule.category);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Second pass: check deny rules (skip allowed categories)
|
|
59
|
+
for (const rule of this.rules) {
|
|
60
|
+
if (!rule.enabled || rule.action !== "deny")
|
|
61
|
+
continue;
|
|
62
|
+
if (allowedCategories.has(rule.category))
|
|
63
|
+
continue;
|
|
64
|
+
const text = this.getTargetText(rule.target, artifact, task);
|
|
65
|
+
const regex = new RegExp(rule.pattern, "i");
|
|
66
|
+
if (regex.test(text)) {
|
|
67
|
+
violations.push(`[${rule.id}] ${rule.description}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (violations.length > 0) {
|
|
71
|
+
return {
|
|
72
|
+
passed: false,
|
|
73
|
+
evidence: `Policy violations:\n${violations.join("\n")}`,
|
|
74
|
+
verifierName: this.name,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
passed: true,
|
|
79
|
+
evidence: "All policy rules passed.",
|
|
80
|
+
verifierName: this.name,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
getTargetText(target, artifact, task) {
|
|
84
|
+
if (target === "artifact")
|
|
85
|
+
return artifact;
|
|
86
|
+
if (target === "task")
|
|
87
|
+
return task;
|
|
88
|
+
return `${task}\n${artifact}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
package/dist/risk.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk classification: keyword-based risk levels for tasks.
|
|
3
|
+
*/
|
|
4
|
+
export type RiskLevel = "low" | "medium" | "high";
|
|
5
|
+
export interface RiskClassification {
|
|
6
|
+
level: RiskLevel;
|
|
7
|
+
reasons: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Classify a task's risk level based on keyword/pattern matching.
|
|
11
|
+
* Returns the highest risk level found and all matching reasons.
|
|
12
|
+
*/
|
|
13
|
+
export declare function classifyRisk(task: string): RiskClassification;
|
package/dist/risk.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk classification: keyword-based risk levels for tasks.
|
|
3
|
+
*/
|
|
4
|
+
const RISK_PATTERNS = [
|
|
5
|
+
// High: destructive operations
|
|
6
|
+
{ pattern: /\brm\s+-rf\b/i, level: "high", reason: "Recursive file deletion (rm -rf)" },
|
|
7
|
+
{ pattern: /\brm\s+-r\b/i, level: "high", reason: "Recursive file deletion (rm -r)" },
|
|
8
|
+
{ pattern: /\brmdir\b/i, level: "high", reason: "Directory removal" },
|
|
9
|
+
{ pattern: /\bdrop\s+(table|database)\b/i, level: "high", reason: "SQL DROP statement" },
|
|
10
|
+
{ pattern: /\btruncate\s+table\b/i, level: "high", reason: "SQL TRUNCATE statement" },
|
|
11
|
+
{ pattern: /\bformat\s+[a-z]:/i, level: "high", reason: "Disk format command" },
|
|
12
|
+
{ pattern: /\bmkfs\b/i, level: "high", reason: "Filesystem creation (mkfs)" },
|
|
13
|
+
{ pattern: /\bdd\s+if=/i, level: "high", reason: "Raw disk write (dd)" },
|
|
14
|
+
// High: privilege escalation
|
|
15
|
+
{ pattern: /\bsudo\b/i, level: "high", reason: "Sudo privilege escalation" },
|
|
16
|
+
{ pattern: /\bchmod\s+777\b/i, level: "high", reason: "World-writable permissions (chmod 777)" },
|
|
17
|
+
{ pattern: /\bchmod\s+\+s\b/i, level: "high", reason: "Set-UID/GID bit (chmod +s)" },
|
|
18
|
+
// High: credential/key access
|
|
19
|
+
{ pattern: /\b(private[_\s]?key|id_rsa|id_ed25519)\b/i, level: "high", reason: "Private key access" },
|
|
20
|
+
{ pattern: /\/etc\/shadow\b/i, level: "high", reason: "Shadow password file access" },
|
|
21
|
+
{ pattern: /~?\/?\.ssh\//i, level: "high", reason: "SSH directory access" },
|
|
22
|
+
{ pattern: /\bcredentials?\.(json|yaml|yml|xml|conf)\b/i, level: "high", reason: "Credentials file access" },
|
|
23
|
+
// High: system modification
|
|
24
|
+
{ pattern: /\/etc\/passwd\b/i, level: "high", reason: "System password file access" },
|
|
25
|
+
{ pattern: /\bsystemctl\s+(stop|disable|mask)\b/i, level: "high", reason: "System service modification" },
|
|
26
|
+
{ pattern: /\bkill\s+-9\b/i, level: "high", reason: "Force kill process" },
|
|
27
|
+
// Medium: network operations
|
|
28
|
+
{ pattern: /\bcurl\b/i, level: "medium", reason: "Network request (curl)" },
|
|
29
|
+
{ pattern: /\bwget\b/i, level: "medium", reason: "Network download (wget)" },
|
|
30
|
+
{ pattern: /\bfetch\s*\(/i, level: "medium", reason: "Network fetch call" },
|
|
31
|
+
{ pattern: /\bhttp(s)?:\/\//i, level: "medium", reason: "HTTP URL reference" },
|
|
32
|
+
// Medium: file writes
|
|
33
|
+
{ pattern: /\bwrite\s*file\b/i, level: "medium", reason: "File write operation" },
|
|
34
|
+
{ pattern: /\bfs\.write/i, level: "medium", reason: "Filesystem write (fs.write)" },
|
|
35
|
+
{ pattern: /\bfs\.unlink/i, level: "medium", reason: "File deletion (fs.unlink)" },
|
|
36
|
+
// Medium: database modifications
|
|
37
|
+
{ pattern: /\b(insert|update|delete|alter)\s+(into|from|table)\b/i, level: "medium", reason: "Database modification" },
|
|
38
|
+
// Medium: subprocess spawning
|
|
39
|
+
{ pattern: /\bexec\s*\(/i, level: "medium", reason: "Subprocess execution (exec)" },
|
|
40
|
+
{ pattern: /\bspawn\s*\(/i, level: "medium", reason: "Subprocess spawning" },
|
|
41
|
+
{ pattern: /\bchild_process\b/i, level: "medium", reason: "Child process module" },
|
|
42
|
+
{ pattern: /\beval\s*\(/i, level: "medium", reason: "Dynamic code evaluation (eval)" },
|
|
43
|
+
];
|
|
44
|
+
/**
|
|
45
|
+
* Classify a task's risk level based on keyword/pattern matching.
|
|
46
|
+
* Returns the highest risk level found and all matching reasons.
|
|
47
|
+
*/
|
|
48
|
+
export function classifyRisk(task) {
|
|
49
|
+
const reasons = [];
|
|
50
|
+
let level = "low";
|
|
51
|
+
for (const { pattern, level: patternLevel, reason } of RISK_PATTERNS) {
|
|
52
|
+
if (pattern.test(task)) {
|
|
53
|
+
reasons.push(reason);
|
|
54
|
+
if (patternLevel === "high") {
|
|
55
|
+
level = "high";
|
|
56
|
+
}
|
|
57
|
+
else if (patternLevel === "medium" && level !== "high") {
|
|
58
|
+
level = "medium";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { level, reasons };
|
|
63
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable verifier interface: any verification strategy implements this contract.
|
|
3
|
+
*/
|
|
4
|
+
import type { WorkingMemory } from "./memory.js";
|
|
5
|
+
/** Result of a single verification run. */
|
|
6
|
+
export interface VerificationResult {
|
|
7
|
+
passed: boolean;
|
|
8
|
+
evidence: string;
|
|
9
|
+
verifierName: string;
|
|
10
|
+
/** Per-verifier details when running a composite verifier. */
|
|
11
|
+
details?: VerificationResult[];
|
|
12
|
+
}
|
|
13
|
+
/** Context passed to verifiers alongside working memory. */
|
|
14
|
+
export interface VerifierContext {
|
|
15
|
+
task?: string;
|
|
16
|
+
testCode?: string;
|
|
17
|
+
domain?: string;
|
|
18
|
+
meta?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/** A verifier that can gate artifacts before they gain authority. */
|
|
21
|
+
export interface Verifier {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
verify(memory: WorkingMemory, context?: VerifierContext): Promise<VerificationResult>;
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moltblock",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Framework for building evolving composite AI intelligences (Entities)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"dist",
|
|
44
|
-
"config"
|
|
44
|
+
"config",
|
|
45
|
+
"skill"
|
|
45
46
|
],
|
|
46
47
|
"dependencies": {
|
|
47
48
|
"better-sqlite3": "^12.6.2",
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# moltblock — Trust Layer for AI Agents
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Moltblock provides verification gating for AI-generated artifacts. Before any high-risk action (file deletion, credential access, system modification, network exfiltration), the `moltblock_verify` tool runs policy checks and optional code verification to catch dangerous patterns.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
Use `moltblock_verify` when the task involves:
|
|
10
|
+
|
|
11
|
+
- **High risk** (always verify): Destructive operations (`rm -rf`, `DROP TABLE`), privilege escalation (`sudo`, `chmod 777`), credential/key access (`.ssh/`, `id_rsa`, `.env`), system modification, raw disk writes
|
|
12
|
+
- **Medium risk** (verify when uncertain): Network requests (`curl`, `wget`, `fetch`), file writes, database modifications, subprocess spawning, dynamic code evaluation
|
|
13
|
+
- **Low risk** (skip verification): Simple text responses, math, reading public information, code that doesn't touch the filesystem or network
|
|
14
|
+
|
|
15
|
+
## Tool: moltblock_verify
|
|
16
|
+
|
|
17
|
+
Verify a task before execution.
|
|
18
|
+
|
|
19
|
+
### Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx moltblock "<task description>" --provider <provider> --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Parameters
|
|
26
|
+
|
|
27
|
+
| Parameter | Required | Description |
|
|
28
|
+
|-----------|----------|-------------|
|
|
29
|
+
| task | Yes | The task description to verify |
|
|
30
|
+
| --provider | No | LLM provider: openai, google, zai, local (auto-detected from env) |
|
|
31
|
+
| --model | No | Model override |
|
|
32
|
+
| --test | No | Path to test file (for code verification) |
|
|
33
|
+
| --json | No | Output structured JSON result |
|
|
34
|
+
|
|
35
|
+
### Environment Variables
|
|
36
|
+
|
|
37
|
+
Set one of these for provider auto-detection:
|
|
38
|
+
- `OPENAI_API_KEY` — OpenAI
|
|
39
|
+
- `GOOGLE_API_KEY` — Google/Gemini
|
|
40
|
+
- `MOLTBLOCK_ZAI_API_KEY` — ZAI
|
|
41
|
+
|
|
42
|
+
### Example
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Verify a potentially dangerous task
|
|
46
|
+
npx moltblock "delete all temporary files older than 30 days" --json
|
|
47
|
+
|
|
48
|
+
# Verify code with tests
|
|
49
|
+
npx moltblock "implement user authentication" --test ./tests/auth.test.ts --json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Output (JSON mode)
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"task": "...",
|
|
57
|
+
"verificationPassed": true,
|
|
58
|
+
"verificationEvidence": "All policy rules passed.",
|
|
59
|
+
"riskLevel": "high",
|
|
60
|
+
"riskReasons": ["Recursive file deletion (rm -rf)"]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install -g moltblock
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or use directly with npx (no install needed):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npx moltblock "your task" --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
Optional. Place `moltblock.json` in your project root or `~/.moltblock/moltblock.json`:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"agent": {
|
|
83
|
+
"bindings": {
|
|
84
|
+
"generator": { "backend": "google", "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/", "model": "gemini-2.0-flash" },
|
|
85
|
+
"critic": { "backend": "google", "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/", "model": "gemini-2.0-flash" },
|
|
86
|
+
"judge": { "backend": "google", "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/", "model": "gemini-2.0-flash" }
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"policy": {
|
|
90
|
+
"rules": [
|
|
91
|
+
{
|
|
92
|
+
"id": "custom-allow-tmp",
|
|
93
|
+
"description": "Allow operations in /tmp",
|
|
94
|
+
"target": "artifact",
|
|
95
|
+
"pattern": "\\/tmp\\/",
|
|
96
|
+
"action": "allow",
|
|
97
|
+
"category": "destructive-cmd",
|
|
98
|
+
"enabled": true
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|