@agent-beam/beam 0.1.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.
Files changed (66) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +188 -0
  3. package/dist/agents.d.ts +26 -0
  4. package/dist/agents.js +96 -0
  5. package/dist/agents.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +234 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/client.d.ts +28 -0
  10. package/dist/client.js +176 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/config.d.ts +5 -0
  13. package/dist/config.js +23 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/core.d.ts +64 -0
  16. package/dist/core.js +176 -0
  17. package/dist/core.js.map +1 -0
  18. package/dist/custom-rules.d.ts +7 -0
  19. package/dist/custom-rules.js +80 -0
  20. package/dist/custom-rules.js.map +1 -0
  21. package/dist/enroll.d.ts +16 -0
  22. package/dist/enroll.js +68 -0
  23. package/dist/enroll.js.map +1 -0
  24. package/dist/extract.d.ts +6 -0
  25. package/dist/extract.js +148 -0
  26. package/dist/extract.js.map +1 -0
  27. package/dist/forward.d.ts +8 -0
  28. package/dist/forward.js +53 -0
  29. package/dist/forward.js.map +1 -0
  30. package/dist/hook-adapters.d.ts +2 -0
  31. package/dist/hook-adapters.js +36 -0
  32. package/dist/hook-adapters.js.map +1 -0
  33. package/dist/install.d.ts +15 -0
  34. package/dist/install.js +68 -0
  35. package/dist/install.js.map +1 -0
  36. package/dist/inventory.d.ts +12 -0
  37. package/dist/inventory.js +23 -0
  38. package/dist/inventory.js.map +1 -0
  39. package/dist/open-browser.d.ts +1 -0
  40. package/dist/open-browser.js +8 -0
  41. package/dist/open-browser.js.map +1 -0
  42. package/dist/os-monitor.d.ts +5 -0
  43. package/dist/os-monitor.js +26 -0
  44. package/dist/os-monitor.js.map +1 -0
  45. package/dist/policy.d.ts +27 -0
  46. package/dist/policy.js +59 -0
  47. package/dist/policy.js.map +1 -0
  48. package/dist/sequences.d.ts +13 -0
  49. package/dist/sequences.js +58 -0
  50. package/dist/sequences.js.map +1 -0
  51. package/dist/serve.d.ts +27 -0
  52. package/dist/serve.js +113 -0
  53. package/dist/serve.js.map +1 -0
  54. package/dist/server.d.ts +10 -0
  55. package/dist/server.js +101 -0
  56. package/dist/server.js.map +1 -0
  57. package/dist/service.d.ts +27 -0
  58. package/dist/service.js +169 -0
  59. package/dist/service.js.map +1 -0
  60. package/dist/store.d.ts +19 -0
  61. package/dist/store.js +114 -0
  62. package/dist/store.js.map +1 -0
  63. package/dist/studio.d.ts +1 -0
  64. package/dist/studio.js +337 -0
  65. package/dist/studio.js.map +1 -0
  66. package/package.json +43 -0
package/dist/client.js ADDED
@@ -0,0 +1,176 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { getBeamHome, getCollectorUrl, getDataDirectory } from "./config.js";
5
+ import { normalize, scanText } from "./core.js";
6
+ import { adaptHookPayload } from "./hook-adapters.js";
7
+ import { forwardEvents } from "./forward.js";
8
+ import { evaluate, readPolicy } from "./policy.js";
9
+ import { extractAgent } from "./extract.js";
10
+ import { loadCustomRules } from "./custom-rules.js";
11
+ export async function readToken() {
12
+ if (process.env.BEAM_TOKEN)
13
+ return process.env.BEAM_TOKEN;
14
+ const tokenPath = join(getDataDirectory(), "token");
15
+ try {
16
+ return (await readFile(tokenPath, "utf8")).trim();
17
+ }
18
+ catch {
19
+ throw new Error(`No token file at ${tokenPath}. Run 'beam start' first.`);
20
+ }
21
+ }
22
+ async function send(route, body) {
23
+ const url = getCollectorUrl();
24
+ const response = await fetch(`${url.origin}${route}`, {
25
+ method: "POST",
26
+ headers: { Authorization: `Bearer ${await readToken()}`, "Content-Type": "application/json" },
27
+ body,
28
+ signal: AbortSignal.timeout(5000)
29
+ });
30
+ if (!response.ok)
31
+ throw new Error(`Collector rejected request: ${await response.text()}`);
32
+ return response.json();
33
+ }
34
+ async function boundedFile(filePath) {
35
+ const stats = await stat(filePath);
36
+ if (stats.size > 2_000_000)
37
+ throw new Error("File exceeds 2 MB. Split it into batches.");
38
+ return readFile(filePath, "utf8");
39
+ }
40
+ export async function importEvents(filePath) {
41
+ return send("/ingest", await boundedFile(filePath));
42
+ }
43
+ export async function reloadRemoteRules() {
44
+ return send("/rules/reload", "{}");
45
+ }
46
+ export async function scanFile(filePath, options = {}, beamHome = getBeamHome()) {
47
+ const content = await boundedFile(filePath);
48
+ const kind = options.mcp ? "mcp" : "skill";
49
+ if (options.save)
50
+ return send("/scan", JSON.stringify({ name: filePath, content, kind }));
51
+ // Offline scanning should flag the same things the live collector would -- load any custom
52
+ // rules from disk first, same as the server does at startup. Note: beamHome is ~/.beam, not
53
+ // the OS home directory -- distinct from extractPreview/extractSave's `home` below.
54
+ await loadCustomRules(beamHome);
55
+ return scanText(filePath, content, kind);
56
+ }
57
+ const INGEST_BATCH_SIZE = 2000; // matches the collector's own per-request record cap
58
+ // Without --save: extract and normalize locally (so redaction still applies) without touching
59
+ // the collector at all -- a read-only preview of what would be imported. `home` is the OS home
60
+ // directory (where ~/.claude, ~/.codex etc. live); `beamHome` is the separate ~/.beam config
61
+ // root that rules.json lives under -- passing one where the other belongs silently loads zero
62
+ // custom rules instead of erroring, so keep them distinct rather than reusing one parameter.
63
+ export async function extractPreview(agentId, limit = 200, home = homedir(), beamHome = getBeamHome()) {
64
+ await loadCustomRules(beamHome);
65
+ const records = await extractAgent(agentId, home);
66
+ const events = [];
67
+ for (const record of records) {
68
+ try {
69
+ events.push(normalize(record));
70
+ }
71
+ catch { /* skip a record normalize() can't accept */ }
72
+ }
73
+ return { found: events.length, previewed: Math.min(events.length, limit), events: events.slice(0, limit) };
74
+ }
75
+ // With --save: send the raw (pre-normalize) records to /ingest so the server's own pipeline --
76
+ // dedupe by event_id, redact, bounded persistence -- handles them exactly like a live hook would.
77
+ export async function extractSave(agentId, home = homedir()) {
78
+ const records = await extractAgent(agentId, home);
79
+ const totals = { accepted: 0, duplicates: 0, skipped: 0 };
80
+ for (let i = 0; i < records.length; i += INGEST_BATCH_SIZE) {
81
+ const batch = records.slice(i, i + INGEST_BATCH_SIZE);
82
+ const result = await send("/ingest", JSON.stringify(batch));
83
+ totals.accepted += result.accepted;
84
+ totals.duplicates += result.duplicates;
85
+ totals.skipped += result.skipped;
86
+ }
87
+ return { found: records.length, ...totals };
88
+ }
89
+ async function readStdin(limitBytes) {
90
+ let input = "";
91
+ for await (const chunk of process.stdin) {
92
+ input += typeof chunk === "string" ? chunk : chunk.toString("utf8");
93
+ if (input.length > limitBytes)
94
+ throw new Error(`Hook exceeds ${Math.floor(limitBytes / 1000)} KB.`);
95
+ }
96
+ return input;
97
+ }
98
+ // Never throws: a Claude Code hook must not block or fail the agent if capture fails.
99
+ export async function captureHook(sourceAgent = "claude-code") {
100
+ try {
101
+ const input = await readStdin(100_000);
102
+ const raw = JSON.parse(input);
103
+ const data = adaptHookPayload(sourceAgent, raw);
104
+ data.source_agent = sourceAgent;
105
+ data.source_type = "hook";
106
+ if (data.hook_event_name === "UserPromptSubmit" && typeof data.prompt === "string") {
107
+ data.event_type = data.event_type ?? "prompt.submit";
108
+ data.tool_name = data.tool_name ?? "UserPromptSubmit";
109
+ data.command = data.command ?? data.prompt;
110
+ }
111
+ // 1. Enforcement first — a local file read, so it works even if the collector is down.
112
+ // Only acts when a manager has set the policy to advisory/enforce; observe mode
113
+ // (the default) is a no-op and Beam stays observation-only.
114
+ const toolInput = data.tool_input && typeof data.tool_input === "object"
115
+ ? data.tool_input : {};
116
+ const decision = evaluate(await readPolicy().catch(() => null), {
117
+ agent: sourceAgent,
118
+ tool: String(data.tool_name ?? ""),
119
+ command: String(data.command ?? toolInput.command ?? ""),
120
+ });
121
+ let event = safeNormalize(data);
122
+ if (decision.action === "deny") {
123
+ if (event)
124
+ event = { ...event, findings: [...event.findings, blockedFinding(decision.reason)] };
125
+ emitDeny(sourceAgent, decision.reason ?? "Blocked by workspace policy.");
126
+ }
127
+ else if (decision.action === "warn") {
128
+ process.stderr.write(`\n⚠ Beam policy (advisory): ${decision.reason}\n`);
129
+ }
130
+ // 2. Local capture (best-effort — a failure here must not skip enforcement or throw).
131
+ try {
132
+ await send("/ingest", JSON.stringify(data));
133
+ }
134
+ catch (e) {
135
+ console.error(e instanceof Error ? e.message : String(e));
136
+ }
137
+ // 3. Forward to the workspace if enrolled (fire-and-forget, never blocks).
138
+ if (event) {
139
+ try {
140
+ await forwardEvents(event);
141
+ }
142
+ catch { /* offline */ }
143
+ }
144
+ }
145
+ catch (error) {
146
+ console.error(error instanceof Error ? error.message : String(error));
147
+ }
148
+ }
149
+ function safeNormalize(data) {
150
+ try {
151
+ return normalize(data);
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ }
157
+ function blockedFinding(reason = "Blocked by workspace policy.") {
158
+ return { id: "policy.blocked", title: "Blocked by workspace policy", severity: "high", explanation: reason, evidence: "" };
159
+ }
160
+ // Claude Code / Codex PreToolUse contract: a JSON decision on stdout denies the tool call.
161
+ // Other agents get a stderr note only (their block contracts differ and aren't verified).
162
+ function emitDeny(agent, reason) {
163
+ if (agent === "claude-code" || agent === "codex") {
164
+ process.stdout.write(JSON.stringify({
165
+ hookSpecificOutput: {
166
+ hookEventName: "PreToolUse",
167
+ permissionDecision: "deny",
168
+ permissionDecisionReason: `Beam: ${reason}`,
169
+ },
170
+ }));
171
+ }
172
+ else {
173
+ process.stderr.write(`\n✖ Beam policy would block this (${agent} enforcement not wired): ${reason}\n`);
174
+ }
175
+ }
176
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function getBeamHome(): string;
2
+ export declare function getDataDirectory(): string;
3
+ export declare function getCollectorUrl(): URL;
4
+ export declare function getApiUrl(): string;
5
+ export declare function getIdentityPath(): string;
package/dist/config.js ADDED
@@ -0,0 +1,23 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ export function getBeamHome() {
4
+ return process.env.BEAM_HOME ? path.resolve(process.env.BEAM_HOME) : path.join(os.homedir(), ".beam");
5
+ }
6
+ export function getDataDirectory() {
7
+ return process.env.BEAM_DATA_DIR ? path.resolve(process.env.BEAM_DATA_DIR) : path.join(getBeamHome(), "data");
8
+ }
9
+ export function getCollectorUrl() {
10
+ const url = new URL(process.env.BEAM_COLLECTOR_URL || "http://127.0.0.1:4319");
11
+ if (url.protocol !== "http:" || !["localhost", "127.0.0.1"].includes(url.hostname))
12
+ throw new Error("Collector must be on HTTP loopback.");
13
+ return url;
14
+ }
15
+ // The Beam workspace API (dashboard / control plane) this device enrolls with and
16
+ // reports to. Not loopback-restricted — this is the remote SaaS endpoint.
17
+ export function getApiUrl() {
18
+ return (process.env.BEAM_API_URL || "http://127.0.0.1:3200").replace(/\/+$/, "");
19
+ }
20
+ export function getIdentityPath() {
21
+ return path.join(getDataDirectory(), "identity.json");
22
+ }
23
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACxG,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC;AAChH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,uBAAuB,CAAC,CAAC;IAC/E,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC3I,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,0EAA0E;AAC1E,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,eAAe,CAAC,CAAC;AACxD,CAAC"}
package/dist/core.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ export type Severity = "critical" | "high" | "medium" | "info";
2
+ export type Finding = {
3
+ id: string;
4
+ title: string;
5
+ severity: Severity;
6
+ explanation: string;
7
+ evidence: string;
8
+ line?: number;
9
+ };
10
+ export type Event = {
11
+ id: string;
12
+ timestamp: string;
13
+ receivedAt: string;
14
+ agent: string;
15
+ session: string;
16
+ type: string;
17
+ tool: string;
18
+ summary: string;
19
+ project: string;
20
+ source: string;
21
+ endpoint: string;
22
+ model: string;
23
+ phase: string;
24
+ findings: Finding[];
25
+ provenance?: {
26
+ recordId: string;
27
+ schemaVersion: string;
28
+ citedEventIds: string[];
29
+ tags: string[];
30
+ evidence: string;
31
+ };
32
+ inputTokens?: number;
33
+ outputTokens?: number;
34
+ costUsd?: number;
35
+ };
36
+ export type Scan = {
37
+ id: string;
38
+ name: string;
39
+ kind: "skill" | "mcp";
40
+ timestamp: string;
41
+ hash: string;
42
+ findings: Finding[];
43
+ lines: number;
44
+ };
45
+ export declare const severityRank: Record<Severity, number>;
46
+ export declare function risk(findings: Finding[]): Severity;
47
+ export declare function redact(text: string): string;
48
+ export type RuleCategory = "exec" | "exfil" | "impact" | "integrity" | "persistence" | "privilege" | "recon" | "secrets" | "source_control" | "custom";
49
+ export type Rule = {
50
+ id: string;
51
+ title: string;
52
+ severity: Severity;
53
+ category: RuleCategory;
54
+ explanation: string;
55
+ match: (s: string) => boolean;
56
+ };
57
+ export declare function setCustomRules(rules: Rule[]): void;
58
+ export declare function ruleCatalog(): Omit<Rule, "match">[];
59
+ export declare function detect(text: string): Finding[];
60
+ export declare function scanText(name: string, content: string, kind: "skill" | "mcp"): Scan;
61
+ type Obj = Record<string, unknown>;
62
+ export declare function parseInput(input: string, otlp?: boolean): Obj[];
63
+ export declare function normalize(raw: Obj): Event;
64
+ export {};
package/dist/core.js ADDED
@@ -0,0 +1,176 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ export const severityRank = { critical: 3, high: 2, medium: 1, info: 0 };
3
+ export function risk(findings) {
4
+ return findings.reduce((s, f) => severityRank[f.severity] > severityRank[s] ? f.severity : s, "info");
5
+ }
6
+ export function redact(text) {
7
+ return text
8
+ .replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?(?:-----END [^-]*PRIVATE KEY-----|$)/g, "[REDACTED PRIVATE KEY]")
9
+ .replace(/\b(?:sk-(?:proj-|ant-)?[A-Za-z0-9_-]{12,}|gh[pousr]_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{16,}|AKIA[A-Z0-9]{16}|xox[baprs]-[\w-]{10,})\b/g, "[REDACTED TOKEN]")
10
+ .replace(/(bearer\s+)[A-Za-z0-9._~+\/-]{8,}/gi, "$1[REDACTED]")
11
+ .replace(/((?:[\w-]*(?:api[_-]?key|token|secret|password|authorization)[\w-]*)["']?\s*[:=]\s*)["']?[^\s,"';&}\]]+/gi, "$1[REDACTED]")
12
+ .replace(/(https?:\/\/)[^\s/@]+:[^\s/@]+@/gi, "$1[REDACTED]@")
13
+ .replace(/(https?:\/\/[^\s?#"']+)\?[^\s"']*/gi, "$1?[REDACTED QUERY]");
14
+ }
15
+ const secret = /(?:\.env(?:\b|[./])|\.ssh[\\/]|id_rsa|id_ed25519|\.aws[\\/]credentials|(?:api[_-]?key|access[_-]?token|password|secret)\b)/i;
16
+ const egress = /(?:https?:\/\/|\bcurl\b|\bwget\b|\bupload\b|\bwebhook\b|\bsend\b|\bexfiltrat\w*)/i;
17
+ const builtinRules = [
18
+ { id: "destructive.delete", title: "Destructive operation", severity: "high", category: "impact", explanation: "Review the target and backups before allowing a recursive delete or destructive data operation.", match: s => /\brm\s+[^\n]*(?:-[a-z]*r[a-z]*f|-[a-z]*f[a-z]*r|--recursive)|\b(?:drop\s+(?:table|database)|truncate\s+(?:table\s+)?\w+)|\bRemove-Item\b[^\n]*(?:-Recurse|-Force)|\bgit\s+(?:reset\s+--hard|clean\s+-[^\n]*f)/i.test(s) },
19
+ { id: "credentials.access", title: "Sensitive credential reference", severity: "medium", category: "secrets", explanation: "This action or instruction references a credential location. Confirm the agent needs access.", match: s => secret.test(s) },
20
+ { id: "credentials.egress", title: "Possible credential exposure", severity: "critical", category: "exfil", explanation: "Credential references and outbound delivery appear together. Inspect the destination and data before running this.", match: s => secret.test(s) && egress.test(s) },
21
+ { id: "execution.remote", title: "Remote code execution pattern", severity: "high", category: "exec", explanation: "Downloaded content is piped directly into a shell without review.", match: s => /\b(?:curl|wget)\b[^\n]*\|\s*(?:sudo\s+)?(?:ba|z|fi)?sh\b/i.test(s) },
22
+ { id: "execution.obfuscated", title: "Encoded execution", severity: "high", category: "exec", explanation: "Encoded content is decoded for execution. Review the decoded payload separately; Beam never executes it.", match: s => /\bbase64\b[^\n]*(?:-d|--decode)[^\n]*\|\s*(?:ba)?sh|\b(?:powershell|pwsh)\b[^\n]*-(?:enc|encodedcommand)\b/i.test(s) },
23
+ { id: "recon.network_sweep", title: "Network sweep", severity: "medium", category: "recon", explanation: "A scanner targets a network range. Verify scope and authorization before the agent probes other systems (ATT&CK T1046).", match: s => /\b(?:nmap|masscan|rustscan)\b/i.test(s) && /(?:\d{1,3}\.){3}\d{1,3}\/\d{1,2}|(?:\d{1,3}\.){3}\d{1,3}-\d{1,3}/.test(s) },
24
+ { id: "privilege.elevation", title: "Elevated privileges", severity: "medium", category: "privilege", explanation: "The action requests elevated privileges or broad write permissions.", match: s => /\bsudo\s|\bchmod\s+(?:-R\s+)?777\b/i.test(s) },
25
+ { id: "network.metadata", title: "Cloud metadata access", severity: "high", category: "secrets", explanation: "Cloud metadata endpoints can expose temporary instance credentials.", match: s => /169\.254\.169\.254|metadata\.google\.internal/i.test(s) },
26
+ { id: "persistence.config", title: "Security-sensitive configuration", severity: "high", category: "persistence", explanation: "A persistence or agent configuration target is referenced. Check the intended change and trust boundary.", match: s => /authorized_keys|\bcrontab\b|LaunchAgents[\\/]|ANTHROPIC_BASE_URL/i.test(s) },
27
+ { id: "network.reverse-shell", title: "Reverse shell pattern", severity: "critical", category: "exec", explanation: "This pattern can connect a command shell to another machine.", match: s => /\/dev\/tcp\/|\bnc\b[^\n]*\s-e\s|socket[\s\S]{0,200}subprocess/i.test(s) },
28
+ { id: "instructions.override", title: "Instruction override attempt", severity: "high", category: "integrity", explanation: "Instructions attempt to override existing safeguards or conceal activity from the user.", match: s => /ignore\s+(?:all\s+)?(?:previous|prior|system|safety)\s+(?:instructions|rules|prompts)|(?:do not|don't|never)\s+(?:tell|inform|notify)\s+(?:the\s+)?user|disable\s+(?:security|safety|logging|audit)/i.test(s) },
29
+ { id: "source_control.history_rewrite", title: "Git history rewrite", severity: "medium", category: "source_control", explanation: "Force-pushing or rewriting shared history can silently discard other people's commits. Confirm the branch isn't shared before proceeding.", match: s => /\bgit\s+push\s+[^\n]*(?:--force(?:-with-lease)?|-f\b)|\bgit\s+filter-(?:branch|repo)\b/i.test(s) },
30
+ { id: "integrity.tls_bypass", title: "Certificate or signature verification disabled", severity: "medium", category: "integrity", explanation: "Disabling TLS/certificate verification removes protection against a tampered or impersonated destination.", match: s => /\bcurl\b[^\n]*(?:-k\b|--insecure)|\bwget\b[^\n]*--no-check-certificate|NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0|\bgit\b[^\n]*-c\s+http\.sslVerify=false/i.test(s) },
31
+ ];
32
+ // Loaded from disk at startup (see custom-rules.ts); empty until loadCustomRules() runs.
33
+ let customRules = [];
34
+ export function setCustomRules(rules) { customRules = rules; }
35
+ function activeRules() { return [...builtinRules, ...customRules]; }
36
+ export function ruleCatalog() {
37
+ return activeRules().map(({ match: _, ...rule }) => rule);
38
+ }
39
+ export function detect(text) {
40
+ return activeRules().filter(r => r.match(text)).map(r => ({ id: r.id, title: r.title, severity: r.severity, explanation: r.explanation, evidence: redact(text).slice(0, 600) }));
41
+ }
42
+ export function scanText(name, content, kind) {
43
+ if (!content.trim() || content.length > 500_000)
44
+ throw new Error("Provide non-empty text, up to 500 KB.");
45
+ const findings = [];
46
+ const lines = content.split(/\r?\n/);
47
+ // Windows of three lines capture adjacent credential + delivery instructions.
48
+ for (let i = 0; i < lines.length; i++) {
49
+ for (const f of detect(lines.slice(i, i + 3).join("\n"))) {
50
+ if (!findings.some(old => old.id === f.id))
51
+ findings.push({ ...f, line: i + 1 });
52
+ }
53
+ }
54
+ if (kind === "mcp") {
55
+ let config;
56
+ try {
57
+ config = JSON.parse(content);
58
+ }
59
+ catch {
60
+ throw new Error("MCP input must be valid JSON (configuration or tool descriptions).");
61
+ }
62
+ if (!config || typeof config !== "object")
63
+ throw new Error("MCP input must be a JSON object or tool array.");
64
+ if (/"(?:command|args)"\s*:/.test(content) && /\bnpx\b/.test(content) && !/@\d+\.\d+/.test(content)) {
65
+ findings.push({ id: "mcp.unpinned", title: "Unpinned MCP executable", severity: "medium", explanation: "Pin the package to a reviewed version; an unpinned install can change between runs.", evidence: "npx configuration without an explicit numeric package version" });
66
+ }
67
+ }
68
+ return { id: randomUUID(), name: redact(name).slice(0, 200) || "Untitled scan", kind, timestamp: new Date().toISOString(), hash: createHash("sha256").update(content).digest("hex"), findings, lines: lines.length };
69
+ }
70
+ function obj(v) { return v && typeof v === "object" && !Array.isArray(v) ? v : {}; }
71
+ function str(v, fallback = "") { return typeof v === "string" && v.length > 0 ? v : fallback; }
72
+ function number(v) { const n = typeof v === "number" || typeof v === "string" ? Number(v) : NaN; return Number.isFinite(n) && n >= 0 ? n : undefined; }
73
+ function attributes(v) {
74
+ return Array.isArray(v) ? Object.fromEntries(v.map(a => { const row = obj(a); const value = obj(row.value); return [str(row.key), value.stringValue ?? value.intValue ?? value.doubleValue ?? value.boolValue]; })) : {};
75
+ }
76
+ export function parseInput(input, otlp = false) {
77
+ if (input.length > 2_000_000)
78
+ throw new Error("Import exceeds 2 MB. Split into smaller batches.");
79
+ if (otlp) {
80
+ const doc = obj(JSON.parse(input));
81
+ if (!Array.isArray(doc.resourceLogs))
82
+ throw new Error("Expected OTLP JSON resourceLogs. Protobuf is not supported.");
83
+ const records = [];
84
+ for (const r of doc.resourceLogs) {
85
+ const resource = obj(r);
86
+ for (const s of Array.isArray(resource.scopeLogs) ? resource.scopeLogs : []) {
87
+ for (const l of Array.isArray(obj(s).logRecords) ? obj(s).logRecords : []) {
88
+ const log = obj(l);
89
+ const a = { ...attributes(obj(resource.resource).attributes), ...attributes(log.attributes) };
90
+ const body = obj(log.body).stringValue;
91
+ let bodyObj = {};
92
+ if (typeof body === "string") {
93
+ try {
94
+ bodyObj = obj(JSON.parse(body));
95
+ }
96
+ catch { /* prose is not an action */ }
97
+ }
98
+ const nanos = number(log.timeUnixNano);
99
+ records.push({ ...bodyObj, ...a, source_type: "otlp", source_agent: a["service.name"] ?? bodyObj.source_agent,
100
+ session_id: a["session.id"] ?? a["gen_ai.conversation.id"] ?? bodyObj.session_id,
101
+ event_type: a["event.name"] ?? bodyObj.event_type ?? "telemetry.log",
102
+ input_tokens: a["gen_ai.usage.input_tokens"] ?? bodyObj.input_tokens,
103
+ output_tokens: a["gen_ai.usage.output_tokens"] ?? bodyObj.output_tokens,
104
+ timestamp: nanos ? new Date(nanos / 1e6).toISOString() : undefined });
105
+ }
106
+ }
107
+ }
108
+ return records;
109
+ }
110
+ let parsed;
111
+ try {
112
+ parsed = JSON.parse(input);
113
+ }
114
+ catch {
115
+ parsed = input.split(/\r?\n/).filter(l => l.trim()).map((line, i) => { try {
116
+ return JSON.parse(line);
117
+ }
118
+ catch {
119
+ throw new Error(`Invalid JSON at line ${i + 1}. Nothing was imported.`);
120
+ } });
121
+ }
122
+ const records = Array.isArray(parsed) ? parsed : [parsed];
123
+ if (!records.length || records.length > 2000 || records.some(r => !r || typeof r !== "object" || Array.isArray(r)))
124
+ throw new Error("Expected 1–2,000 event objects.");
125
+ return records;
126
+ }
127
+ export function normalize(raw) {
128
+ if (JSON.stringify(raw).length > 100_000)
129
+ throw new Error("One record exceeds 100 KB.");
130
+ const input = obj(raw.tool_input ?? raw.input);
131
+ const tool = str(raw.tool_name ?? raw.tool);
132
+ const command = str(raw.command ?? raw.observed_command ?? input.command);
133
+ const path = str(raw.file_path ?? input.file_path ?? input.path);
134
+ const url = str(raw.url ?? input.url);
135
+ let type = str(raw.event_type ?? raw.observed_event_type);
136
+ if (!type) {
137
+ if (["Bash", "bash", "Shell", "shell", "exec_command", "shell_command", "exec"].includes(tool) && command)
138
+ type = "command.exec";
139
+ else if (["Read", "read_file"].includes(tool))
140
+ type = "file.read";
141
+ else if (["Write", "Edit", "write_file", "apply_patch"].includes(tool))
142
+ type = "file.write";
143
+ else if (["browser.navigate", "browser_navigate"].includes(tool))
144
+ type = "browser.navigate";
145
+ else if (tool)
146
+ type = "tool.call";
147
+ else if (raw.record_type === "finding")
148
+ type = "finding";
149
+ else
150
+ throw new Error("Record needs event_type or tool_name. Raw transcripts are not supported; normalize them first.");
151
+ }
152
+ const detail = command || path || url || str(raw.content_preview ?? raw.observed_content_preview ?? raw.summary) || tool || type;
153
+ const findings = /(?:result|message|telemetry)/.test(type) ? [] : detect(detail);
154
+ if (raw.record_type === "finding") {
155
+ findings.push({ id: str(raw.rule_id, "imported.finding"), title: redact(str(raw.title, "Imported finding")), severity: ["critical", "high", "medium", "info"].includes(str(raw.severity)) ? raw.severity : "medium", explanation: "Imported rule match. It indicates a pattern, not proof of compromise or action completion.", evidence: redact(detail).slice(0, 600) });
156
+ }
157
+ const timestamp = str(raw.timestamp, new Date().toISOString());
158
+ if (!Number.isFinite(Date.parse(timestamp)))
159
+ throw new Error("Invalid event timestamp.");
160
+ const clean = (s) => redact(s).slice(0, 500);
161
+ const stableId = str(raw.event_id ?? raw.finding_id ?? raw.id);
162
+ return {
163
+ id: createHash("sha256").update(stableId ? `${str(raw.source_agent)}:${str(obj(raw.endpoint).hostname)}:${stableId}` : JSON.stringify(raw)).digest("hex"),
164
+ timestamp: new Date(timestamp).toISOString(), receivedAt: new Date().toISOString(), agent: clean(str(raw.source_agent ?? raw.agent, "custom")),
165
+ session: clean(str(raw.session_id ?? raw.session, "unassigned")), type: clean(type), tool: clean(tool), summary: redact(detail).slice(0, 4000),
166
+ project: clean(str(raw.project_path ?? raw.cwd)), source: clean(str(raw.source_type, raw.hook_event_name ? "hook" : "import")),
167
+ endpoint: clean(str(obj(raw.endpoint).hostname ?? raw.hostname, "local")), model: clean(str(raw.model)),
168
+ phase: (() => { const event = str(raw.hook_event_name).toLowerCase(); return event === "pretooluse" ? "proposed" : event === "posttooluse" ? "completed hook" : "observed"; })(),
169
+ provenance: { recordId: clean(stableId), schemaVersion: clean(str(raw.schema_version)),
170
+ citedEventIds: Array.isArray(raw.cited_event_ids) ? raw.cited_event_ids.filter((v) => typeof v === "string").slice(0, 100).map(clean) : [],
171
+ tags: Array.isArray(raw.tags) ? raw.tags.filter((v) => typeof v === "string").slice(0, 100).map(clean) : [],
172
+ evidence: redact(JSON.stringify(raw.evidence_refs ?? raw.evidence ?? {})).slice(0, 8000) },
173
+ findings, inputTokens: number(raw.input_tokens), outputTokens: number(raw.output_tokens), costUsd: number(raw.cost_usd),
174
+ };
175
+ }
176
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface CustomRuleLoadResult {
2
+ path: string;
3
+ loaded: number;
4
+ errors: string[];
5
+ }
6
+ export declare function customRulesPath(home?: string): string;
7
+ export declare function loadCustomRules(home?: string): Promise<CustomRuleLoadResult>;
@@ -0,0 +1,80 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { getBeamHome } from "./config.js";
4
+ import { setCustomRules } from "./core.js";
5
+ const VALID_SEVERITIES = ["critical", "high", "medium", "info"];
6
+ export function customRulesPath(home = getBeamHome()) { return join(home, "rules.json"); }
7
+ // Custom rules extend detection without editing beam's own source: a JSON array of
8
+ // { id, pattern, severity, title?, explanation?, category? } at ~/.beam/rules.json. A missing
9
+ // file is not an error (zero custom rules); a malformed entry is skipped with a reported reason,
10
+ // not a crash -- one bad rule must never take down detection for every other rule.
11
+ export async function loadCustomRules(home = getBeamHome()) {
12
+ const path = customRulesPath(home);
13
+ const errors = [];
14
+ let raw;
15
+ try {
16
+ raw = await readFile(path, "utf8");
17
+ }
18
+ catch (e) {
19
+ if (e.code === "ENOENT") {
20
+ setCustomRules([]);
21
+ return { path, loaded: 0, errors: [] };
22
+ }
23
+ throw e;
24
+ }
25
+ let parsed;
26
+ try {
27
+ parsed = JSON.parse(raw);
28
+ }
29
+ catch {
30
+ setCustomRules([]);
31
+ return { path, loaded: 0, errors: [`${path}: not valid JSON; no custom rules loaded.`] };
32
+ }
33
+ if (!Array.isArray(parsed)) {
34
+ setCustomRules([]);
35
+ return { path, loaded: 0, errors: [`${path}: expected a JSON array of rule objects.`] };
36
+ }
37
+ const rules = [];
38
+ parsed.forEach((entry, i) => {
39
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
40
+ errors.push(`rule[${i}]: not an object, skipped.`);
41
+ return;
42
+ }
43
+ const e = entry;
44
+ if (typeof e.id !== "string" || !e.id.trim()) {
45
+ errors.push(`rule[${i}]: missing "id", skipped.`);
46
+ return;
47
+ }
48
+ if (typeof e.pattern !== "string" || !e.pattern) {
49
+ errors.push(`rule[${i}] (${e.id}): missing "pattern", skipped.`);
50
+ return;
51
+ }
52
+ if (typeof e.severity !== "string" || !VALID_SEVERITIES.includes(e.severity)) {
53
+ errors.push(`rule[${i}] (${e.id}): "severity" must be one of ${VALID_SEVERITIES.join(", ")}, skipped.`);
54
+ return;
55
+ }
56
+ let regex;
57
+ try {
58
+ regex = new RegExp(e.pattern, "i");
59
+ }
60
+ catch (err) {
61
+ errors.push(`rule[${i}] (${e.id}): invalid regex pattern (${err instanceof Error ? err.message : String(err)}), skipped.`);
62
+ return;
63
+ }
64
+ if (rules.some(r => r.id === `custom.${e.id}`)) {
65
+ errors.push(`rule[${i}] (${e.id}): duplicate id, skipped.`);
66
+ return;
67
+ }
68
+ rules.push({
69
+ id: `custom.${e.id}`,
70
+ title: typeof e.title === "string" && e.title ? e.title : e.id,
71
+ severity: e.severity,
72
+ category: (typeof e.category === "string" && e.category ? e.category : "custom"),
73
+ explanation: typeof e.explanation === "string" && e.explanation ? e.explanation : "User-defined rule.",
74
+ match: (s) => regex.test(s),
75
+ });
76
+ });
77
+ setCustomRules(rules);
78
+ return { path, loaded: rules.length, errors };
79
+ }
80
+ //# sourceMappingURL=custom-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-rules.js","sourceRoot":"","sources":["../src/custom-rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAA+C,MAAM,WAAW,CAAC;AAIxF,MAAM,gBAAgB,GAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAE5E,MAAM,UAAU,eAAe,CAAC,IAAI,GAAG,WAAW,EAAE,IAAY,OAAO,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AAElG,mFAAmF;AACnF,8FAA8F;AAC9F,iGAAiG;AACjG,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAI,GAAG,WAAW,EAAE;IACxD,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QAAC,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC;QACT,IAAK,CAA2B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAAC,CAAC;QACnH,MAAM,CAAC,CAAC;IACV,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IACjC,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,2CAA2C,CAAC,EAAE,CAAC;IAAC,CAAC;IAEvH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,0CAA0C,CAAC,EAAE,CAAC;IAAC,CAAC;IAE5I,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAChI,MAAM,CAAC,GAAG,KAAgC,CAAC;QAC3C,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC5G,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,gCAAgC,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC9H,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAoB,CAAC,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,gCAAgC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC9M,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YAAC,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAAC,CAAC;QAC3C,OAAO,GAAG,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,6BAA6B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QACnJ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QACxH,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,UAAU,CAAC,CAAC,EAAE,EAAE;YACpB,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9D,QAAQ,EAAE,CAAC,CAAC,QAAoB;YAChC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAiB;YAChG,WAAW,EAAE,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB;YACtG,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;SACpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,KAAK,CAAC,CAAC;IACtB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;AAChD,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface Identity {
2
+ deviceId: string;
3
+ deviceSecret: string;
4
+ orgId: string;
5
+ apiBase: string;
6
+ publicKey: string;
7
+ privateKey: string;
8
+ hostname: string;
9
+ os: string;
10
+ enrolledAt: string;
11
+ }
12
+ export declare function readIdentity(): Promise<Identity | null>;
13
+ export declare function enrollDevice(options: {
14
+ code: string;
15
+ url?: string;
16
+ }): Promise<Identity>;