@scopewatch/diff-engine 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compute.d.ts +8 -0
- package/dist/compute.d.ts.map +1 -0
- package/dist/compute.js +445 -0
- package/dist/compute.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/render.d.ts +14 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +266 -0
- package/dist/render.js.map +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ServerManifest } from '@scopewatch/manifest';
|
|
2
|
+
import type { CapabilityDiff } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compute a capability diff between two manifest versions.
|
|
5
|
+
* This is the core P0 algorithm.
|
|
6
|
+
*/
|
|
7
|
+
export declare function computeDiff(from: ServerManifest, to: ServerManifest): CapabilityDiff;
|
|
8
|
+
//# sourceMappingURL=compute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../src/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA4C,MAAM,sBAAsB,CAAC;AACrG,OAAO,KAAK,EAAE,cAAc,EAA2D,MAAM,YAAY,CAAC;AAE1G;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc,GAAG,cAAc,CAqCpF"}
|
package/dist/compute.js
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute a capability diff between two manifest versions.
|
|
3
|
+
* This is the core P0 algorithm.
|
|
4
|
+
*/
|
|
5
|
+
export function computeDiff(from, to) {
|
|
6
|
+
// Index capabilities by tool and (verb, resource) pair
|
|
7
|
+
const fromByTool = indexCapabilitiesByTool(from.capabilities);
|
|
8
|
+
const toByTool = indexCapabilitiesByTool(to.capabilities);
|
|
9
|
+
// Compute capability changes
|
|
10
|
+
const capabilityChanges = computeCapabilityChanges(fromByTool, toByTool);
|
|
11
|
+
// Compute credential changes
|
|
12
|
+
const secretChanges = computeSecretChanges(from.secrets, to.secrets);
|
|
13
|
+
// Determine risk level
|
|
14
|
+
// Tier 1: categorical acquisition in either added (new tool with destructive) or modified (existing tool gains destructive)
|
|
15
|
+
const newly_destructive = capabilityChanges.added.some(c => c.severity === 'categorical_acquisition') ||
|
|
16
|
+
capabilityChanges.modified.some(c => c.severity === 'categorical_acquisition');
|
|
17
|
+
const riskLevel = determineRiskLevel(capabilityChanges, secretChanges, newly_destructive);
|
|
18
|
+
const hasChanges = capabilityChanges.added.length > 0 ||
|
|
19
|
+
capabilityChanges.removed.length > 0 ||
|
|
20
|
+
capabilityChanges.modified.length > 0 ||
|
|
21
|
+
secretChanges.new.length > 0 ||
|
|
22
|
+
secretChanges.reused.length > 0 ||
|
|
23
|
+
secretChanges.removed.length > 0 ||
|
|
24
|
+
secretChanges.required_changed.length > 0;
|
|
25
|
+
return {
|
|
26
|
+
from_version: from.version,
|
|
27
|
+
to_version: to.version,
|
|
28
|
+
capabilities: capabilityChanges,
|
|
29
|
+
secrets: secretChanges,
|
|
30
|
+
newly_destructive,
|
|
31
|
+
riskLevel,
|
|
32
|
+
hasChanges,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Index capabilities by tool_id.
|
|
37
|
+
*/
|
|
38
|
+
function indexCapabilitiesByTool(capabilities) {
|
|
39
|
+
const index = new Map();
|
|
40
|
+
for (const cap of capabilities) {
|
|
41
|
+
if (!index.has(cap.tool_id)) {
|
|
42
|
+
index.set(cap.tool_id, new Map());
|
|
43
|
+
}
|
|
44
|
+
const key = `${cap.verb}:${cap.resource ?? ''}`;
|
|
45
|
+
index.get(cap.tool_id).set(key, cap);
|
|
46
|
+
}
|
|
47
|
+
return index;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Compute all capability changes between two versions.
|
|
51
|
+
*
|
|
52
|
+
* Strategy: index by (tool_id, verb) to properly detect scope changes.
|
|
53
|
+
* A scope change is when the same (tool_id, verb) pair has different resources.
|
|
54
|
+
*/
|
|
55
|
+
function computeCapabilityChanges(fromByTool, toByTool) {
|
|
56
|
+
const added = [];
|
|
57
|
+
const removed = [];
|
|
58
|
+
const modified = [];
|
|
59
|
+
const allToolIds = new Set([...fromByTool.keys(), ...toByTool.keys()]);
|
|
60
|
+
for (const toolId of allToolIds) {
|
|
61
|
+
const fromCaps = fromByTool.get(toolId);
|
|
62
|
+
const toCaps = toByTool.get(toolId);
|
|
63
|
+
// Tool entirely removed
|
|
64
|
+
if (!toCaps && fromCaps) {
|
|
65
|
+
// Tool removal is marked as scope_narrowing, but we need to detect "tool_removed" case
|
|
66
|
+
for (const cap of fromCaps.values()) {
|
|
67
|
+
removed.push({
|
|
68
|
+
tool_id: toolId,
|
|
69
|
+
verb: cap.verb,
|
|
70
|
+
resource: cap.resource,
|
|
71
|
+
changeType: 'removed',
|
|
72
|
+
severity: 'scope_narrowing', // tool removal is a narrowing
|
|
73
|
+
provenance: cap.provenance,
|
|
74
|
+
previousResource: undefined,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// Tool entirely added
|
|
80
|
+
if (!fromCaps && toCaps) {
|
|
81
|
+
for (const cap of toCaps.values()) {
|
|
82
|
+
// For a completely new tool, classify each capability
|
|
83
|
+
// If tool is new and has ANY destructive verb → Tier 1 categorical_acquisition
|
|
84
|
+
// Otherwise, non-destructive adds are cosmetic
|
|
85
|
+
const hasDestructive = Array.from(toCaps.values()).some(c => isDestructive(c.verb));
|
|
86
|
+
const severity = hasDestructive && isDestructive(cap.verb) ? 'categorical_acquisition' : 'cosmetic';
|
|
87
|
+
added.push({
|
|
88
|
+
tool_id: toolId,
|
|
89
|
+
verb: cap.verb,
|
|
90
|
+
resource: cap.resource,
|
|
91
|
+
changeType: 'added',
|
|
92
|
+
severity,
|
|
93
|
+
provenance: cap.provenance,
|
|
94
|
+
previousResource: undefined,
|
|
95
|
+
isNewTool: true, // Mark that this tool is brand new
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
// Tool exists in both; compare capabilities at (tool_id, verb) level
|
|
101
|
+
if (fromCaps && toCaps) {
|
|
102
|
+
// Group by verb to detect scope changes
|
|
103
|
+
const allVerbs = new Set();
|
|
104
|
+
for (const cap of fromCaps.values())
|
|
105
|
+
allVerbs.add(cap.verb);
|
|
106
|
+
for (const cap of toCaps.values())
|
|
107
|
+
allVerbs.add(cap.verb);
|
|
108
|
+
for (const verb of allVerbs) {
|
|
109
|
+
// Collect all resources for this (tool_id, verb) pair
|
|
110
|
+
const fromResources = Array.from(fromCaps.values())
|
|
111
|
+
.filter(c => c.verb === verb)
|
|
112
|
+
.map(c => c.resource);
|
|
113
|
+
const toResources = Array.from(toCaps.values())
|
|
114
|
+
.filter(c => c.verb === verb)
|
|
115
|
+
.map(c => c.resource);
|
|
116
|
+
// If either from or to is empty, it's an addition or removal
|
|
117
|
+
if (fromResources.length === 0 && toResources.length > 0) {
|
|
118
|
+
// New verb on existing tool
|
|
119
|
+
for (const toResource of toResources) {
|
|
120
|
+
const toCap = Array.from(toCaps.values()).find(c => c.verb === verb && c.resource === toResource);
|
|
121
|
+
const severity = classifyAddedCapability(toolId, toCap, fromCaps);
|
|
122
|
+
added.push({
|
|
123
|
+
tool_id: toolId,
|
|
124
|
+
verb,
|
|
125
|
+
resource: toResource,
|
|
126
|
+
changeType: 'added',
|
|
127
|
+
severity,
|
|
128
|
+
provenance: toCap.provenance,
|
|
129
|
+
previousResource: undefined,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else if (fromResources.length > 0 && toResources.length === 0) {
|
|
134
|
+
// Verb entirely removed
|
|
135
|
+
for (const fromResource of fromResources) {
|
|
136
|
+
const fromCap = Array.from(fromCaps.values()).find(c => c.verb === verb && c.resource === fromResource);
|
|
137
|
+
removed.push({
|
|
138
|
+
tool_id: toolId,
|
|
139
|
+
verb,
|
|
140
|
+
resource: fromResource,
|
|
141
|
+
changeType: 'removed',
|
|
142
|
+
severity: 'scope_narrowing',
|
|
143
|
+
provenance: fromCap.provenance,
|
|
144
|
+
previousResource: undefined,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (fromResources.length === 1 && toResources.length === 1) {
|
|
149
|
+
// Single resource per verb in both versions → check for scope change
|
|
150
|
+
const fromResource = fromResources[0];
|
|
151
|
+
const toResource = toResources[0];
|
|
152
|
+
if (fromResource !== toResource) {
|
|
153
|
+
const toCap = Array.from(toCaps.values()).find(c => c.verb === verb && c.resource === toResource);
|
|
154
|
+
const severity = classifyScopeChange(fromResource, toResource, verb);
|
|
155
|
+
if (severity !== 'cosmetic') {
|
|
156
|
+
modified.push({
|
|
157
|
+
tool_id: toolId,
|
|
158
|
+
verb,
|
|
159
|
+
resource: toResource,
|
|
160
|
+
changeType: 'modified',
|
|
161
|
+
severity,
|
|
162
|
+
provenance: toCap.provenance,
|
|
163
|
+
previousResource: fromResource,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// Multiple resources before/after for the same (tool_id, verb)
|
|
170
|
+
// Detect additions/removals/widening independently per resource
|
|
171
|
+
const fromSet = new Set(fromResources);
|
|
172
|
+
const toSet = new Set(toResources);
|
|
173
|
+
for (const fromRes of fromResources) {
|
|
174
|
+
if (!toSet.has(fromRes)) {
|
|
175
|
+
// This resource was removed. Check if it's subsumed by a wider resource in "to"
|
|
176
|
+
const isSubsumedByWider = toResources.some(toRes => isScopeWider(fromRes, toRes));
|
|
177
|
+
const fromCap = Array.from(fromCaps.values()).find(c => c.verb === verb && c.resource === fromRes);
|
|
178
|
+
if (isSubsumedByWider) {
|
|
179
|
+
// The resource was subsumed by a wider one → this is part of a widening change
|
|
180
|
+
// Mark it as a modification on the wider resource instead
|
|
181
|
+
// (The matching "added" wider resource will be classified as scope_expansion)
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Standalone removal
|
|
185
|
+
removed.push({
|
|
186
|
+
tool_id: toolId,
|
|
187
|
+
verb,
|
|
188
|
+
resource: fromRes,
|
|
189
|
+
changeType: 'removed',
|
|
190
|
+
severity: 'scope_narrowing',
|
|
191
|
+
provenance: fromCap.provenance,
|
|
192
|
+
previousResource: undefined,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const toRes of toResources) {
|
|
198
|
+
if (!fromSet.has(toRes)) {
|
|
199
|
+
// This resource was added. Check if it's a widening of an existing resource
|
|
200
|
+
const matchingNarrower = fromResources.find(fromRes => isScopeWider(fromRes, toRes));
|
|
201
|
+
const toCap = Array.from(toCaps.values()).find(c => c.verb === verb && c.resource === toRes);
|
|
202
|
+
if (matchingNarrower) {
|
|
203
|
+
// This is a widening of an existing resource
|
|
204
|
+
modified.push({
|
|
205
|
+
tool_id: toolId,
|
|
206
|
+
verb,
|
|
207
|
+
resource: toRes,
|
|
208
|
+
changeType: 'modified',
|
|
209
|
+
severity: 'scope_expansion',
|
|
210
|
+
provenance: toCap.provenance,
|
|
211
|
+
previousResource: matchingNarrower,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// Standalone addition (new resource, different from any existing one)
|
|
216
|
+
added.push({
|
|
217
|
+
tool_id: toolId,
|
|
218
|
+
verb,
|
|
219
|
+
resource: toRes,
|
|
220
|
+
changeType: 'added',
|
|
221
|
+
severity: 'cosmetic', // Non-destructive additional resource
|
|
222
|
+
provenance: toCap.provenance,
|
|
223
|
+
previousResource: undefined,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return { added, removed, modified };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Classify the severity of a newly added capability to an existing tool.
|
|
236
|
+
* Tier 1: tool goes from having zero destructive verbs to having any destructive verb.
|
|
237
|
+
*/
|
|
238
|
+
function classifyAddedCapability(toolId, toCap, fromCaps) {
|
|
239
|
+
if (!isDestructive(toCap.verb)) {
|
|
240
|
+
return 'cosmetic'; // Non-destructive additions are cosmetic
|
|
241
|
+
}
|
|
242
|
+
// Check if tool previously had ANY destructive verb
|
|
243
|
+
// If it didn't, then adding one is Tier 1 (categorical_acquisition)
|
|
244
|
+
// If it did, then adding another one is cosmetic (not Tier 1)
|
|
245
|
+
for (const cap of fromCaps.values()) {
|
|
246
|
+
if (isDestructive(cap.verb)) {
|
|
247
|
+
return 'cosmetic'; // Tool already had destructive access, so no new category acquired
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Tool had NO destructive verbs before, now adding one → Tier 1
|
|
251
|
+
return 'categorical_acquisition';
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Classify the severity of a scope change.
|
|
255
|
+
*/
|
|
256
|
+
function classifyScopeChange(fromResource, toResource, verb) {
|
|
257
|
+
if (fromResource === toResource) {
|
|
258
|
+
return 'cosmetic'; // No change
|
|
259
|
+
}
|
|
260
|
+
// Simple heuristic: if "to" is wider than "from", it's an expansion
|
|
261
|
+
// E.g., "repo:owner/name" → "repo:*" is an expansion
|
|
262
|
+
if (isScopeWider(fromResource, toResource)) {
|
|
263
|
+
return 'scope_expansion';
|
|
264
|
+
}
|
|
265
|
+
if (isScopeNarrower(fromResource, toResource)) {
|
|
266
|
+
return 'scope_narrowing';
|
|
267
|
+
}
|
|
268
|
+
return 'cosmetic'; // Unknown relationship, treat as cosmetic
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Check if toScope is wider than fromScope per the resource grammar.
|
|
272
|
+
* Resource format: domain:path with /–delimited segments and trailing * for wildcards.
|
|
273
|
+
*
|
|
274
|
+
* A pattern matches another if:
|
|
275
|
+
* - Same domain
|
|
276
|
+
* - toPath contains everything fromPath matches, plus at least one thing it doesn't
|
|
277
|
+
*
|
|
278
|
+
* Examples of widening:
|
|
279
|
+
* - repo:owner/name → repo:* (specific → all)
|
|
280
|
+
* - repo:owner/name → repo:owner/* (specific → directory level)
|
|
281
|
+
* - repo:owner/* → repo:* (directory → all)
|
|
282
|
+
*/
|
|
283
|
+
function isScopeWider(fromScope, toScope) {
|
|
284
|
+
if (!fromScope || !toScope)
|
|
285
|
+
return false;
|
|
286
|
+
if (fromScope === toScope)
|
|
287
|
+
return false; // No change
|
|
288
|
+
const fromParts = fromScope.split(':');
|
|
289
|
+
const toParts = toScope.split(':');
|
|
290
|
+
if (fromParts.length !== 2 || toParts.length !== 2)
|
|
291
|
+
return false;
|
|
292
|
+
if (fromParts[0] !== toParts[0])
|
|
293
|
+
return false; // Different resource domains
|
|
294
|
+
const fromDomain = fromParts[0];
|
|
295
|
+
const fromPath = fromParts[1];
|
|
296
|
+
const toPath = toParts[1];
|
|
297
|
+
// Both are wildcards → no change
|
|
298
|
+
if (toPath === '*' && fromPath === '*')
|
|
299
|
+
return false;
|
|
300
|
+
// To is global wildcard → always wider (unless from already is)
|
|
301
|
+
if (toPath === '*' && fromPath !== '*')
|
|
302
|
+
return true;
|
|
303
|
+
// To is directory wildcard, from is not → potentially wider
|
|
304
|
+
// E.g., repo:owner/* vs repo:owner/name
|
|
305
|
+
if (toPath.endsWith('/*') && !fromPath.endsWith('/*') && !fromPath.endsWith('*')) {
|
|
306
|
+
const toDir = toPath.slice(0, -2); // Remove trailing /*
|
|
307
|
+
return fromPath.startsWith(toDir + '/');
|
|
308
|
+
}
|
|
309
|
+
// Both have wildcards at same level → not wider
|
|
310
|
+
// E.g., repo:owner/* vs repo:owner/* (equal)
|
|
311
|
+
if (toPath.endsWith('/*') && fromPath.endsWith('/*')) {
|
|
312
|
+
return toPath.length > fromPath.length && fromPath.startsWith(toPath.slice(0, -2));
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Check if toScope is narrower than fromScope.
|
|
318
|
+
*/
|
|
319
|
+
function isScopeNarrower(fromScope, toScope) {
|
|
320
|
+
return isScopeWider(toScope, fromScope); // Symmetry
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Is this verb destructive? (write, delete, execute)
|
|
324
|
+
*/
|
|
325
|
+
function isDestructive(verb) {
|
|
326
|
+
return verb === 'write' || verb === 'delete' || verb === 'execute';
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Compute credential changes between two versions.
|
|
330
|
+
*/
|
|
331
|
+
function computeSecretChanges(fromSecrets, toSecrets) {
|
|
332
|
+
const newSecrets = [];
|
|
333
|
+
const reusedSecrets = [];
|
|
334
|
+
const removedSecrets = [];
|
|
335
|
+
const requiredChanged = [];
|
|
336
|
+
const fromById = new Map(fromSecrets.map(s => [s.id, s]));
|
|
337
|
+
const toById = new Map(toSecrets.map(s => [s.id, s]));
|
|
338
|
+
// Find new and reused secrets
|
|
339
|
+
for (const toSecret of toSecrets) {
|
|
340
|
+
const fromSecret = fromById.get(toSecret.id);
|
|
341
|
+
if (!fromSecret) {
|
|
342
|
+
// Genuinely new secret
|
|
343
|
+
newSecrets.push({
|
|
344
|
+
secret_id: toSecret.id,
|
|
345
|
+
changeType: 'new',
|
|
346
|
+
description: toSecret.description,
|
|
347
|
+
used_by_new_tools: undefined,
|
|
348
|
+
requiredBefore: undefined,
|
|
349
|
+
requiredAfter: undefined,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
// Existing secret
|
|
354
|
+
if (toSecret.used_by.length > fromSecret.used_by.length) {
|
|
355
|
+
// New tools now using this secret
|
|
356
|
+
const newToolIds = toSecret.used_by.filter(t => !fromSecret.used_by.includes(t));
|
|
357
|
+
reusedSecrets.push({
|
|
358
|
+
secret_id: toSecret.id,
|
|
359
|
+
changeType: 'reused',
|
|
360
|
+
description: toSecret.description,
|
|
361
|
+
used_by_new_tools: newToolIds,
|
|
362
|
+
requiredBefore: undefined,
|
|
363
|
+
requiredAfter: undefined,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
// Check if required status changed
|
|
367
|
+
if (fromSecret.required !== toSecret.required) {
|
|
368
|
+
requiredChanged.push({
|
|
369
|
+
secret_id: toSecret.id,
|
|
370
|
+
changeType: 'required_changed',
|
|
371
|
+
description: toSecret.description,
|
|
372
|
+
used_by_new_tools: undefined,
|
|
373
|
+
requiredBefore: fromSecret.required,
|
|
374
|
+
requiredAfter: toSecret.required,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Find removed secrets
|
|
380
|
+
for (const fromSecret of fromSecrets) {
|
|
381
|
+
if (!toById.has(fromSecret.id)) {
|
|
382
|
+
removedSecrets.push({
|
|
383
|
+
secret_id: fromSecret.id,
|
|
384
|
+
changeType: 'removed',
|
|
385
|
+
description: fromSecret.description,
|
|
386
|
+
used_by_new_tools: undefined,
|
|
387
|
+
requiredBefore: undefined,
|
|
388
|
+
requiredAfter: undefined,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
new: newSecrets,
|
|
394
|
+
reused: reusedSecrets,
|
|
395
|
+
removed: removedSecrets,
|
|
396
|
+
required_changed: requiredChanged,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Determine overall risk level for the update.
|
|
401
|
+
* Follows the locked mapping exactly:
|
|
402
|
+
* - high: any categorical_acquisition, OR any new required secret with no reuse
|
|
403
|
+
* - medium: any scope_expansion, OR new required secret reusing existing credential, OR required_changed
|
|
404
|
+
* - low: only removals/narrowing, OR reused secret with no other changes
|
|
405
|
+
* - none: cosmetic-only or no changes
|
|
406
|
+
*/
|
|
407
|
+
function determineRiskLevel(capabilityChanges, secretChanges, newly_destructive) {
|
|
408
|
+
// No changes at all
|
|
409
|
+
if (capabilityChanges.added.length === 0 &&
|
|
410
|
+
capabilityChanges.removed.length === 0 &&
|
|
411
|
+
capabilityChanges.modified.length === 0 &&
|
|
412
|
+
secretChanges.new.length === 0 &&
|
|
413
|
+
secretChanges.reused.length === 0 &&
|
|
414
|
+
secretChanges.removed.length === 0 &&
|
|
415
|
+
secretChanges.required_changed.length === 0) {
|
|
416
|
+
return 'none';
|
|
417
|
+
}
|
|
418
|
+
// HIGH RISK: Tier 1 (newly destructive capability)
|
|
419
|
+
if (newly_destructive) {
|
|
420
|
+
return 'high';
|
|
421
|
+
}
|
|
422
|
+
// HIGH RISK: Any new required secret with no reuse (locked rule, independent of capability tier)
|
|
423
|
+
if (secretChanges.new.length > 0) {
|
|
424
|
+
return 'high';
|
|
425
|
+
}
|
|
426
|
+
// MEDIUM RISK: Tier 2 changes (scope expansion)
|
|
427
|
+
if (capabilityChanges.modified.some(c => c.severity === 'scope_expansion')) {
|
|
428
|
+
return 'medium';
|
|
429
|
+
}
|
|
430
|
+
// MEDIUM RISK: New non-destructive capabilities
|
|
431
|
+
if (capabilityChanges.added.some(c => c.severity !== 'categorical_acquisition')) {
|
|
432
|
+
return 'medium';
|
|
433
|
+
}
|
|
434
|
+
// MEDIUM RISK: Reused secret (existing secret used by new tools)
|
|
435
|
+
if (secretChanges.reused.length > 0) {
|
|
436
|
+
return 'medium';
|
|
437
|
+
}
|
|
438
|
+
// MEDIUM RISK: Secret requirement changed (graceful degradation disappears)
|
|
439
|
+
if (secretChanges.required_changed.length > 0) {
|
|
440
|
+
return 'medium';
|
|
441
|
+
}
|
|
442
|
+
// LOW RISK: Only removals and scope narrowing
|
|
443
|
+
return 'low';
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=compute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compute.js","sourceRoot":"","sources":["../src/compute.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CapabilityDiff } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render a capability diff to human-readable plain text.
|
|
4
|
+
* Critical: output must be a one-sentence summary a human can understand without the manifests.
|
|
5
|
+
*
|
|
6
|
+
* Rendering order: severity descending (Tier 1 first), then grouped by tool.
|
|
7
|
+
*/
|
|
8
|
+
export declare function renderDiff(diff: CapabilityDiff): string;
|
|
9
|
+
/**
|
|
10
|
+
* Extract a one-sentence summary from the diff for testing.
|
|
11
|
+
* This is what the test assertions will check against.
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractSummary(diff: CapabilityDiff): string;
|
|
14
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAoB,MAAM,YAAY,CAAC;AAEnE;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAuMvD;AAoBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAgF3D"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a capability diff to human-readable plain text.
|
|
3
|
+
* Critical: output must be a one-sentence summary a human can understand without the manifests.
|
|
4
|
+
*
|
|
5
|
+
* Rendering order: severity descending (Tier 1 first), then grouped by tool.
|
|
6
|
+
*/
|
|
7
|
+
export function renderDiff(diff) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
// Header: version info
|
|
10
|
+
lines.push(`→ Update: ${diff.from_version} → ${diff.to_version}`);
|
|
11
|
+
lines.push('');
|
|
12
|
+
// No changes: silent success must explicitly state this
|
|
13
|
+
if (!diff.hasChanges) {
|
|
14
|
+
lines.push('✓ No capability changes detected.');
|
|
15
|
+
return lines.join('\n');
|
|
16
|
+
}
|
|
17
|
+
// Render capabilities in severity order
|
|
18
|
+
if (diff.newly_destructive) {
|
|
19
|
+
lines.push('⚠️ HIGH RISK: Newly destructive capability detected');
|
|
20
|
+
lines.push('');
|
|
21
|
+
// Tier 1: Categorical acquisition
|
|
22
|
+
const tier1 = [
|
|
23
|
+
...diff.capabilities.added.filter(c => c.severity === 'categorical_acquisition'),
|
|
24
|
+
...diff.capabilities.modified.filter(c => c.severity === 'categorical_acquisition'),
|
|
25
|
+
];
|
|
26
|
+
const tier1ByTool = groupByTool(tier1);
|
|
27
|
+
for (const [toolId, changes] of tier1ByTool) {
|
|
28
|
+
// Check if this is a new tool (all capabilities added to a tool that didn't exist before)
|
|
29
|
+
const isNewTool = changes.every(c => c.isNewTool);
|
|
30
|
+
if (isNewTool && changes.length === 1) {
|
|
31
|
+
// Brand-new tool with single destructive capability
|
|
32
|
+
const change = changes[0];
|
|
33
|
+
const confidence = change.provenance === 'inferred' ? 'appears to be added' : 'added';
|
|
34
|
+
lines.push(` • New tool ${confidence}: ${toolId} with ${change.verb} access to ${change.resource ?? 'default'}`);
|
|
35
|
+
}
|
|
36
|
+
else if (isNewTool && changes.length > 1) {
|
|
37
|
+
// Brand-new tool with multiple capabilities
|
|
38
|
+
const verbs = changes.map(c => c.verb).join(', ');
|
|
39
|
+
const isInferred = changes.some(c => c.provenance === 'inferred');
|
|
40
|
+
const confidence = isInferred ? 'appears to be added' : 'added';
|
|
41
|
+
lines.push(` • New tool ${confidence}: ${toolId} with ${verbs} access`);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Existing tool gaining destructive capability
|
|
45
|
+
for (const change of changes) {
|
|
46
|
+
const confidence = change.provenance === 'inferred' ? 'appears to have' : 'now has';
|
|
47
|
+
lines.push(` • ${toolId}: ${confidence} ${change.verb} access to ${change.resource ?? 'default'}`);
|
|
48
|
+
if (change.previousResource) {
|
|
49
|
+
lines.push(` (previously read-only or scoped to ${change.previousResource})`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
lines.push('');
|
|
55
|
+
}
|
|
56
|
+
// Tier 2: Scope expansion
|
|
57
|
+
const tier2 = diff.capabilities.modified.filter(c => c.severity === 'scope_expansion');
|
|
58
|
+
if (tier2.length > 0) {
|
|
59
|
+
lines.push('🔄 SCOPE EXPANDED:');
|
|
60
|
+
const tier2ByTool = groupByTool(tier2);
|
|
61
|
+
for (const [toolId, changes] of tier2ByTool) {
|
|
62
|
+
for (const change of changes) {
|
|
63
|
+
lines.push(` • ${toolId}: now has ${change.verb} access to ${change.resource ?? 'default'} ` +
|
|
64
|
+
`(previously ${change.previousResource ?? 'default'})`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
lines.push('');
|
|
68
|
+
}
|
|
69
|
+
// Tier 3: Scope narrowing
|
|
70
|
+
const tier3 = [
|
|
71
|
+
...diff.capabilities.removed.filter(c => c.severity === 'scope_narrowing'),
|
|
72
|
+
...diff.capabilities.modified.filter(c => c.severity === 'scope_narrowing'),
|
|
73
|
+
];
|
|
74
|
+
// Detect complete tool removals vs. capability removals
|
|
75
|
+
const allRemovals = diff.capabilities.removed.filter(c => c.severity === 'scope_narrowing');
|
|
76
|
+
const removedToolIds = new Set(allRemovals.map(c => c.tool_id));
|
|
77
|
+
const completelyRemovedTools = new Set();
|
|
78
|
+
// A tool is completely removed if all its removals are in the removed list
|
|
79
|
+
// (not added back in any other way)
|
|
80
|
+
for (const toolId of removedToolIds) {
|
|
81
|
+
const hasAnyAddBack = diff.capabilities.added.some(c => c.tool_id === toolId);
|
|
82
|
+
if (!hasAnyAddBack) {
|
|
83
|
+
completelyRemovedTools.add(toolId);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (tier3.length > 0) {
|
|
87
|
+
lines.push('✓ SCOPE NARROWED (safer):');
|
|
88
|
+
const tier3ByTool = groupByTool(tier3);
|
|
89
|
+
for (const [toolId, changes] of tier3ByTool) {
|
|
90
|
+
if (completelyRemovedTools.has(toolId)) {
|
|
91
|
+
// Tool is entirely removed
|
|
92
|
+
lines.push(` • ${toolId} tool removed`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Partial removal or scope narrowing
|
|
96
|
+
for (const change of changes) {
|
|
97
|
+
if (change.changeType === 'removed') {
|
|
98
|
+
lines.push(` • ${toolId}: removed ${change.verb} access`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
lines.push(` • ${toolId}: ${change.verb} scope narrowed to ${change.resource ?? 'default'}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
lines.push('');
|
|
107
|
+
}
|
|
108
|
+
// Tier 4: Cosmetic (only if there are Tier 4 changes and no higher tiers)
|
|
109
|
+
const tier4 = diff.capabilities.modified.filter(c => c.severity === 'cosmetic');
|
|
110
|
+
if (tier4.length > 0 &&
|
|
111
|
+
!diff.newly_destructive &&
|
|
112
|
+
tier2.length === 0 &&
|
|
113
|
+
tier3.length === 0) {
|
|
114
|
+
lines.push('ℹ️ DESCRIPTION UPDATED:');
|
|
115
|
+
for (const change of tier4) {
|
|
116
|
+
lines.push(` • ${change.tool_id}: description updated`);
|
|
117
|
+
}
|
|
118
|
+
lines.push('');
|
|
119
|
+
}
|
|
120
|
+
// New tools (not already covered by Tier 1)
|
|
121
|
+
const tier1ToolIds = new Set([
|
|
122
|
+
...diff.capabilities.added.filter(c => c.severity === 'categorical_acquisition'),
|
|
123
|
+
...diff.capabilities.modified.filter(c => c.severity === 'categorical_acquisition'),
|
|
124
|
+
].map(c => c.tool_id));
|
|
125
|
+
const newToolsNotTier1 = diff.capabilities.added.filter(c => c.severity !== 'categorical_acquisition' && !tier1ToolIds.has(c.tool_id));
|
|
126
|
+
if (newToolsNotTier1.length > 0) {
|
|
127
|
+
lines.push('🆕 NEW CAPABILITIES:');
|
|
128
|
+
const toolIds = new Set(newToolsNotTier1.map(c => c.tool_id));
|
|
129
|
+
for (const toolId of toolIds) {
|
|
130
|
+
const caps = newToolsNotTier1.filter(c => c.tool_id === toolId);
|
|
131
|
+
// For single capability, use full phrasing; for multiple, use bracket format
|
|
132
|
+
if (caps.length === 1) {
|
|
133
|
+
const cap = caps[0];
|
|
134
|
+
const isInferred = cap.provenance === 'inferred';
|
|
135
|
+
const confidence = isInferred ? 'appears to add' : 'adds';
|
|
136
|
+
lines.push(` • ${toolId} ${confidence} ${cap.verb} access to ${cap.resource ?? 'default'}`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const isInferred = caps.some(c => c.provenance === 'inferred');
|
|
140
|
+
const confidence = isInferred ? 'appears to add' : 'adds';
|
|
141
|
+
const verbs = caps.map(c => c.verb).join(', ');
|
|
142
|
+
lines.push(` • ${toolId} ${confidence}: [${verbs}]`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
lines.push('');
|
|
146
|
+
}
|
|
147
|
+
// Render credentials
|
|
148
|
+
if (diff.secrets.new.length > 0 ||
|
|
149
|
+
diff.secrets.reused.length > 0 ||
|
|
150
|
+
diff.secrets.removed.length > 0 ||
|
|
151
|
+
diff.secrets.required_changed.length > 0) {
|
|
152
|
+
lines.push('🔑 CREDENTIALS:');
|
|
153
|
+
// New secrets
|
|
154
|
+
for (const secret of diff.secrets.new) {
|
|
155
|
+
lines.push(` • requires new credential: ${secret.secret_id} (${secret.description})`);
|
|
156
|
+
}
|
|
157
|
+
// Reused secrets
|
|
158
|
+
for (const secret of diff.secrets.reused) {
|
|
159
|
+
const toolList = (secret.used_by_new_tools ?? []).join(', ');
|
|
160
|
+
lines.push(` • REUSED: ${secret.secret_id} (now used by: ${toolList})`);
|
|
161
|
+
}
|
|
162
|
+
// Removed secrets
|
|
163
|
+
for (const secret of diff.secrets.removed) {
|
|
164
|
+
lines.push(` • REMOVED: ${secret.secret_id} (no longer needed)`);
|
|
165
|
+
}
|
|
166
|
+
// Required status changed
|
|
167
|
+
for (const secret of diff.secrets.required_changed) {
|
|
168
|
+
const status = secret.requiredAfter
|
|
169
|
+
? 'now required (previously optional)'
|
|
170
|
+
: 'now optional (previously required)';
|
|
171
|
+
lines.push(` • REQUIREMENT CHANGED: ${secret.secret_id} ${status}`);
|
|
172
|
+
}
|
|
173
|
+
lines.push('');
|
|
174
|
+
}
|
|
175
|
+
// Trailing note
|
|
176
|
+
lines.push('Review carefully. Approve? [y/N]:');
|
|
177
|
+
return lines.join('\n');
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Group capability changes by tool_id.
|
|
181
|
+
*/
|
|
182
|
+
function groupByTool(changes) {
|
|
183
|
+
const groups = new Map();
|
|
184
|
+
for (const change of changes) {
|
|
185
|
+
if (!groups.has(change.tool_id)) {
|
|
186
|
+
groups.set(change.tool_id, []);
|
|
187
|
+
}
|
|
188
|
+
groups.get(change.tool_id).push(change);
|
|
189
|
+
}
|
|
190
|
+
return groups;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Extract a one-sentence summary from the diff for testing.
|
|
194
|
+
* This is what the test assertions will check against.
|
|
195
|
+
*/
|
|
196
|
+
export function extractSummary(diff) {
|
|
197
|
+
if (!diff.hasChanges) {
|
|
198
|
+
return 'No capability changes detected.';
|
|
199
|
+
}
|
|
200
|
+
if (diff.newly_destructive) {
|
|
201
|
+
const tier1Changes = [
|
|
202
|
+
...diff.capabilities.added.filter(c => c.severity === 'categorical_acquisition'),
|
|
203
|
+
...diff.capabilities.modified.filter(c => c.severity === 'categorical_acquisition'),
|
|
204
|
+
];
|
|
205
|
+
if (tier1Changes.length > 0) {
|
|
206
|
+
const first = tier1Changes[0];
|
|
207
|
+
if (first.isNewTool) {
|
|
208
|
+
const confidence = first.provenance === 'inferred' ? 'appears to be added' : 'added';
|
|
209
|
+
return `New tool ${confidence}: ${first.tool_id} with ${first.verb} access to ${first.resource ?? 'default'}.`;
|
|
210
|
+
}
|
|
211
|
+
const confidence = first.provenance === 'inferred' ? 'appears to have' : 'now has';
|
|
212
|
+
return `${first.tool_id} ${confidence} ${first.verb} access to ${first.resource ?? 'default'} (previously read-only).`;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const tier2 = diff.capabilities.modified.filter(c => c.severity === 'scope_expansion');
|
|
216
|
+
if (tier2.length > 0) {
|
|
217
|
+
const first = tier2[0];
|
|
218
|
+
return `${first.tool_id} now has ${first.verb} access to ${first.resource ?? 'default'} (previously scoped to ${first.previousResource ?? 'default'}).`;
|
|
219
|
+
}
|
|
220
|
+
const allRemovals = diff.capabilities.removed.filter(c => c.severity === 'scope_narrowing');
|
|
221
|
+
const removedToolIds = new Set(allRemovals.map(c => c.tool_id));
|
|
222
|
+
const completelyRemovedTools = new Set();
|
|
223
|
+
for (const toolId of removedToolIds) {
|
|
224
|
+
const hasAnyAddBack = diff.capabilities.added.some(c => c.tool_id === toolId);
|
|
225
|
+
if (!hasAnyAddBack) {
|
|
226
|
+
completelyRemovedTools.add(toolId);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const tier3 = [
|
|
230
|
+
...diff.capabilities.removed.filter(c => c.severity === 'scope_narrowing'),
|
|
231
|
+
...diff.capabilities.modified.filter(c => c.severity === 'scope_narrowing'),
|
|
232
|
+
];
|
|
233
|
+
if (tier3.length > 0) {
|
|
234
|
+
const first = tier3[0];
|
|
235
|
+
if (completelyRemovedTools.has(first.tool_id)) {
|
|
236
|
+
return `${first.tool_id} tool removed.`;
|
|
237
|
+
}
|
|
238
|
+
if (first.changeType === 'removed') {
|
|
239
|
+
return `${first.tool_id} tool removed; no longer has ${first.verb} access to ${first.resource ?? 'default'}.`;
|
|
240
|
+
}
|
|
241
|
+
return `${first.tool_id} scope narrowed to ${first.resource ?? 'default'} (previously ${first.previousResource ?? 'default'}).`;
|
|
242
|
+
}
|
|
243
|
+
if (diff.secrets.new.length > 0) {
|
|
244
|
+
const secret = diff.secrets.new[0];
|
|
245
|
+
return `New tool requires new credential: ${secret.secret_id} (${secret.description}).`;
|
|
246
|
+
}
|
|
247
|
+
if (diff.secrets.reused.length > 0) {
|
|
248
|
+
const secret = diff.secrets.reused[0];
|
|
249
|
+
return `New tool added; reuses existing credential ${secret.secret_id}.`;
|
|
250
|
+
}
|
|
251
|
+
if (diff.secrets.required_changed.length > 0) {
|
|
252
|
+
const secret = diff.secrets.required_changed[0];
|
|
253
|
+
const status = secret.requiredAfter ? 'now required' : 'now optional';
|
|
254
|
+
return `Credential requirement changed: ${secret.secret_id} is ${status} (previously ${!secret.requiredAfter ? 'required' : 'optional'}).`;
|
|
255
|
+
}
|
|
256
|
+
// New non-destructive capabilities
|
|
257
|
+
const newNonDestructive = diff.capabilities.added.filter(c => c.severity !== 'categorical_acquisition');
|
|
258
|
+
if (newNonDestructive.length > 0) {
|
|
259
|
+
const first = newNonDestructive[0];
|
|
260
|
+
const confidence = first.provenance === 'inferred' ? 'appears to add' : 'adds';
|
|
261
|
+
return `${first.tool_id} ${confidence} ${first.verb} access to ${first.resource ?? 'default'}.`;
|
|
262
|
+
}
|
|
263
|
+
// Fallback
|
|
264
|
+
return 'Changes detected.';
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Verb, Provenance, CapabilityEntry } from '@scopewatch/manifest';
|
|
2
|
+
/**
|
|
3
|
+
* A single capability changed between two versions.
|
|
4
|
+
*/
|
|
5
|
+
export type CapabilityChange = {
|
|
6
|
+
tool_id: string;
|
|
7
|
+
verb: Verb;
|
|
8
|
+
resource: string | undefined;
|
|
9
|
+
changeType: 'added' | 'removed' | 'modified';
|
|
10
|
+
severity: 'categorical_acquisition' | 'scope_expansion' | 'scope_narrowing' | 'cosmetic';
|
|
11
|
+
provenance: Provenance;
|
|
12
|
+
previousResource: string | undefined;
|
|
13
|
+
isNewTool?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A single credential changed between two versions.
|
|
17
|
+
* Four-state model, not two:
|
|
18
|
+
* - new: new secret introduced
|
|
19
|
+
* - reused: existing secret now used by additional tools
|
|
20
|
+
* - removed: secret no longer required
|
|
21
|
+
* - required_changed: secret's required field changed (false→true means graceful degradation disappears)
|
|
22
|
+
*/
|
|
23
|
+
export type CredentialChange = {
|
|
24
|
+
secret_id: string;
|
|
25
|
+
changeType: 'new' | 'reused' | 'removed' | 'required_changed';
|
|
26
|
+
description: string;
|
|
27
|
+
used_by_new_tools: string[] | undefined;
|
|
28
|
+
requiredBefore: boolean | undefined;
|
|
29
|
+
requiredAfter: boolean | undefined;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Complete diff between two manifest versions.
|
|
33
|
+
* Organized by change type and severity.
|
|
34
|
+
*/
|
|
35
|
+
export type CapabilityDiff = {
|
|
36
|
+
from_version: string;
|
|
37
|
+
to_version: string;
|
|
38
|
+
capabilities: {
|
|
39
|
+
added: CapabilityChange[];
|
|
40
|
+
removed: CapabilityChange[];
|
|
41
|
+
modified: CapabilityChange[];
|
|
42
|
+
};
|
|
43
|
+
secrets: {
|
|
44
|
+
new: CredentialChange[];
|
|
45
|
+
reused: CredentialChange[];
|
|
46
|
+
removed: CredentialChange[];
|
|
47
|
+
required_changed: CredentialChange[];
|
|
48
|
+
};
|
|
49
|
+
newly_destructive: boolean;
|
|
50
|
+
riskLevel: 'none' | 'low' | 'medium' | 'high';
|
|
51
|
+
hasChanges: boolean;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Internal: indexed capability for diff computation.
|
|
55
|
+
*/
|
|
56
|
+
export type IndexedCapability = {
|
|
57
|
+
capability: CapabilityEntry;
|
|
58
|
+
inVersion: 'from' | 'to' | 'both';
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Internal: index of capabilities keyed by (tool_id, verb, resource).
|
|
62
|
+
*/
|
|
63
|
+
export type CapabilityIndex = Map<string, CapabilityEntry>;
|
|
64
|
+
/**
|
|
65
|
+
* Internal: for organizing changes by tool for severity assessment.
|
|
66
|
+
*/
|
|
67
|
+
export type ToolCapabilityDelta = {
|
|
68
|
+
tool_id: string;
|
|
69
|
+
from: Map<string, CapabilityEntry>;
|
|
70
|
+
to: Map<string, CapabilityEntry>;
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAkB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE9F;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,UAAU,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;IAC7C,QAAQ,EAAE,yBAAyB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,UAAU,CAAC;IACzF,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,kBAAkB,CAAC;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,aAAa,EAAE,OAAO,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IAGnB,YAAY,EAAE;QACZ,KAAK,EAAE,gBAAgB,EAAE,CAAC;QAC1B,OAAO,EAAE,gBAAgB,EAAE,CAAC;QAC5B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;KAC9B,CAAC;IAGF,OAAO,EAAE;QACP,GAAG,EAAE,gBAAgB,EAAE,CAAC;QACxB,MAAM,EAAE,gBAAgB,EAAE,CAAC;QAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;QAC5B,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;KACtC,CAAC;IAGF,iBAAiB,EAAE,OAAO,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC9C,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;CACnC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnC,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAClC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scopewatch/diff-engine",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Capability diff computation and human-readable rendering",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Sathvik Putta <puttasathvik16@gmail.com>",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/PuttaSathvik16/scopewatch.git",
|
|
10
|
+
"directory": "packages/diff-engine"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"test": "node --import tsx --test 'test/**/*.test.ts'",
|
|
27
|
+
"clean": "rm -rf dist"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@scopewatch/manifest": "0.0.1",
|
|
31
|
+
"zod": "^3.24.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"typescript": "^5.7.0",
|
|
36
|
+
"tsx": "^4.19.0"
|
|
37
|
+
}
|
|
38
|
+
}
|