@guilz-dev/belay 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.
- package/LICENSE +21 -0
- package/README.md +268 -0
- package/agent-belay-logo.png +0 -0
- package/dist/adapters/claude/adapter.d.ts +7 -0
- package/dist/adapters/claude/adapter.js +114 -0
- package/dist/adapters/claude/hooks.d.ts +13 -0
- package/dist/adapters/claude/hooks.js +49 -0
- package/dist/adapters/claude/runtime-entry.d.ts +4 -0
- package/dist/adapters/claude/runtime-entry.js +260 -0
- package/dist/adapters/codex/adapter.d.ts +7 -0
- package/dist/adapters/codex/adapter.js +73 -0
- package/dist/adapters/codex/hooks.d.ts +21 -0
- package/dist/adapters/codex/hooks.js +78 -0
- package/dist/adapters/codex/runtime-entry.d.ts +4 -0
- package/dist/adapters/codex/runtime-entry.js +237 -0
- package/dist/adapters/cursor/adapter.d.ts +7 -0
- package/dist/adapters/cursor/adapter.js +29 -0
- package/dist/adapters/cursor/hooks.d.ts +2 -0
- package/dist/adapters/cursor/hooks.js +26 -0
- package/dist/adapters/cursor/runtime-entry.d.ts +4 -0
- package/dist/adapters/cursor/runtime-entry.js +143 -0
- package/dist/adapters/layouts/claude.d.ts +2 -0
- package/dist/adapters/layouts/claude.js +40 -0
- package/dist/adapters/layouts/codex.d.ts +2 -0
- package/dist/adapters/layouts/codex.js +43 -0
- package/dist/adapters/layouts/cursor.d.ts +2 -0
- package/dist/adapters/layouts/cursor.js +40 -0
- package/dist/adapters/layouts/index.d.ts +7 -0
- package/dist/adapters/layouts/index.js +23 -0
- package/dist/adapters/layouts/protected-paths.d.ts +3 -0
- package/dist/adapters/layouts/protected-paths.js +15 -0
- package/dist/adapters/layouts/scope.d.ts +19 -0
- package/dist/adapters/layouts/scope.js +86 -0
- package/dist/adapters/layouts/types.d.ts +14 -0
- package/dist/adapters/layouts/types.js +1 -0
- package/dist/adapters/registry.d.ts +4 -0
- package/dist/adapters/registry.js +14 -0
- package/dist/adapters/shared/gate-runtime.d.ts +51 -0
- package/dist/adapters/shared/gate-runtime.js +518 -0
- package/dist/adapters/shared/repo-root.d.ts +2 -0
- package/dist/adapters/shared/repo-root.js +17 -0
- package/dist/adapters/types.d.ts +19 -0
- package/dist/adapters/types.js +1 -0
- package/dist/branding.d.ts +3 -0
- package/dist/branding.js +3 -0
- package/dist/bundle/claude-runtime.mjs +5323 -0
- package/dist/bundle/codex-runtime.mjs +5310 -0
- package/dist/bundle/cursor-runtime.mjs +5208 -0
- package/dist/cleanup-orphans.d.ts +7 -0
- package/dist/cleanup-orphans.js +59 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +631 -0
- package/dist/commands/approve.d.ts +14 -0
- package/dist/commands/approve.js +65 -0
- package/dist/commands/audit.d.ts +59 -0
- package/dist/commands/audit.js +132 -0
- package/dist/commands/classify-for-report.d.ts +9 -0
- package/dist/commands/classify-for-report.js +85 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.js +366 -0
- package/dist/commands/dogfood.d.ts +5 -0
- package/dist/commands/dogfood.js +71 -0
- package/dist/commands/explain.d.ts +3 -0
- package/dist/commands/explain.js +133 -0
- package/dist/commands/health-snapshot.d.ts +2 -0
- package/dist/commands/health-snapshot.js +166 -0
- package/dist/commands/init-wizard.d.ts +16 -0
- package/dist/commands/init-wizard.js +50 -0
- package/dist/commands/metrics.d.ts +7 -0
- package/dist/commands/metrics.js +89 -0
- package/dist/commands/recover.d.ts +3 -0
- package/dist/commands/recover.js +105 -0
- package/dist/commands/report.d.ts +3 -0
- package/dist/commands/report.js +65 -0
- package/dist/commands/revoke.d.ts +5 -0
- package/dist/commands/revoke.js +22 -0
- package/dist/commands/simulate.d.ts +14 -0
- package/dist/commands/simulate.js +55 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.js +107 -0
- package/dist/config-io.d.ts +23 -0
- package/dist/config-io.js +180 -0
- package/dist/conformance/guarantee-table.d.ts +14 -0
- package/dist/conformance/guarantee-table.js +95 -0
- package/dist/conformance/types.d.ts +6 -0
- package/dist/conformance/types.js +1 -0
- package/dist/core/approval-service.d.ts +26 -0
- package/dist/core/approval-service.js +41 -0
- package/dist/core/approval-token.d.ts +11 -0
- package/dist/core/approval-token.js +61 -0
- package/dist/core/approval.d.ts +19 -0
- package/dist/core/approval.js +58 -0
- package/dist/core/audit-analysis.d.ts +10 -0
- package/dist/core/audit-analysis.js +147 -0
- package/dist/core/audit-metrics.d.ts +51 -0
- package/dist/core/audit-metrics.js +155 -0
- package/dist/core/audit-query.d.ts +11 -0
- package/dist/core/audit-query.js +142 -0
- package/dist/core/audit-summary.d.ts +33 -0
- package/dist/core/audit-summary.js +111 -0
- package/dist/core/audit-types.d.ts +65 -0
- package/dist/core/audit-types.js +2 -0
- package/dist/core/capability/allowlist.d.ts +10 -0
- package/dist/core/capability/allowlist.js +53 -0
- package/dist/core/capability/broker.d.ts +17 -0
- package/dist/core/capability/broker.js +29 -0
- package/dist/core/capability/index.d.ts +5 -0
- package/dist/core/capability/index.js +4 -0
- package/dist/core/capability/paths.d.ts +1 -0
- package/dist/core/capability/paths.js +20 -0
- package/dist/core/capability/reasons.d.ts +2 -0
- package/dist/core/capability/reasons.js +4 -0
- package/dist/core/capability/types.d.ts +10 -0
- package/dist/core/capability/types.js +1 -0
- package/dist/core/capability-approval.d.ts +28 -0
- package/dist/core/capability-approval.js +43 -0
- package/dist/core/classify-subagent.d.ts +2 -0
- package/dist/core/classify-subagent.js +69 -0
- package/dist/core/classify-tool.d.ts +3 -0
- package/dist/core/classify-tool.js +311 -0
- package/dist/core/config-layers.d.ts +23 -0
- package/dist/core/config-layers.js +59 -0
- package/dist/core/config.d.ts +219 -0
- package/dist/core/config.js +720 -0
- package/dist/core/control-plane-isolation.d.ts +10 -0
- package/dist/core/control-plane-isolation.js +83 -0
- package/dist/core/custom-command-match.d.ts +2 -0
- package/dist/core/custom-command-match.js +8 -0
- package/dist/core/egress/allowlist.d.ts +7 -0
- package/dist/core/egress/allowlist.js +33 -0
- package/dist/core/egress/env.d.ts +3 -0
- package/dist/core/egress/env.js +17 -0
- package/dist/core/egress/fingerprint.d.ts +3 -0
- package/dist/core/egress/fingerprint.js +35 -0
- package/dist/core/egress/policy.d.ts +8 -0
- package/dist/core/egress/policy.js +47 -0
- package/dist/core/egress/proxy-server.d.ts +21 -0
- package/dist/core/egress/proxy-server.js +263 -0
- package/dist/core/egress/types.d.ts +25 -0
- package/dist/core/egress/types.js +1 -0
- package/dist/core/egress-approval.d.ts +48 -0
- package/dist/core/egress-approval.js +129 -0
- package/dist/core/fingerprint.d.ts +6 -0
- package/dist/core/fingerprint.js +24 -0
- package/dist/core/gate-contract.d.ts +48 -0
- package/dist/core/gate-contract.js +50 -0
- package/dist/core/gate-engine.d.ts +20 -0
- package/dist/core/gate-engine.js +172 -0
- package/dist/core/glob.d.ts +1 -0
- package/dist/core/glob.js +39 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.js +15 -0
- package/dist/core/integrity.d.ts +15 -0
- package/dist/core/integrity.js +68 -0
- package/dist/core/judge-api-key.d.ts +4 -0
- package/dist/core/judge-api-key.js +11 -0
- package/dist/core/judge-config.d.ts +29 -0
- package/dist/core/judge-config.js +85 -0
- package/dist/core/judge-doctor.d.ts +7 -0
- package/dist/core/judge-doctor.js +124 -0
- package/dist/core/judgment.d.ts +6 -0
- package/dist/core/judgment.js +38 -0
- package/dist/core/notify.d.ts +13 -0
- package/dist/core/notify.js +44 -0
- package/dist/core/path-utils.d.ts +12 -0
- package/dist/core/path-utils.js +107 -0
- package/dist/core/reclassify.d.ts +15 -0
- package/dist/core/reclassify.js +82 -0
- package/dist/core/recover-advice.d.ts +30 -0
- package/dist/core/recover-advice.js +177 -0
- package/dist/core/recover-git-probe.d.ts +8 -0
- package/dist/core/recover-git-probe.js +50 -0
- package/dist/core/recover-select.d.ts +10 -0
- package/dist/core/recover-select.js +60 -0
- package/dist/core/scrub.d.ts +3 -0
- package/dist/core/scrub.js +87 -0
- package/dist/core/shell-substitution.d.ts +6 -0
- package/dist/core/shell-substitution.js +130 -0
- package/dist/core/shell-tokenizer.d.ts +5 -0
- package/dist/core/shell-tokenizer.js +129 -0
- package/dist/core/shell-unparseable.d.ts +4 -0
- package/dist/core/shell-unparseable.js +96 -0
- package/dist/core/transactional/diff-evaluator.d.ts +2 -0
- package/dist/core/transactional/diff-evaluator.js +84 -0
- package/dist/core/transactional/eligibility.d.ts +4 -0
- package/dist/core/transactional/eligibility.js +44 -0
- package/dist/core/transactional/git-worktree.d.ts +13 -0
- package/dist/core/transactional/git-worktree.js +189 -0
- package/dist/core/transactional/index.d.ts +5 -0
- package/dist/core/transactional/index.js +4 -0
- package/dist/core/transactional/reasons.d.ts +4 -0
- package/dist/core/transactional/reasons.js +8 -0
- package/dist/core/transactional/runner.d.ts +2 -0
- package/dist/core/transactional/runner.js +113 -0
- package/dist/core/transactional/types.d.ts +46 -0
- package/dist/core/transactional/types.js +1 -0
- package/dist/core/types.d.ts +90 -0
- package/dist/core/types.js +1 -0
- package/dist/core/v2/adapter.d.ts +14 -0
- package/dist/core/v2/adapter.js +118 -0
- package/dist/core/v2/containment.d.ts +19 -0
- package/dist/core/v2/containment.js +91 -0
- package/dist/core/v2/egress-classify.d.ts +7 -0
- package/dist/core/v2/egress-classify.js +216 -0
- package/dist/core/v2/fingerprint.d.ts +1 -0
- package/dist/core/v2/fingerprint.js +4 -0
- package/dist/core/v2/index.d.ts +12 -0
- package/dist/core/v2/index.js +10 -0
- package/dist/core/v2/judge-audit.d.ts +2 -0
- package/dist/core/v2/judge-audit.js +15 -0
- package/dist/core/v2/judge-factory.d.ts +25 -0
- package/dist/core/v2/judge-factory.js +75 -0
- package/dist/core/v2/judge-outbound.d.ts +12 -0
- package/dist/core/v2/judge-outbound.js +73 -0
- package/dist/core/v2/judge.d.ts +47 -0
- package/dist/core/v2/judge.js +264 -0
- package/dist/core/v2/launcher-resolve.d.ts +12 -0
- package/dist/core/v2/launcher-resolve.js +190 -0
- package/dist/core/v2/overrides.d.ts +7 -0
- package/dist/core/v2/overrides.js +37 -0
- package/dist/core/v2/parser.d.ts +21 -0
- package/dist/core/v2/parser.js +213 -0
- package/dist/core/v2/types.d.ts +67 -0
- package/dist/core/v2/types.js +1 -0
- package/dist/core/v2/verdict.d.ts +2 -0
- package/dist/core/v2/verdict.js +699 -0
- package/dist/corpus/evaluate.d.ts +24 -0
- package/dist/corpus/evaluate.js +69 -0
- package/dist/defaults.d.ts +18 -0
- package/dist/defaults.js +155 -0
- package/dist/egress-daemon.d.ts +1 -0
- package/dist/egress-daemon.js +52 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +15 -0
- package/dist/installer/bootstrap.d.ts +5 -0
- package/dist/installer/bootstrap.js +61 -0
- package/dist/installer/runtime-artifacts.d.ts +3 -0
- package/dist/installer/runtime-artifacts.js +23 -0
- package/dist/installer/scope-config.d.ts +8 -0
- package/dist/installer/scope-config.js +25 -0
- package/dist/installer.d.ts +22 -0
- package/dist/installer.js +169 -0
- package/dist/node-resolution.d.ts +8 -0
- package/dist/node-resolution.js +237 -0
- package/dist/operational-insights.d.ts +19 -0
- package/dist/operational-insights.js +24 -0
- package/dist/presets.d.ts +4 -0
- package/dist/presets.js +95 -0
- package/dist/services/egress-service.d.ts +57 -0
- package/dist/services/egress-service.js +334 -0
- package/dist/services/sandbox-service.d.ts +38 -0
- package/dist/services/sandbox-service.js +95 -0
- package/dist/templates.d.ts +7 -0
- package/dist/templates.js +56 -0
- package/dist/types.d.ts +230 -0
- package/dist/types.js +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +65 -0
- package/skills/belay/SKILL.md +52 -0
- package/skills/belay/belay-approve.md +7 -0
- package/skills/belay/belay-explain.md +11 -0
- package/skills/belay/belay-recover.md +13 -0
- package/skills/belay/belay-report.md +7 -0
- package/skills/belay/belay-status.md +9 -0
- package/skills/belay/belay-why.md +11 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { matchesCustomCommand } from '../custom-command-match.js';
|
|
2
|
+
export function matchesCustomPatterns(command, segment, patterns) {
|
|
3
|
+
if (!patterns || patterns.length === 0) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const normalized = command.trim();
|
|
7
|
+
return patterns.some((pattern) => matchesCustomCommand(normalized, segment.key, pattern) ||
|
|
8
|
+
matchesCustomCommand(segment.normalized, segment.key, pattern));
|
|
9
|
+
}
|
|
10
|
+
export function customAllowMatch(command, segment, context) {
|
|
11
|
+
return matchesCustomPatterns(command, segment, context.customAllowCommands);
|
|
12
|
+
}
|
|
13
|
+
export function customExternalMatch(command, segment, context) {
|
|
14
|
+
return matchesCustomPatterns(command, segment, context.customExternalCommands);
|
|
15
|
+
}
|
|
16
|
+
export function allowFromCustomOverride(opacity) {
|
|
17
|
+
return {
|
|
18
|
+
permission: 'allow',
|
|
19
|
+
location: 'repo_local',
|
|
20
|
+
opacity,
|
|
21
|
+
effect: 'unknown',
|
|
22
|
+
confidence: 'deterministic',
|
|
23
|
+
reason: 'custom_allow',
|
|
24
|
+
signals: ['custom_allow'],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function askFromCustomExternal(opacity) {
|
|
28
|
+
return {
|
|
29
|
+
permission: 'ask',
|
|
30
|
+
location: 'external',
|
|
31
|
+
opacity,
|
|
32
|
+
effect: 'remote_mutation',
|
|
33
|
+
confidence: 'deterministic',
|
|
34
|
+
reason: 'custom_external',
|
|
35
|
+
signals: ['custom_external'],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { VerdictOpacity } from './types.js';
|
|
2
|
+
export interface ParsedSegment {
|
|
3
|
+
tokens: string[];
|
|
4
|
+
head: string;
|
|
5
|
+
key: string;
|
|
6
|
+
normalized: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function normalizeHead(token: string): string;
|
|
9
|
+
export declare function peelTransparentWrappers(tokens: string[]): {
|
|
10
|
+
tokens: string[];
|
|
11
|
+
xargsStdinOpaque: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare function isVariableIndirectHead(head: string): boolean;
|
|
14
|
+
export declare function extractEvalBody(tokens: string[]): string | null;
|
|
15
|
+
export declare function extractRecursiveScript(tokens: string[]): string | null;
|
|
16
|
+
export declare function isBareInterpreter(tokens: string[]): boolean;
|
|
17
|
+
export declare function splitTopLevelSegments(command: string): string[];
|
|
18
|
+
export declare function parseSegment(command: string): ParsedSegment;
|
|
19
|
+
export declare function segmentOpacity(command: string): VerdictOpacity;
|
|
20
|
+
export declare function substitutionInners(command: string): string[];
|
|
21
|
+
export declare function redactCommand(command: string): string;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findCommandSubstitutions } from '../shell-substitution.js';
|
|
3
|
+
import { commandKey, tokenizeShell } from '../shell-tokenizer.js';
|
|
4
|
+
import { detectUnparseableShell } from '../shell-unparseable.js';
|
|
5
|
+
const ENV_PREFIX_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|"[^"]*"|\S+)$/;
|
|
6
|
+
const TRANSPARENT_WRAPPERS = new Set([
|
|
7
|
+
'sudo',
|
|
8
|
+
'env',
|
|
9
|
+
'nohup',
|
|
10
|
+
'time',
|
|
11
|
+
'nice',
|
|
12
|
+
'ionice',
|
|
13
|
+
'stdbuf',
|
|
14
|
+
'setsid',
|
|
15
|
+
'xargs',
|
|
16
|
+
]);
|
|
17
|
+
const SHELL_INTERPRETERS = new Set(['bash', 'sh', 'zsh', 'dash', 'fish']);
|
|
18
|
+
const CODE_INTERPRETERS = new Set(['python', 'python3', 'node', 'ruby', 'perl', 'osascript']);
|
|
19
|
+
const SCRIPT_FLAGS = new Set(['-c', '-lc', '-e', '--eval']);
|
|
20
|
+
const INTERPRETER_SCRIPT_EXTENSIONS = new Set([
|
|
21
|
+
'.js',
|
|
22
|
+
'.mjs',
|
|
23
|
+
'.cjs',
|
|
24
|
+
'.ts',
|
|
25
|
+
'.py',
|
|
26
|
+
'.rb',
|
|
27
|
+
'.pl',
|
|
28
|
+
'.sh',
|
|
29
|
+
]);
|
|
30
|
+
export function normalizeHead(token) {
|
|
31
|
+
const base = path.basename(token);
|
|
32
|
+
if (base && base !== '.' && base !== '..') {
|
|
33
|
+
return base;
|
|
34
|
+
}
|
|
35
|
+
return token;
|
|
36
|
+
}
|
|
37
|
+
export function peelTransparentWrappers(tokens) {
|
|
38
|
+
let current = [...tokens];
|
|
39
|
+
let xargsStdinOpaque = false;
|
|
40
|
+
while (current.length > 0) {
|
|
41
|
+
while (current.length > 0 && ENV_PREFIX_PATTERN.test(current[0] ?? '')) {
|
|
42
|
+
current.shift();
|
|
43
|
+
}
|
|
44
|
+
if (current.length === 0) {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
const head = normalizeHead(current[0] ?? '');
|
|
48
|
+
if (!TRANSPARENT_WRAPPERS.has(head)) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
if (head === 'xargs') {
|
|
52
|
+
let index = 1;
|
|
53
|
+
while (index < current.length && current[index]?.startsWith('-')) {
|
|
54
|
+
index += 1;
|
|
55
|
+
}
|
|
56
|
+
const rest = current.slice(index);
|
|
57
|
+
if (rest.length === 0) {
|
|
58
|
+
xargsStdinOpaque = true;
|
|
59
|
+
return { tokens: [], xargsStdinOpaque: true };
|
|
60
|
+
}
|
|
61
|
+
current = rest;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (head === 'env') {
|
|
65
|
+
let index = 1;
|
|
66
|
+
while (index < current.length) {
|
|
67
|
+
const token = current[index] ?? '';
|
|
68
|
+
if (ENV_PREFIX_PATTERN.test(token) || token.startsWith('-')) {
|
|
69
|
+
index += 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
current = current.slice(index);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
current = current.slice(1);
|
|
78
|
+
}
|
|
79
|
+
return { tokens: current, xargsStdinOpaque };
|
|
80
|
+
}
|
|
81
|
+
export function isVariableIndirectHead(head) {
|
|
82
|
+
return head.startsWith('$');
|
|
83
|
+
}
|
|
84
|
+
export function extractEvalBody(tokens) {
|
|
85
|
+
const head = normalizeHead(tokens[0] ?? '');
|
|
86
|
+
if (head !== 'eval') {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const body = tokens.slice(1).join(' ').trim();
|
|
90
|
+
return body || null;
|
|
91
|
+
}
|
|
92
|
+
export function extractRecursiveScript(tokens) {
|
|
93
|
+
const filtered = tokens.filter((token) => token !== 'sudo');
|
|
94
|
+
const head = normalizeHead(filtered[0] ?? '');
|
|
95
|
+
const second = filtered[1] ?? '';
|
|
96
|
+
if (head === 'eval') {
|
|
97
|
+
return extractEvalBody(tokens);
|
|
98
|
+
}
|
|
99
|
+
if (SHELL_INTERPRETERS.has(head) || CODE_INTERPRETERS.has(head)) {
|
|
100
|
+
const flagIndex = filtered.findIndex((token) => SCRIPT_FLAGS.has(token));
|
|
101
|
+
if (flagIndex !== -1) {
|
|
102
|
+
const body = filtered
|
|
103
|
+
.slice(flagIndex + 1)
|
|
104
|
+
.join(' ')
|
|
105
|
+
.replace(/^['"]|['"]$/g, '')
|
|
106
|
+
.trim();
|
|
107
|
+
return body || null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (head === 'bash' && (second === '-lc' || second === '-c')) {
|
|
111
|
+
const body = filtered
|
|
112
|
+
.slice(2)
|
|
113
|
+
.join(' ')
|
|
114
|
+
.replace(/^['"]|['"]$/g, '')
|
|
115
|
+
.trim();
|
|
116
|
+
return body || null;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
export function isBareInterpreter(tokens) {
|
|
121
|
+
const { tokens: peeled, xargsStdinOpaque } = peelTransparentWrappers(tokens);
|
|
122
|
+
if (xargsStdinOpaque) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (peeled.length === 0) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
const head = normalizeHead(peeled[0] ?? '');
|
|
129
|
+
if (!SHELL_INTERPRETERS.has(head) && !CODE_INTERPRETERS.has(head)) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const hasScriptFlag = peeled.some((token) => SCRIPT_FLAGS.has(token));
|
|
133
|
+
if (hasScriptFlag) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
const args = peeled.slice(1);
|
|
137
|
+
if (args.length === 0) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
if (args.every((token) => token.startsWith('-'))) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const scriptArg = args.find((token) => !token.startsWith('-'));
|
|
144
|
+
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path.extname(scriptArg))) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (scriptArg) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
export function splitTopLevelSegments(command) {
|
|
153
|
+
const tokens = tokenizeShell(command);
|
|
154
|
+
const segments = [];
|
|
155
|
+
let current = [];
|
|
156
|
+
const flush = () => {
|
|
157
|
+
if (current.length > 0) {
|
|
158
|
+
segments.push(current.join(' '));
|
|
159
|
+
current = [];
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
for (const token of tokens) {
|
|
163
|
+
if (token === '&&' || token === '||' || token === ';' || token === '|' || token === '&') {
|
|
164
|
+
flush();
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
current.push(token);
|
|
168
|
+
}
|
|
169
|
+
flush();
|
|
170
|
+
return segments.filter((segment) => segment.trim().length > 0);
|
|
171
|
+
}
|
|
172
|
+
export function parseSegment(command) {
|
|
173
|
+
const tokens = tokenizeShell(command);
|
|
174
|
+
const { tokens: peeled } = peelTransparentWrappers(tokens);
|
|
175
|
+
const normalizedTokens = peeled.map((token) => normalizeHead(token));
|
|
176
|
+
const key = commandKey(peeled.map((token, index) => (index === 0 ? normalizeHead(token) : token)));
|
|
177
|
+
return {
|
|
178
|
+
tokens: peeled,
|
|
179
|
+
head: normalizeHead(peeled[0] ?? ''),
|
|
180
|
+
key,
|
|
181
|
+
normalized: normalizedTokens.join(' ').trim(),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export function segmentOpacity(command) {
|
|
185
|
+
if (detectUnparseableShell(command)) {
|
|
186
|
+
return 'unparseable';
|
|
187
|
+
}
|
|
188
|
+
const tokens = tokenizeShell(command);
|
|
189
|
+
const { xargsStdinOpaque } = peelTransparentWrappers(tokens);
|
|
190
|
+
if (xargsStdinOpaque) {
|
|
191
|
+
return 'opaque';
|
|
192
|
+
}
|
|
193
|
+
if (isBareInterpreter(tokens)) {
|
|
194
|
+
return 'opaque';
|
|
195
|
+
}
|
|
196
|
+
const segment = parseSegment(command);
|
|
197
|
+
if (isVariableIndirectHead(segment.head)) {
|
|
198
|
+
return 'opaque';
|
|
199
|
+
}
|
|
200
|
+
if (extractRecursiveScript(tokens)) {
|
|
201
|
+
return 'recursive';
|
|
202
|
+
}
|
|
203
|
+
return 'transparent';
|
|
204
|
+
}
|
|
205
|
+
export function substitutionInners(command) {
|
|
206
|
+
return findCommandSubstitutions(command);
|
|
207
|
+
}
|
|
208
|
+
export function redactCommand(command) {
|
|
209
|
+
return command
|
|
210
|
+
.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, 'Bearer [REDACTED]')
|
|
211
|
+
.replace(/sk-[A-Za-z0-9]{8,}/g, 'sk-[REDACTED]')
|
|
212
|
+
.trim();
|
|
213
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type VerdictPermission = 'allow' | 'ask';
|
|
2
|
+
export type VerdictLocation = 'repo_local' | 'repo_outside' | 'external' | 'mixed' | 'unknown';
|
|
3
|
+
export type VerdictOpacity = 'transparent' | 'recursive' | 'opaque' | 'unparseable';
|
|
4
|
+
export type VerdictEffect = 'read_only' | 'local_mutation' | 'remote_mutation' | 'unknown';
|
|
5
|
+
export type VerdictConfidence = 'deterministic' | 'llm' | 'assumed_repo_local' | 'verified_substrate';
|
|
6
|
+
export interface VerdictResult {
|
|
7
|
+
permission: VerdictPermission;
|
|
8
|
+
location: VerdictLocation;
|
|
9
|
+
opacity: VerdictOpacity;
|
|
10
|
+
effect: VerdictEffect;
|
|
11
|
+
confidence: VerdictConfidence;
|
|
12
|
+
reason: string;
|
|
13
|
+
commandRedacted: string;
|
|
14
|
+
fingerprint: string;
|
|
15
|
+
signals: string[];
|
|
16
|
+
judgeTrace?: JudgeTrace;
|
|
17
|
+
}
|
|
18
|
+
export interface Tier1Verdict {
|
|
19
|
+
external_change: boolean;
|
|
20
|
+
destroys_outside_repo: boolean;
|
|
21
|
+
destroys_history_or_secrets: boolean;
|
|
22
|
+
reason: string;
|
|
23
|
+
}
|
|
24
|
+
export interface Tier1EvaluateInput {
|
|
25
|
+
text: string;
|
|
26
|
+
context: {
|
|
27
|
+
cwd: string;
|
|
28
|
+
repoRoot: string;
|
|
29
|
+
};
|
|
30
|
+
innerCode?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface Tier1Judge {
|
|
33
|
+
evaluate(input: Tier1EvaluateInput): Promise<Tier1Verdict>;
|
|
34
|
+
}
|
|
35
|
+
export interface JudgeTrace {
|
|
36
|
+
provider: 'openai-compatible' | 'ollama' | 'fallback';
|
|
37
|
+
modelRequested: string;
|
|
38
|
+
modelResolved: string;
|
|
39
|
+
latencyMs: number;
|
|
40
|
+
outboundRedacted?: boolean;
|
|
41
|
+
fallbackReason?: string;
|
|
42
|
+
}
|
|
43
|
+
export type VerdictMode = 'enforce' | 'audit';
|
|
44
|
+
export interface VerdictContext {
|
|
45
|
+
cwd: string;
|
|
46
|
+
repoRoot: string;
|
|
47
|
+
trustedCwd: boolean;
|
|
48
|
+
sensitivePaths: string[];
|
|
49
|
+
protectedArtifactRoots?: string[];
|
|
50
|
+
customAllowCommands?: string[];
|
|
51
|
+
customExternalCommands?: string[];
|
|
52
|
+
judge: Tier1Judge;
|
|
53
|
+
mode: VerdictMode;
|
|
54
|
+
unknownLocalEffect: 'allow_flagged' | 'deny';
|
|
55
|
+
unparseableShell: 'allow_flagged' | 'deny';
|
|
56
|
+
maxRecursionDepth?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface InternalSegmentVerdict {
|
|
59
|
+
permission: VerdictPermission;
|
|
60
|
+
location: VerdictLocation;
|
|
61
|
+
opacity: VerdictOpacity;
|
|
62
|
+
effect: VerdictEffect;
|
|
63
|
+
confidence: VerdictConfidence;
|
|
64
|
+
reason: string;
|
|
65
|
+
signals: string[];
|
|
66
|
+
judgeTrace?: JudgeTrace;
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|