@guilz-dev/belay 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.
Files changed (158) hide show
  1. package/README.md +7 -1
  2. package/dist/adapters/layouts/scope.js +3 -2
  3. package/dist/adapters/shared/gate-runtime.d.ts +1 -2
  4. package/dist/adapters/shared/gate-runtime.js +226 -28
  5. package/dist/bundle/claude-runtime.mjs +6967 -4078
  6. package/dist/bundle/codex-runtime.mjs +5951 -3064
  7. package/dist/bundle/cursor-runtime.mjs +5951 -3064
  8. package/dist/cli.js +43 -1
  9. package/dist/commands/classify-for-report.js +1 -1
  10. package/dist/commands/config.d.ts +8 -0
  11. package/dist/commands/config.js +134 -11
  12. package/dist/commands/doctor.js +36 -1
  13. package/dist/commands/explain.js +11 -1
  14. package/dist/commands/judge.js +3 -2
  15. package/dist/commands/session.d.ts +20 -0
  16. package/dist/commands/session.js +51 -0
  17. package/dist/config-io.js +49 -12
  18. package/dist/conformance/guarantee-posture.d.ts +21 -0
  19. package/dist/conformance/guarantee-posture.js +46 -0
  20. package/dist/conformance/guarantee-table.d.ts +1 -0
  21. package/dist/conformance/guarantee-table.js +14 -9
  22. package/dist/core/approval-service.js +6 -2
  23. package/dist/core/approval.d.ts +2 -0
  24. package/dist/core/approval.js +14 -3
  25. package/dist/core/capability/approval-state-mutation.d.ts +13 -0
  26. package/dist/core/capability/approval-state-mutation.js +92 -0
  27. package/dist/core/capability/approval-v3.d.ts +15 -0
  28. package/dist/core/capability/approval-v3.js +74 -0
  29. package/dist/core/capability/attestation.d.ts +13 -0
  30. package/dist/core/capability/attestation.js +55 -0
  31. package/dist/core/capability/boundary-attestation-sign.d.ts +21 -0
  32. package/dist/core/capability/boundary-attestation-sign.js +84 -0
  33. package/dist/core/capability/boundary-driver-container.d.ts +7 -0
  34. package/dist/core/capability/boundary-driver-container.js +122 -0
  35. package/dist/core/capability/boundary-driver.d.ts +29 -0
  36. package/dist/core/capability/boundary-driver.js +43 -0
  37. package/dist/core/capability/boundary-egress.d.ts +21 -0
  38. package/dist/core/capability/boundary-egress.js +109 -0
  39. package/dist/core/capability/boundary-grant-materialize.d.ts +13 -0
  40. package/dist/core/capability/boundary-grant-materialize.js +78 -0
  41. package/dist/core/capability/boundary-profile.d.ts +15 -0
  42. package/dist/core/capability/boundary-profile.js +25 -0
  43. package/dist/core/capability/boundary-run.d.ts +23 -0
  44. package/dist/core/capability/boundary-run.js +23 -0
  45. package/dist/core/capability/boundary-session.d.ts +57 -0
  46. package/dist/core/capability/boundary-session.js +129 -0
  47. package/dist/core/capability/capability-request-hash.d.ts +2 -0
  48. package/dist/core/capability/capability-request-hash.js +8 -0
  49. package/dist/core/capability/gate-latency-ratchet.d.ts +7 -0
  50. package/dist/core/capability/gate-latency-ratchet.js +18 -0
  51. package/dist/core/capability/gate-policy-shadow.d.ts +25 -0
  52. package/dist/core/capability/gate-policy-shadow.js +108 -0
  53. package/dist/core/capability/gate-shadow-audit.d.ts +1 -0
  54. package/dist/core/capability/gate-shadow-audit.js +1 -0
  55. package/dist/core/capability/gate-shadow-ratchet.d.ts +14 -0
  56. package/dist/core/capability/gate-shadow-ratchet.js +81 -0
  57. package/dist/core/capability/grant-lease.d.ts +9 -0
  58. package/dist/core/capability/grant-lease.js +46 -0
  59. package/dist/core/capability/grant-loader.d.ts +12 -0
  60. package/dist/core/capability/grant-loader.js +23 -0
  61. package/dist/core/capability/grant-match.d.ts +6 -0
  62. package/dist/core/capability/grant-match.js +93 -0
  63. package/dist/core/capability/grant.d.ts +16 -0
  64. package/dist/core/capability/grant.js +16 -0
  65. package/dist/core/capability/index.d.ts +8 -0
  66. package/dist/core/capability/index.js +7 -0
  67. package/dist/core/capability/limits.d.ts +7 -0
  68. package/dist/core/capability/limits.js +55 -0
  69. package/dist/core/capability/policy-bridge.d.ts +18 -0
  70. package/dist/core/capability/policy-bridge.js +51 -0
  71. package/dist/core/capability/policy-engine.d.ts +70 -0
  72. package/dist/core/capability/policy-engine.js +476 -0
  73. package/dist/core/capability/policy-types.d.ts +20 -0
  74. package/dist/core/capability/policy-types.js +1 -0
  75. package/dist/core/capability/request.d.ts +45 -0
  76. package/dist/core/capability/request.js +1 -0
  77. package/dist/core/capability/resolver.d.ts +4 -0
  78. package/dist/core/capability/resolver.js +4 -0
  79. package/dist/core/classify-subagent.d.ts +2 -1
  80. package/dist/core/classify-subagent.js +38 -2
  81. package/dist/core/classify-tool.js +126 -62
  82. package/dist/core/config.d.ts +14 -3
  83. package/dist/core/config.js +56 -3
  84. package/dist/core/gate-contract.d.ts +3 -0
  85. package/dist/core/gate-contract.js +3 -0
  86. package/dist/core/gate-engine.js +6 -1
  87. package/dist/core/judge-doctor.js +39 -14
  88. package/dist/core/judge-fallback-hints.d.ts +13 -0
  89. package/dist/core/judge-fallback-hints.js +108 -0
  90. package/dist/core/path-utils.d.ts +1 -0
  91. package/dist/core/path-utils.js +5 -2
  92. package/dist/core/recovery/capability.d.ts +3 -0
  93. package/dist/core/recovery/capability.js +22 -0
  94. package/dist/core/recovery/fail-closed.d.ts +6 -0
  95. package/dist/core/recovery/fail-closed.js +25 -0
  96. package/dist/core/recovery/index.d.ts +3 -0
  97. package/dist/core/recovery/index.js +2 -0
  98. package/dist/core/recovery/types.d.ts +20 -0
  99. package/dist/core/recovery/types.js +1 -0
  100. package/dist/core/standing-allow.js +3 -0
  101. package/dist/core/transactional/diff-evaluator.js +4 -1
  102. package/dist/core/transactional/eligibility.js +4 -0
  103. package/dist/core/transactional/git-worktree.d.ts +10 -3
  104. package/dist/core/transactional/git-worktree.js +81 -11
  105. package/dist/core/transactional/reasons.d.ts +1 -0
  106. package/dist/core/transactional/reasons.js +4 -0
  107. package/dist/core/transactional/runner.js +22 -6
  108. package/dist/core/transactional/types.d.ts +4 -0
  109. package/dist/core/types.d.ts +21 -3
  110. package/dist/core/verdict/adapter.d.ts +3 -4
  111. package/dist/core/verdict/adapter.js +16 -12
  112. package/dist/core/verdict/cursor-acp-client.d.ts +67 -0
  113. package/dist/core/verdict/cursor-acp-client.js +345 -0
  114. package/dist/core/verdict/egress-classify.d.ts +2 -2
  115. package/dist/core/verdict/egress-classify.js +2 -2
  116. package/dist/core/verdict/git-classifier.d.ts +26 -0
  117. package/dist/core/verdict/git-classifier.js +533 -0
  118. package/dist/core/verdict/judge-audit.js +1 -0
  119. package/dist/core/verdict/judge-baseline.d.ts +1 -1
  120. package/dist/core/verdict/judge-baseline.js +1 -0
  121. package/dist/core/verdict/judge-broker-service.js +12 -0
  122. package/dist/core/verdict/judge-catalog.js +1 -0
  123. package/dist/core/verdict/judge-cli-fingerprint.d.ts +1 -0
  124. package/dist/core/verdict/judge-cli-fingerprint.js +6 -0
  125. package/dist/core/verdict/judge-cli.js +5 -3
  126. package/dist/core/verdict/judge-provider-matrix.js +1 -1
  127. package/dist/core/verdict/judge-runtime-config.d.ts +2 -0
  128. package/dist/core/verdict/judge-runtime-config.js +10 -6
  129. package/dist/core/verdict/judge-session-broker.d.ts +1 -1
  130. package/dist/core/verdict/judge-session-broker.js +10 -5
  131. package/dist/core/verdict/judge-transport.d.ts +5 -1
  132. package/dist/core/verdict/judge-transport.js +24 -14
  133. package/dist/core/verdict/judge.d.ts +2 -15
  134. package/dist/core/verdict/judge.js +5 -68
  135. package/dist/core/verdict/launcher-resolve.d.ts +2 -0
  136. package/dist/core/verdict/launcher-resolve.js +16 -0
  137. package/dist/core/verdict/prescan.d.ts +15 -0
  138. package/dist/core/verdict/prescan.js +68 -0
  139. package/dist/core/verdict/shell-policy.d.ts +25 -0
  140. package/dist/core/verdict/shell-policy.js +40 -0
  141. package/dist/core/verdict/shell-semantics.d.ts +24 -0
  142. package/dist/core/verdict/shell-semantics.js +225 -0
  143. package/dist/core/verdict/types.d.ts +13 -1
  144. package/dist/core/verdict/verdict.js +296 -178
  145. package/dist/corpus/evaluate.js +3 -7
  146. package/dist/corpus/gate-latency-budget.d.ts +39 -0
  147. package/dist/corpus/gate-latency-budget.js +33 -0
  148. package/dist/corpus/mutators.d.ts +1 -1
  149. package/dist/corpus/mutators.js +11 -0
  150. package/dist/corpus/runtime-match.js +1 -3
  151. package/dist/corpus/standing-allow-catalog.generated.js +29 -9
  152. package/dist/judge-broker-daemon.js +15 -1
  153. package/dist/services/sandbox-service.d.ts +4 -0
  154. package/dist/services/sandbox-service.js +28 -2
  155. package/dist/types.d.ts +2 -2
  156. package/dist/version.d.ts +1 -1
  157. package/dist/version.js +1 -1
  158. package/package.json +1 -1
@@ -0,0 +1,225 @@
1
+ import path from 'node:path';
2
+ import { extractRedirectTargets } from '../shell-tokenizer.js';
3
+ import { classifyGitCommand } from './git-classifier.js';
4
+ const READ_ONLY_KEYS = new Set([
5
+ 'cat',
6
+ 'cd',
7
+ 'echo',
8
+ 'head',
9
+ 'ls',
10
+ 'pwd',
11
+ 'rg',
12
+ 'sort',
13
+ 'tail',
14
+ 'wc',
15
+ 'which',
16
+ 'find',
17
+ 'grep',
18
+ 'jq',
19
+ 'stat',
20
+ 'file',
21
+ 'du',
22
+ 'readlink',
23
+ 'realpath',
24
+ 'basename',
25
+ 'dirname',
26
+ 'uname',
27
+ 'whoami',
28
+ 'id',
29
+ 'printenv',
30
+ 'test',
31
+ 'printf',
32
+ 'cut',
33
+ 'tr',
34
+ 'uniq',
35
+ 'cmp',
36
+ 'comm',
37
+ 'shasum',
38
+ 'md5sum',
39
+ ]);
40
+ const PURE_READ_ONLY_KEYS = new Set([
41
+ 'echo',
42
+ 'pwd',
43
+ 'which',
44
+ 'grep',
45
+ 'jq',
46
+ 'stat',
47
+ 'file',
48
+ 'du',
49
+ 'readlink',
50
+ 'realpath',
51
+ 'basename',
52
+ 'dirname',
53
+ 'uname',
54
+ 'whoami',
55
+ 'id',
56
+ 'printenv',
57
+ 'test',
58
+ 'printf',
59
+ 'cut',
60
+ 'tr',
61
+ 'uniq',
62
+ 'cmp',
63
+ 'comm',
64
+ 'shasum',
65
+ 'md5sum',
66
+ ]);
67
+ const LOCAL_MUTATION_KEYS = new Set([
68
+ 'chmod',
69
+ 'cp',
70
+ 'mkdir',
71
+ 'mv',
72
+ 'rm',
73
+ 'sed',
74
+ 'tee',
75
+ 'touch',
76
+ 'truncate',
77
+ ]);
78
+ export const LOCAL_ROUTINE_HEADS = new Set([
79
+ 'tsc',
80
+ 'vitest',
81
+ 'vite',
82
+ 'webpack',
83
+ 'esbuild',
84
+ 'rollup',
85
+ 'jest',
86
+ 'mocha',
87
+ 'cargo',
88
+ 'go',
89
+ 'make',
90
+ 'cmake',
91
+ 'biome',
92
+ 'eslint',
93
+ ]);
94
+ function looksLikePathToken(token) {
95
+ if (!token || token.startsWith('-')) {
96
+ return false;
97
+ }
98
+ return (token.includes('/') || token.includes('\\') || token.startsWith('.') || token.includes('...'));
99
+ }
100
+ function filterRoutinePathTargets(head, targets) {
101
+ if (!LOCAL_ROUTINE_HEADS.has(head)) {
102
+ return targets;
103
+ }
104
+ return targets.filter((target) => looksLikePathToken(target));
105
+ }
106
+ function extractFilePathOperands(tokens) {
107
+ const redirects = extractRedirectTargets(tokens);
108
+ const args = [...redirects];
109
+ for (let index = 1; index < tokens.length; index += 1) {
110
+ const token = tokens[index];
111
+ if (!token || token.startsWith('-')) {
112
+ continue;
113
+ }
114
+ if (redirects.includes(token)) {
115
+ continue;
116
+ }
117
+ args.push(token);
118
+ }
119
+ return args;
120
+ }
121
+ function isRsyncRemoteOperand(token) {
122
+ if (/^rsync:\/\/.+/.test(token)) {
123
+ return true;
124
+ }
125
+ if (/^(?:[^@\s/:]+@)?(?:\[[^\]]+\]|[^:/\s]+)::/.test(token)) {
126
+ return true;
127
+ }
128
+ if (!/^[A-Za-z]:[\\/]/.test(token) &&
129
+ /^(?:[^@\s/:]+@)?(?:\[[^\]]+\]|[^:/\s]+):[^:].*/.test(token)) {
130
+ return true;
131
+ }
132
+ if (/^\/\/.+\//.test(token)) {
133
+ return true;
134
+ }
135
+ return false;
136
+ }
137
+ function classifyRsync(tokens) {
138
+ const args = tokens.slice(1);
139
+ const pathTargets = args.filter((token) => token && !token.startsWith('-'));
140
+ const signals = ['rsync'];
141
+ const destructive = args.some((token) => token.startsWith('--delete') ||
142
+ token === '--del' ||
143
+ token === '--remove-source-files' ||
144
+ token.startsWith('--remove-source-files='));
145
+ if (destructive) {
146
+ return {
147
+ effect: 'local_mutation',
148
+ pathTargets,
149
+ signals: [...signals, 'rsync.destructive'],
150
+ requiresAsk: {
151
+ reason: 'rsync_destructive',
152
+ signals: ['rsync.destructive', 'rsync.delete'],
153
+ },
154
+ };
155
+ }
156
+ const remote = pathTargets.some((token) => isRsyncRemoteOperand(token));
157
+ if (remote) {
158
+ return {
159
+ effect: 'remote_mutation',
160
+ pathTargets,
161
+ signals: [...signals, 'rsync.remote'],
162
+ egressClass: 'ambiguous',
163
+ };
164
+ }
165
+ return {
166
+ effect: 'local_mutation',
167
+ pathTargets,
168
+ signals: [...signals, 'rsync.local'],
169
+ };
170
+ }
171
+ export function isPureReadOnlySemantics(segment, semantics) {
172
+ return (semantics.isReadOnly === true ||
173
+ PURE_READ_ONLY_KEYS.has(segment.head) ||
174
+ PURE_READ_ONLY_KEYS.has(segment.key) ||
175
+ PURE_READ_ONLY_KEYS.has(semantics.normalizedKey ?? ''));
176
+ }
177
+ export function analyzeShellCommandSemantics(tokens, segment, cwd) {
178
+ const head = segment.head;
179
+ const basename = path.basename(tokens[0] ?? head);
180
+ if (basename === 'git') {
181
+ const gitSemantics = classifyGitCommand(tokens, cwd);
182
+ if (gitSemantics) {
183
+ return {
184
+ effect: gitSemantics.effect,
185
+ pathTargets: gitSemantics.pathTargets,
186
+ scopeTargets: gitSemantics.scopeTargets,
187
+ signals: gitSemantics.signals,
188
+ egressClass: gitSemantics.egressClass,
189
+ requiresAsk: gitSemantics.requiresAsk,
190
+ effectiveCwd: gitSemantics.effectiveCwd,
191
+ gitWorkTree: gitSemantics.gitWorkTree,
192
+ normalizedKey: gitSemantics.normalizedKey,
193
+ isReadOnly: gitSemantics.isReadOnly,
194
+ };
195
+ }
196
+ }
197
+ if (head === 'rsync') {
198
+ return classifyRsync(tokens);
199
+ }
200
+ let effect = 'unknown';
201
+ let pathTargets = extractFilePathOperands(tokens);
202
+ pathTargets = filterRoutinePathTargets(head, pathTargets);
203
+ const signals = [];
204
+ if (READ_ONLY_KEYS.has(segment.key) || READ_ONLY_KEYS.has(head)) {
205
+ effect = 'read_only';
206
+ }
207
+ else if (LOCAL_MUTATION_KEYS.has(segment.key) || LOCAL_MUTATION_KEYS.has(head)) {
208
+ effect = 'local_mutation';
209
+ }
210
+ else if (LOCAL_ROUTINE_HEADS.has(head)) {
211
+ effect = 'local_mutation';
212
+ signals.push('routine_local');
213
+ }
214
+ if (extractRedirectTargets(tokens).length > 0 && effect === 'read_only') {
215
+ effect = 'local_mutation';
216
+ }
217
+ return {
218
+ effect,
219
+ pathTargets,
220
+ signals,
221
+ normalizedKey: segment.key,
222
+ isReadOnly: effect === 'read_only',
223
+ };
224
+ }
225
+ export { LOCAL_MUTATION_KEYS, PURE_READ_ONLY_KEYS, READ_ONLY_KEYS };
@@ -1,3 +1,6 @@
1
+ import type { PolicyDecision } from '../capability/policy-types.js';
2
+ import type { CapabilityRequestV1 } from '../capability/request.js';
3
+ import type { BelayConfigV4 } from '../config.js';
1
4
  export type VerdictPermission = 'allow' | 'ask';
2
5
  export type VerdictLocation = 'repo_local' | 'repo_outside' | 'external' | 'mixed' | 'unknown';
3
6
  export type VerdictOpacity = 'transparent' | 'recursive' | 'opaque' | 'unparseable';
@@ -14,6 +17,8 @@ export interface VerdictResult {
14
17
  fingerprint: string;
15
18
  signals: string[];
16
19
  judgeTrace?: JudgeTrace;
20
+ capabilityRequests?: CapabilityRequestV1[];
21
+ authorizationDecision?: PolicyDecision;
17
22
  }
18
23
  export interface Tier1Verdict {
19
24
  /** true = undoable via git/fs snapshot or trivial local revert (ADR-002 local-recoverable). */
@@ -33,6 +38,7 @@ export interface Tier1EvaluateInput {
33
38
  };
34
39
  innerCode?: string;
35
40
  }
41
+ /** @deprecated Sync gate path no longer invokes Tier1 judge. Retained for shadow tooling. */
36
42
  export interface Tier1Judge {
37
43
  evaluate(input: Tier1EvaluateInput): Promise<Tier1Verdict>;
38
44
  }
@@ -41,6 +47,7 @@ export interface JudgeTrace {
41
47
  modelRequested: string;
42
48
  modelResolved: string;
43
49
  latencyMs: number;
50
+ transport?: 'http' | 'ollama-http' | 'codex-cli' | 'cursor-cli' | 'claude-cli' | 'codex-cli-session' | 'cursor-cli-session' | 'claude-cli-session' | 'cursor-acp' | 'unavailable';
44
51
  outboundRedacted?: boolean;
45
52
  fallbackReason?: string;
46
53
  judgeSessionUsed?: boolean;
@@ -60,17 +67,20 @@ export type VerdictMode = 'enforce' | 'audit';
60
67
  export interface VerdictContext {
61
68
  cwd: string;
62
69
  repoRoot: string;
70
+ config: BelayConfigV4;
63
71
  trustedCwd: boolean;
64
72
  trustedWorkspaceRoots?: string[];
65
73
  sensitivePaths: string[];
66
74
  protectedArtifactRoots?: string[];
67
75
  customAllowCommands?: string[];
68
76
  customExternalCommands?: string[];
69
- judge: Tier1Judge;
70
77
  mode: VerdictMode;
71
78
  unknownLocalEffect: 'allow_flagged' | 'deny';
72
79
  unparseableShell: 'allow_flagged' | 'deny';
73
80
  maxRecursionDepth?: number;
81
+ grants?: import('../capability/grant.js').CapabilityGrantV1[];
82
+ attestation?: import('../capability/attestation.js').BoundaryAttestation | null;
83
+ egressProxyActive?: boolean;
74
84
  }
75
85
  export interface InternalSegmentVerdict {
76
86
  permission: VerdictPermission;
@@ -81,4 +91,6 @@ export interface InternalSegmentVerdict {
81
91
  reason: string;
82
92
  signals: string[];
83
93
  judgeTrace?: JudgeTrace;
94
+ capabilityRequests?: CapabilityRequestV1[];
95
+ authorizationDecision?: PolicyDecision;
84
96
  }