@vess-id/vess 0.0.0-dev-20261015070513 â 0.0.0-dev-20261015130518
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/core/approval-pull.d.ts +4 -1
- package/dist/core/approval-pull.d.ts.map +1 -1
- package/dist/core/approval-pull.js.map +1 -1
- package/dist/core/execution-engine.d.ts +32 -5
- package/dist/core/execution-engine.d.ts.map +1 -1
- package/dist/core/execution-engine.js +173 -165
- package/dist/core/execution-engine.js.map +1 -1
- package/dist/core/local-invoke.d.ts +50 -0
- package/dist/core/local-invoke.d.ts.map +1 -0
- package/dist/core/local-invoke.js +266 -0
- package/dist/core/local-invoke.js.map +1 -0
- package/dist/executor/secret-file.d.ts.map +1 -1
- package/dist/executor/secret-file.js +49 -2
- package/dist/executor/secret-file.js.map +1 -1
- package/dist/gateway/gateway-client.d.ts +47 -0
- package/dist/gateway/gateway-client.d.ts.map +1 -1
- package/dist/gateway/gateway-client.js +53 -0
- package/dist/gateway/gateway-client.js.map +1 -1
- package/package.json +2 -2
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
import type { AgentdGatewayClient, DelegatedApprovalView } from '../gateway/gateway-client';
|
|
24
24
|
/** What the pull hands to a holder: the API's row, nothing from an LLM. */
|
|
25
25
|
export type ApprovedRow = Pick<DelegatedApprovalView, 'id' | 'action' | 'actionParams'>;
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* `executed` = it ran; `failed` = it was issued but did not run successfully (presented and failed, or
|
|
28
|
+
* refused at presentation); `skipped` = nothing was asked or run.
|
|
29
|
+
*/
|
|
27
30
|
export type PullOutcome = 'executed' | 'failed' | 'skipped';
|
|
28
31
|
/** A holder that runs in this process (an `ExecutionEngine`). */
|
|
29
32
|
export interface PullHolder {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-pull.d.ts","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAE3F,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,EAAE,IAAI,GAAG,QAAQ,GAAG,cAAc,CAAC,CAAA;AAEvF
|
|
1
|
+
{"version":3,"file":"approval-pull.d.ts","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAE3F,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,EAAE,IAAI,GAAG,QAAQ,GAAG,cAAc,CAAC,CAAA;AAEvF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE3D,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,gFAAgF;IAChF,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACxD;AASD,qBAAa,YAAY;IAWrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAZtB,MAAM,CAAC,QAAQ,CAAC,WAAW,SAAS;IACpC,OAAO,CAAC,KAAK,CAAC,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAQ;IAEvB;;;;OAIG;gBAEgB,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,EAC3D,OAAO,EAAE,MAAM,SAAS,UAAU,EAAE,EACpC,GAAG,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAe;IAGzD,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;IAKZ,sFAAsF;IAChF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBb,OAAO;CAqBtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-pull.js","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"approval-pull.js","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -120,8 +120,11 @@ export declare class ExecutionEngine {
|
|
|
120
120
|
* question â an approval card the owner never asked for, every 10 s.
|
|
121
121
|
* ðī Only `allow` runs. `in_flight` / `done` (another path got there first), `closed`, `ask`, a
|
|
122
122
|
* refusal or a failure run nothing; the issuer's CAS is what keeps a row to one execution.
|
|
123
|
-
*
|
|
124
|
-
*
|
|
123
|
+
* ðī Local actions (`os.*`, B3b) take the same route; `allow` is then presented at `local/present`
|
|
124
|
+
* and the executor runs that answer's arguments (`executeLocalDelegated`). A permanent present
|
|
125
|
+
* failure closes the row, so it is not pulled again.
|
|
126
|
+
* The PEP (the api, or agentd for a local action via `local/result`) records the outcome against the
|
|
127
|
+
* credential, which is what `aidentity_get_result` reads.
|
|
125
128
|
*/
|
|
126
129
|
executeApproved(row: ApprovedRow): Promise<PullOutcome>;
|
|
127
130
|
/**
|
|
@@ -161,7 +164,6 @@ export declare class ExecutionEngine {
|
|
|
161
164
|
*/
|
|
162
165
|
private isPolicyForbiddenError;
|
|
163
166
|
private policyForbiddenReason;
|
|
164
|
-
private executeLocal;
|
|
165
167
|
/**
|
|
166
168
|
* Execute locally with an already-acquired VC (skips ensureVC).
|
|
167
169
|
* Used by both the normal path (after ensureVC) and handleApprovalResponse (after quickApprove).
|
|
@@ -185,6 +187,8 @@ export declare class ExecutionEngine {
|
|
|
185
187
|
* not decided in time â `pending` + `request_id` (read later with `aidentity_get_result`);
|
|
186
188
|
* 3. `allow` â present the credential and call the PEP with `allow.actionParams` only
|
|
187
189
|
* (`executeWithCredential`; `FrozenParams` makes the LLM input unpassable).
|
|
190
|
+
* A local action (`os.*`, PR B3b) takes this same route; its `allow` is presented at
|
|
191
|
+
* `local/present` and run here with that answer's arguments (`executeLocalDelegated`).
|
|
188
192
|
* ðī No legacy endpoint is reached from here: no wallet VC, no auto-issue / claim / OOB request /
|
|
189
193
|
* resource resolution, no in-band approval token. Only the issuer raises approval requests.
|
|
190
194
|
*/
|
|
@@ -200,6 +204,26 @@ export declare class ExecutionEngine {
|
|
|
200
204
|
private auditHandoffRefused;
|
|
201
205
|
/** One audit entry for a call that ended without execution on the delegated arm. */
|
|
202
206
|
private auditNotExecuted;
|
|
207
|
+
/** Audit kind of the delegated arms: a local action is executed (and enforced) on this machine. */
|
|
208
|
+
private delegatedAuditKind;
|
|
209
|
+
/** `allow` from the issuer: a local action is presented and run here, a gateway action at the PEP. */
|
|
210
|
+
private executeAllowed;
|
|
211
|
+
/**
|
|
212
|
+
* A local action (`os.*`) after the issuer's `allow` (plan B, PR B3b): present the credential at
|
|
213
|
+
* `local/present`, run EXACTLY the arguments it returns, write the outcome once
|
|
214
|
+
* (`core/local-invoke.ts`). No wallet, no `verify-authorize`, no offline arm.
|
|
215
|
+
*/
|
|
216
|
+
private executeLocalDelegated;
|
|
217
|
+
/**
|
|
218
|
+
* Run the local executor on the present answer's arguments.
|
|
219
|
+
* ðī `params` is the only input (`FrozenParams`): the env profile, the working directory, the file
|
|
220
|
+
* path and the content all come from it.
|
|
221
|
+
* ðī `approvedResource` = the frozen `file_path`: the executor resolves the path again right before it
|
|
222
|
+
* reads / writes and refuses if it now points elsewhere (a symlink swapped in after the approval,
|
|
223
|
+
* plan B I-E). `approvedFingerprint` (inode binding) is not passed â Q21 default (a), the same
|
|
224
|
+
* protection as the legacy path.
|
|
225
|
+
*/
|
|
226
|
+
private runLocalExecutor;
|
|
203
227
|
/** Present the credential and call the PEP with the issuer's arguments (`FrozenParams`). */
|
|
204
228
|
private executeDelegated;
|
|
205
229
|
/** The issuer refused (403 = the owner's settings forbid it: terminal) or could not be reached. */
|
|
@@ -243,8 +267,11 @@ export declare class ExecutionEngine {
|
|
|
243
267
|
private createInBandApprovalResponse;
|
|
244
268
|
/**
|
|
245
269
|
* Pre-request permissions for multiple actions (batch).
|
|
246
|
-
*
|
|
247
|
-
*
|
|
270
|
+
* ðī There is no pre-approval any more (B1 for gateway actions, B3b for local ones): every
|
|
271
|
+
* credential is issued per call by the api's issuer (`aidentity_call_tool` â `pending` +
|
|
272
|
+
* `request_id` when the owner must approve). Raising a legacy approval request here would create
|
|
273
|
+
* a card that no new build ever executes. Only the device's own deny is reported (a local action
|
|
274
|
+
* that the local / org policy forbids would be refused before the issuer is asked).
|
|
248
275
|
*/
|
|
249
276
|
requestPermissions(actions: string[]): Promise<ExecuteResult>;
|
|
250
277
|
listAvailableTools(): Promise<ListToolsResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-engine.d.ts","sourceRoot":"","sources":["../../src/core/execution-engine.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAuC,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EACL,mBAAmB,EAMpB,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"execution-engine.d.ts","sourceRoot":"","sources":["../../src/core/execution-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,6 +57,7 @@ const fs = __importStar(require("fs"));
|
|
|
57
57
|
const wallet_1 = require("../wallet/wallet");
|
|
58
58
|
const gateway_client_1 = require("../gateway/gateway-client");
|
|
59
59
|
const delegated_invoke_1 = require("./delegated-invoke");
|
|
60
|
+
const local_invoke_1 = require("./local-invoke");
|
|
60
61
|
const call_budget_1 = require("./call-budget");
|
|
61
62
|
const resource_canonicalizer_1 = require("../utils/resource-canonicalizer");
|
|
62
63
|
const vc_utils_1 = require("../utils/vc-utils");
|
|
@@ -84,6 +85,19 @@ const POLICY_SYNC_TTL_MS = 30 * 60 * 1000;
|
|
|
84
85
|
/** Fallback OOB approval expiration (seconds) when the API doesn't return a value.
|
|
85
86
|
* Kept short (5 min) so the agent doesn't wait on a possibly-expired request. */
|
|
86
87
|
const OOB_APPROVAL_DEFAULT_EXPIRES_IN_SECONDS = 300;
|
|
88
|
+
/**
|
|
89
|
+
* The resource of a local action for the audit log (same rule as `execute()`): the file path, or the
|
|
90
|
+
* command line of `os.process.run`. Only the path / command â never `content`.
|
|
91
|
+
*/
|
|
92
|
+
function localAuditResource(action, params) {
|
|
93
|
+
if (typeof params.file_path === 'string' && params.file_path !== '') {
|
|
94
|
+
return { requestedResource: params.file_path, normalizedResource: params.file_path };
|
|
95
|
+
}
|
|
96
|
+
if (action === 'os.process.run' && Array.isArray(params.command)) {
|
|
97
|
+
return { requestedResource: params.command.map(String).join(' ') };
|
|
98
|
+
}
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
87
101
|
class ExecutionEngine {
|
|
88
102
|
policyEvaluator;
|
|
89
103
|
wallet;
|
|
@@ -296,11 +310,10 @@ class ExecutionEngine {
|
|
|
296
310
|
return { success: false, error: LEGACY_HANDOFF_REFUSED };
|
|
297
311
|
}
|
|
298
312
|
const { action, input } = request;
|
|
299
|
-
// ðī `pendingRequestId` (claim of a legacy OOB approval) is refused for
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
if (request.pendingRequestId && !(0, executor_registry_1.isLocalAction)(action)) {
|
|
313
|
+
// ðī `pendingRequestId` (claim of a legacy OOB approval) is refused for EVERY action (B1 for gateway
|
|
314
|
+
// actions, B3b for local ones): both arms only execute approvals the issuer hands back for THIS
|
|
315
|
+
// holder, and an approved call runs without being resent (the pull, B2).
|
|
316
|
+
if (request.pendingRequestId) {
|
|
304
317
|
this.auditHandoffRefused(action, 'pendingRequestId');
|
|
305
318
|
return { success: false, error: LEGACY_HANDOFF_REFUSED };
|
|
306
319
|
}
|
|
@@ -315,11 +328,9 @@ class ExecutionEngine {
|
|
|
315
328
|
// (incl. local os.* actions) pass through unchanged. Skipped on the
|
|
316
329
|
// approval-retry / pending-approval paths, which carry the already
|
|
317
330
|
// validated original input plus an approval token / request id.
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
return { success: false, error: inputCheck.errors.join(' ') };
|
|
322
|
-
}
|
|
331
|
+
const inputCheck = (0, ai_identity_1.validateActionInput)(action, input ?? {});
|
|
332
|
+
if (!inputCheck.valid) {
|
|
333
|
+
return { success: false, error: inputCheck.errors.join(' ') };
|
|
323
334
|
}
|
|
324
335
|
// 1. Extract provider from action (e.g., 'os' from 'os.secret.read')
|
|
325
336
|
const provider = action.split('.')[0];
|
|
@@ -352,19 +363,20 @@ class ExecutionEngine {
|
|
|
352
363
|
});
|
|
353
364
|
return { success: false, error: `Action denied by policy: ${policyResult.reason}` };
|
|
354
365
|
}
|
|
355
|
-
// Handle OOB approval polling (pendingRequestId) â local actions only (checked above).
|
|
356
|
-
if (request.pendingRequestId) {
|
|
357
|
-
return this.handlePendingApproval(request);
|
|
358
|
-
}
|
|
359
366
|
// 4. Determine execution routing
|
|
360
367
|
const routing = (0, executor_registry_1.determineRouting)(provider, action);
|
|
361
|
-
// 5.
|
|
368
|
+
// 5. Both arms ask the api's issuer (B1 gateway, B3b local). ðī A local action asks with the
|
|
369
|
+
// RESOLVED path (`canonicalizePath`: `~`, `..`, symlinks): the issued digest, the approval row's
|
|
370
|
+
// frozen arguments and the approval card all carry the real file, and the executor compares
|
|
371
|
+
// that path again at execution time (`approvedResource`, plan B I-E).
|
|
362
372
|
if (routing.executor === 'local') {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
373
|
+
if (!(0, executor_registry_1.getLocalExecutor)(action)) {
|
|
374
|
+
return { success: false, error: `No local executor for action: ${action}` };
|
|
375
|
+
}
|
|
376
|
+
const sent = normalizedResource ? { ...input, file_path: normalizedResource } : input;
|
|
377
|
+
return this.executeViaGateway(provider, action, sent, startedAt);
|
|
367
378
|
}
|
|
379
|
+
return this.executeViaGateway(provider, action, input, startedAt);
|
|
368
380
|
}
|
|
369
381
|
/** The holder DID of this engine (the approval pull lists approved rows per DID). */
|
|
370
382
|
get agentDid() {
|
|
@@ -379,13 +391,14 @@ class ExecutionEngine {
|
|
|
379
391
|
* question â an approval card the owner never asked for, every 10 s.
|
|
380
392
|
* ðī Only `allow` runs. `in_flight` / `done` (another path got there first), `closed`, `ask`, a
|
|
381
393
|
* refusal or a failure run nothing; the issuer's CAS is what keeps a row to one execution.
|
|
382
|
-
*
|
|
383
|
-
*
|
|
394
|
+
* ðī Local actions (`os.*`, B3b) take the same route; `allow` is then presented at `local/present`
|
|
395
|
+
* and the executor runs that answer's arguments (`executeLocalDelegated`). A permanent present
|
|
396
|
+
* failure closes the row, so it is not pulled again.
|
|
397
|
+
* The PEP (the api, or agentd for a local action via `local/result`) records the outcome against the
|
|
398
|
+
* credential, which is what `aidentity_get_result` reads.
|
|
384
399
|
*/
|
|
385
400
|
async executeApproved(row) {
|
|
386
401
|
const { id, action } = row;
|
|
387
|
-
if ((0, executor_registry_1.isLocalAction)(action))
|
|
388
|
-
return 'skipped';
|
|
389
402
|
// ðī Never ask unnamed: an empty id would read as "no approval named" and raise a NEW question.
|
|
390
403
|
if (typeof id !== 'string' || id === '')
|
|
391
404
|
return 'skipped';
|
|
@@ -411,7 +424,7 @@ class ExecutionEngine {
|
|
|
411
424
|
decisionSource: 'local_policy',
|
|
412
425
|
decisionReason: `approval_pull ${id}: ${policyResult.reason}`,
|
|
413
426
|
...(typeof filePath === 'string' ? { requestedResource: filePath } : {}),
|
|
414
|
-
executionType: 'gateway',
|
|
427
|
+
executionType: (0, executor_registry_1.isLocalAction)(action) ? 'local' : 'gateway',
|
|
415
428
|
});
|
|
416
429
|
}
|
|
417
430
|
return 'skipped';
|
|
@@ -427,7 +440,7 @@ class ExecutionEngine {
|
|
|
427
440
|
}
|
|
428
441
|
if (answer.status !== 'allow')
|
|
429
442
|
return 'skipped';
|
|
430
|
-
const result = await this.
|
|
443
|
+
const result = await this.executeAllowed(provider, action, answer);
|
|
431
444
|
return result.success ? 'executed' : 'failed';
|
|
432
445
|
}
|
|
433
446
|
/**
|
|
@@ -471,8 +484,21 @@ class ExecutionEngine {
|
|
|
471
484
|
break;
|
|
472
485
|
}
|
|
473
486
|
const outcome = r.execution?.outcome;
|
|
474
|
-
if (outcome === 'executed')
|
|
487
|
+
if (outcome === 'executed') {
|
|
488
|
+
// ðī No stored content (a secret read keeps none, owner decision 2): say it ran, and that the
|
|
489
|
+
// content is not available â never an empty value the LLM could read as "the file is empty".
|
|
490
|
+
if (r.result === null || r.result === undefined) {
|
|
491
|
+
return {
|
|
492
|
+
success: true,
|
|
493
|
+
data: {
|
|
494
|
+
status: 'executed',
|
|
495
|
+
request_id: requestId,
|
|
496
|
+
note: 'It was carried out; no result content is stored for it, so none can be returned here.',
|
|
497
|
+
},
|
|
498
|
+
};
|
|
499
|
+
}
|
|
475
500
|
return { success: true, data: r.result };
|
|
501
|
+
}
|
|
476
502
|
// ðī `expired` = not executed: unanswered until it expired / closed after approval without running /
|
|
477
503
|
// withdrawn. An executed row is `consumed` + `executed` (the branch above).
|
|
478
504
|
if (r.status === 'expired') {
|
|
@@ -676,36 +702,6 @@ class ExecutionEngine {
|
|
|
676
702
|
// ===========================================================================
|
|
677
703
|
// Local execution with VP verification (spec §7.4)
|
|
678
704
|
// ===========================================================================
|
|
679
|
-
async executeLocal(action, params, provider, normalizedResource, resourceFingerprint, requestedResource) {
|
|
680
|
-
const resourceInfo = normalizedResource && resourceFingerprint
|
|
681
|
-
? { normalizedResource, fingerprint: resourceFingerprint }
|
|
682
|
-
: undefined;
|
|
683
|
-
// 1. Ensure VC (4-step acquisition)
|
|
684
|
-
const vcResult = await this.ensureVC(action, provider, resourceInfo, params);
|
|
685
|
-
if ('approvalRequired' in vcResult) {
|
|
686
|
-
return { success: false, approvalRequired: vcResult.approvalRequired };
|
|
687
|
-
}
|
|
688
|
-
if ('waitingForApproval' in vcResult) {
|
|
689
|
-
return { success: false, waitingForApproval: vcResult.waitingForApproval };
|
|
690
|
-
}
|
|
691
|
-
if ('denied' in vcResult) {
|
|
692
|
-
this.logAudit({
|
|
693
|
-
action,
|
|
694
|
-
provider,
|
|
695
|
-
decision: 'deny',
|
|
696
|
-
enforcementType: 'local',
|
|
697
|
-
decisionSource: 'local_policy',
|
|
698
|
-
decisionReason: vcResult.reason,
|
|
699
|
-
requestedResource,
|
|
700
|
-
normalizedResource,
|
|
701
|
-
resourceFingerprint,
|
|
702
|
-
executionType: 'local',
|
|
703
|
-
});
|
|
704
|
-
return { success: false, error: `Permission denied: ${vcResult.reason}` };
|
|
705
|
-
}
|
|
706
|
-
// 2. Execute with the acquired VC
|
|
707
|
-
return this.executeLocalWithVC(action, params, provider, vcResult, normalizedResource, resourceFingerprint, requestedResource);
|
|
708
|
-
}
|
|
709
705
|
/**
|
|
710
706
|
* Execute locally with an already-acquired VC (skips ensureVC).
|
|
711
707
|
* Used by both the normal path (after ensureVC) and handleApprovalResponse (after quickApprove).
|
|
@@ -972,6 +968,8 @@ class ExecutionEngine {
|
|
|
972
968
|
* not decided in time â `pending` + `request_id` (read later with `aidentity_get_result`);
|
|
973
969
|
* 3. `allow` â present the credential and call the PEP with `allow.actionParams` only
|
|
974
970
|
* (`executeWithCredential`; `FrozenParams` makes the LLM input unpassable).
|
|
971
|
+
* A local action (`os.*`, PR B3b) takes this same route; its `allow` is presented at
|
|
972
|
+
* `local/present` and run here with that answer's arguments (`executeLocalDelegated`).
|
|
975
973
|
* ðī No legacy endpoint is reached from here: no wallet VC, no auto-issue / claim / OOB request /
|
|
976
974
|
* resource resolution, no in-band approval token. Only the issuer raises approval requests.
|
|
977
975
|
*/
|
|
@@ -1021,7 +1019,7 @@ class ExecutionEngine {
|
|
|
1021
1019
|
}
|
|
1022
1020
|
if (second.status === 'ask') {
|
|
1023
1021
|
// The approved row could not be used and a different question stands. Do not execute.
|
|
1024
|
-
return this.deferred(second.approvalId, second.approvalUrl);
|
|
1022
|
+
return this.deferred(second.approvalId, second.approvalUrl, action);
|
|
1025
1023
|
}
|
|
1026
1024
|
return this.settle(provider, action, second);
|
|
1027
1025
|
}
|
|
@@ -1048,7 +1046,7 @@ class ExecutionEngine {
|
|
|
1048
1046
|
return this.inFlight(first.approvalId);
|
|
1049
1047
|
default:
|
|
1050
1048
|
// Still pending, or no time was left to wait.
|
|
1051
|
-
return this.deferred(first.approvalId, first.approvalUrl);
|
|
1049
|
+
return this.deferred(first.approvalId, first.approvalUrl, action);
|
|
1052
1050
|
}
|
|
1053
1051
|
}
|
|
1054
1052
|
/**
|
|
@@ -1069,7 +1067,7 @@ class ExecutionEngine {
|
|
|
1069
1067
|
async settle(provider, action, answer) {
|
|
1070
1068
|
switch (answer.status) {
|
|
1071
1069
|
case 'allow':
|
|
1072
|
-
return this.
|
|
1070
|
+
return this.executeAllowed(provider, action, answer);
|
|
1073
1071
|
case 'done':
|
|
1074
1072
|
return { success: true, data: answer.result };
|
|
1075
1073
|
case 'not_executed':
|
|
@@ -1117,10 +1115,97 @@ class ExecutionEngine {
|
|
|
1117
1115
|
action,
|
|
1118
1116
|
provider,
|
|
1119
1117
|
decision: 'deny',
|
|
1120
|
-
|
|
1118
|
+
...this.delegatedAuditKind(action),
|
|
1121
1119
|
decisionSource: 'delegated_issuer',
|
|
1122
1120
|
decisionReason: reason,
|
|
1123
|
-
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
/** Audit kind of the delegated arms: a local action is executed (and enforced) on this machine. */
|
|
1124
|
+
delegatedAuditKind(action) {
|
|
1125
|
+
return (0, executor_registry_1.isLocalAction)(action)
|
|
1126
|
+
? { enforcementType: 'gateway_verified_local', executionType: 'local' }
|
|
1127
|
+
: { enforcementType: 'gateway', executionType: 'gateway' };
|
|
1128
|
+
}
|
|
1129
|
+
/** `allow` from the issuer: a local action is presented and run here, a gateway action at the PEP. */
|
|
1130
|
+
executeAllowed(provider, action, allow) {
|
|
1131
|
+
return (0, executor_registry_1.isLocalAction)(action)
|
|
1132
|
+
? this.executeLocalDelegated(provider, action, allow)
|
|
1133
|
+
: this.executeDelegated(provider, action, allow);
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* A local action (`os.*`) after the issuer's `allow` (plan B, PR B3b): present the credential at
|
|
1137
|
+
* `local/present`, run EXACTLY the arguments it returns, write the outcome once
|
|
1138
|
+
* (`core/local-invoke.ts`). No wallet, no `verify-authorize`, no offline arm.
|
|
1139
|
+
*/
|
|
1140
|
+
async executeLocalDelegated(provider, action, allow) {
|
|
1141
|
+
// No executor â do not present (presenting consumes the credential and burns the approval).
|
|
1142
|
+
if (!(0, executor_registry_1.getLocalExecutor)(action)) {
|
|
1143
|
+
await this.gatewayClient
|
|
1144
|
+
.delegatedRelease({ vcJti: allow.vcJti, subjectDid: this.context.agentDid })
|
|
1145
|
+
.catch(err => {
|
|
1146
|
+
process.stderr.write(`[vess] release of ${allow.vcJti} failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
1147
|
+
});
|
|
1148
|
+
this.logAudit({
|
|
1149
|
+
action,
|
|
1150
|
+
provider,
|
|
1151
|
+
decision: 'deny',
|
|
1152
|
+
enforcementType: 'gateway_verified_local',
|
|
1153
|
+
decisionSource: 'delegated_issuer',
|
|
1154
|
+
decisionReason: 'no_local_executor',
|
|
1155
|
+
executionType: 'local',
|
|
1156
|
+
credentialId: allow.vcJti,
|
|
1157
|
+
});
|
|
1158
|
+
return { success: false, error: `No local executor for action: ${action}` };
|
|
1159
|
+
}
|
|
1160
|
+
const execution = await (0, local_invoke_1.executeLocalWithCredential)({ gateway: this.gatewayClient, vpBuilder: this.vpBuilder }, {
|
|
1161
|
+
agentDid: this.context.agentDid,
|
|
1162
|
+
projectId: this.context.projectId,
|
|
1163
|
+
agentPrivateKeyJwk: this.context.agentPrivateKeyJwk,
|
|
1164
|
+
gatewayUrl: this.context.gatewayUrl,
|
|
1165
|
+
}, action, allow, params => this.runLocalExecutor(action, params));
|
|
1166
|
+
this.logAudit({
|
|
1167
|
+
action,
|
|
1168
|
+
provider,
|
|
1169
|
+
decision: execution.success ? 'allow' : 'deny',
|
|
1170
|
+
enforcementType: 'gateway_verified_local',
|
|
1171
|
+
decisionSource: 'delegated_issuer',
|
|
1172
|
+
decisionReason: execution.success
|
|
1173
|
+
? undefined
|
|
1174
|
+
: `${execution.outcome}: ${execution.error ?? ''}`,
|
|
1175
|
+
executionType: 'local',
|
|
1176
|
+
credentialId: allow.vcJti,
|
|
1177
|
+
// ðī Which file / command: what RAN (the present's answer), or what was asked for when nothing ran.
|
|
1178
|
+
...localAuditResource(action, execution.ran ?? allow.actionParams),
|
|
1179
|
+
...(execution.normalizedResource ? { normalizedResource: execution.normalizedResource } : {}),
|
|
1180
|
+
...(execution.resourceFingerprint
|
|
1181
|
+
? { resourceFingerprint: execution.resourceFingerprint }
|
|
1182
|
+
: {}),
|
|
1183
|
+
});
|
|
1184
|
+
if (execution.success)
|
|
1185
|
+
return { success: true, data: execution.data };
|
|
1186
|
+
return { success: false, data: execution.data, error: execution.error };
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Run the local executor on the present answer's arguments.
|
|
1190
|
+
* ðī `params` is the only input (`FrozenParams`): the env profile, the working directory, the file
|
|
1191
|
+
* path and the content all come from it.
|
|
1192
|
+
* ðī `approvedResource` = the frozen `file_path`: the executor resolves the path again right before it
|
|
1193
|
+
* reads / writes and refuses if it now points elsewhere (a symlink swapped in after the approval,
|
|
1194
|
+
* plan B I-E). `approvedFingerprint` (inode binding) is not passed â Q21 default (a), the same
|
|
1195
|
+
* protection as the legacy path.
|
|
1196
|
+
*/
|
|
1197
|
+
async runLocalExecutor(action, params) {
|
|
1198
|
+
const executor = (0, executor_registry_1.getLocalExecutor)(action);
|
|
1199
|
+
if (!executor)
|
|
1200
|
+
return { success: false, error: `No local executor for action: ${action}` };
|
|
1201
|
+
const args = params;
|
|
1202
|
+
if (action === 'os.process.run') {
|
|
1203
|
+
const resolvedEnv = await this.resolveProcessEnv(args);
|
|
1204
|
+
return executor(args, { resolvedEnv });
|
|
1205
|
+
}
|
|
1206
|
+
return executor(args, {
|
|
1207
|
+
rootDid: this.context.rootDid,
|
|
1208
|
+
approvedResource: typeof args.file_path === 'string' ? args.file_path : undefined,
|
|
1124
1209
|
});
|
|
1125
1210
|
}
|
|
1126
1211
|
/** Present the credential and call the PEP with the issuer's arguments (`FrozenParams`). */
|
|
@@ -1172,10 +1257,9 @@ class ExecutionEngine {
|
|
|
1172
1257
|
action,
|
|
1173
1258
|
provider,
|
|
1174
1259
|
decision: 'deny',
|
|
1175
|
-
enforcementType: 'gateway',
|
|
1176
1260
|
decisionSource: 'delegated_issuer',
|
|
1177
1261
|
decisionReason: `refused: ${reason}`,
|
|
1178
|
-
|
|
1262
|
+
...this.delegatedAuditKind(action),
|
|
1179
1263
|
});
|
|
1180
1264
|
return { success: false, error: `"${action}" was refused: ${reason}. Nothing was done.` };
|
|
1181
1265
|
}
|
|
@@ -1185,10 +1269,9 @@ class ExecutionEngine {
|
|
|
1185
1269
|
action,
|
|
1186
1270
|
provider,
|
|
1187
1271
|
decision: 'deny',
|
|
1188
|
-
enforcementType: 'gateway',
|
|
1189
1272
|
decisionSource: 'delegated_issuer',
|
|
1190
1273
|
decisionReason: `policy_forbidden: ${reason}`,
|
|
1191
|
-
|
|
1274
|
+
...this.delegatedAuditKind(action),
|
|
1192
1275
|
});
|
|
1193
1276
|
// ðī Terminal: an approval cannot lift it, so no approval URL is offered.
|
|
1194
1277
|
return {
|
|
@@ -1202,14 +1285,15 @@ class ExecutionEngine {
|
|
|
1202
1285
|
action,
|
|
1203
1286
|
provider,
|
|
1204
1287
|
decision: 'deny',
|
|
1205
|
-
enforcementType: 'gateway',
|
|
1206
1288
|
decisionSource: 'delegated_issuer',
|
|
1207
1289
|
decisionReason: `Gateway unreachable: ${msg}`,
|
|
1208
|
-
|
|
1290
|
+
...this.delegatedAuditKind(action),
|
|
1209
1291
|
});
|
|
1210
1292
|
return {
|
|
1211
1293
|
success: false,
|
|
1212
|
-
error:
|
|
1294
|
+
error: (0, executor_registry_1.isLocalAction)(action)
|
|
1295
|
+
? `Gateway required to authorize local actions but unreachable: ${msg}. Nothing was done.`
|
|
1296
|
+
: `Gateway required for SaaS operations but unreachable: ${msg}. Nothing was done.`,
|
|
1213
1297
|
};
|
|
1214
1298
|
}
|
|
1215
1299
|
/**
|
|
@@ -1217,7 +1301,7 @@ class ExecutionEngine {
|
|
|
1217
1301
|
* "call again once approved": an approved call is executed with the frozen arguments, and a resend
|
|
1218
1302
|
* whose arguments differ by one character is a different question.
|
|
1219
1303
|
*/
|
|
1220
|
-
deferred(approvalId, approvalUrl) {
|
|
1304
|
+
deferred(approvalId, approvalUrl, action) {
|
|
1221
1305
|
return {
|
|
1222
1306
|
success: true,
|
|
1223
1307
|
data: {
|
|
@@ -1226,7 +1310,13 @@ class ExecutionEngine {
|
|
|
1226
1310
|
approvalUrl,
|
|
1227
1311
|
next: 'The owner must approve this at approvalUrl. Show them the URL. Do NOT call ' +
|
|
1228
1312
|
'aidentity_call_tool again for this action: once approved it runs with exactly the ' +
|
|
1229
|
-
'arguments you sent. Read the outcome with aidentity_get_result { request_id }.'
|
|
1313
|
+
'arguments you sent. Read the outcome with aidentity_get_result { request_id }.' +
|
|
1314
|
+
// ðī Owner decision (2): a secret's content is kept nowhere, so a late approval cannot
|
|
1315
|
+
// deliver it. Say so, or an empty result reads as "the file is empty".
|
|
1316
|
+
(action && (0, local_invoke_1.readsSecret)(action)
|
|
1317
|
+
? ' This action handles a secret: its content is not kept, so if it is approved after ' +
|
|
1318
|
+
'this call, aidentity_get_result reports only that it ran, not the content.'
|
|
1319
|
+
: ''),
|
|
1230
1320
|
},
|
|
1231
1321
|
};
|
|
1232
1322
|
}
|
|
@@ -1781,112 +1871,32 @@ class ExecutionEngine {
|
|
|
1781
1871
|
// ===========================================================================
|
|
1782
1872
|
/**
|
|
1783
1873
|
* Pre-request permissions for multiple actions (batch).
|
|
1784
|
-
*
|
|
1785
|
-
*
|
|
1874
|
+
* ðī There is no pre-approval any more (B1 for gateway actions, B3b for local ones): every
|
|
1875
|
+
* credential is issued per call by the api's issuer (`aidentity_call_tool` â `pending` +
|
|
1876
|
+
* `request_id` when the owner must approve). Raising a legacy approval request here would create
|
|
1877
|
+
* a card that no new build ever executes. Only the device's own deny is reported (a local action
|
|
1878
|
+
* that the local / org policy forbids would be refused before the issuer is asked).
|
|
1786
1879
|
*/
|
|
1787
1880
|
async requestPermissions(actions) {
|
|
1788
1881
|
const approved = [];
|
|
1789
1882
|
const denied = [];
|
|
1790
1883
|
const pending = [];
|
|
1791
|
-
// ðī B1: gateway actions have no pre-approval. Their credential is issued per call by the api's
|
|
1792
|
-
// issuer (`aidentity_call_tool` â `pending` + `request_id` when the owner must approve). Raising a
|
|
1793
|
-
// legacy approval request here would create a card that no new build ever executes.
|
|
1794
1884
|
const callDirectly = [];
|
|
1795
1885
|
for (const action of actions) {
|
|
1796
1886
|
const provider = action.split('.')[0];
|
|
1797
|
-
if (
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
// Policy check
|
|
1802
|
-
const policyResult = this.policyEvaluator.evaluate(provider, action.replace(`${provider}.`, ''), { type: this.getResourceType(action) });
|
|
1803
|
-
if (!policyResult.allowed) {
|
|
1804
|
-
denied.push(action);
|
|
1805
|
-
continue;
|
|
1806
|
-
}
|
|
1807
|
-
// Try VC acquisition (steps 1-3 only, no terminal prompt for batch)
|
|
1808
|
-
try {
|
|
1809
|
-
const walletVC = this.wallet.findCredential(this.context.agentDid, action, this.context.projectId);
|
|
1810
|
-
if (walletVC) {
|
|
1811
|
-
approved.push(action);
|
|
1887
|
+
if ((0, executor_registry_1.isLocalAction)(action)) {
|
|
1888
|
+
const policyResult = this.policyEvaluator.evaluate(provider, action.replace(`${provider}.`, ''), { type: this.getResourceType(action) });
|
|
1889
|
+
if (!policyResult.allowed) {
|
|
1890
|
+
denied.push(action);
|
|
1812
1891
|
continue;
|
|
1813
1892
|
}
|
|
1814
|
-
// Try auto-issue
|
|
1815
|
-
const autoResult = await this.gatewayClient.autoIssueVC({
|
|
1816
|
-
subjectDid: this.context.agentDid,
|
|
1817
|
-
projectId: this.context.projectId,
|
|
1818
|
-
actions: [action],
|
|
1819
|
-
});
|
|
1820
|
-
if (autoResult?.autoIssued && autoResult.credential) {
|
|
1821
|
-
this.wallet.storeCredential({
|
|
1822
|
-
holderDid: this.context.agentDid,
|
|
1823
|
-
projectId: this.context.projectId,
|
|
1824
|
-
credentialJwt: autoResult.credential.jwt,
|
|
1825
|
-
actions: autoResult.actions || [action],
|
|
1826
|
-
provider,
|
|
1827
|
-
expiresAt: autoResult.credential.expiresAt,
|
|
1828
|
-
resources: (0, wallet_1.validateResources)(autoResult.resources),
|
|
1829
|
-
metadata: autoResult.metadata,
|
|
1830
|
-
});
|
|
1831
|
-
approved.push(action);
|
|
1832
|
-
continue;
|
|
1833
|
-
}
|
|
1834
|
-
pending.push(action);
|
|
1835
|
-
}
|
|
1836
|
-
catch {
|
|
1837
|
-
pending.push(action);
|
|
1838
1893
|
}
|
|
1894
|
+
callDirectly.push(action);
|
|
1839
1895
|
}
|
|
1840
|
-
const allApproved = denied.length === 0 && pending.length === 0 && callDirectly.length === 0;
|
|
1841
1896
|
const callDirectlyNote = callDirectly.length > 0
|
|
1842
1897
|
? ` No pre-approval for [${callDirectly.join(', ')}]: call aidentity_call_tool directly; if the owner ` +
|
|
1843
1898
|
`must approve, it answers status "pending" with a request_id, read later with aidentity_get_result.`
|
|
1844
1899
|
: '';
|
|
1845
|
-
// Create approval URL for pending actions (matches remote-mcp behavior)
|
|
1846
|
-
if (pending.length > 0) {
|
|
1847
|
-
try {
|
|
1848
|
-
const approvalResult = await this.gatewayClient.createApprovalRequest({
|
|
1849
|
-
subjectDid: this.context.agentDid,
|
|
1850
|
-
projectId: this.context.projectId,
|
|
1851
|
-
actions: pending,
|
|
1852
|
-
});
|
|
1853
|
-
if (!approvalResult.approvalUrl) {
|
|
1854
|
-
throw new Error('Gateway returned empty approval URL');
|
|
1855
|
-
}
|
|
1856
|
-
return {
|
|
1857
|
-
success: true,
|
|
1858
|
-
data: {
|
|
1859
|
-
approved,
|
|
1860
|
-
denied,
|
|
1861
|
-
pending,
|
|
1862
|
-
...(callDirectly.length > 0 ? { callDirectly } : {}),
|
|
1863
|
-
requestId: approvalResult.requestId,
|
|
1864
|
-
approvalUrl: approvalResult.approvalUrl,
|
|
1865
|
-
expiresAt: approvalResult.expiresAt,
|
|
1866
|
-
status: 'pending',
|
|
1867
|
-
message: approved.length > 0
|
|
1868
|
-
? `Approved: [${approved.join(', ')}]. Approval required for: [${pending.join(', ')}]. See approvalUrl field.` +
|
|
1869
|
-
callDirectlyNote
|
|
1870
|
-
: `Permission required for: [${pending.join(', ')}]. See approvalUrl field.` +
|
|
1871
|
-
callDirectlyNote,
|
|
1872
|
-
},
|
|
1873
|
-
};
|
|
1874
|
-
}
|
|
1875
|
-
catch (err) {
|
|
1876
|
-
// Fallback: return pending without URL if approval request creation fails
|
|
1877
|
-
return {
|
|
1878
|
-
success: true,
|
|
1879
|
-
data: {
|
|
1880
|
-
approved,
|
|
1881
|
-
denied,
|
|
1882
|
-
pending,
|
|
1883
|
-
...(callDirectly.length > 0 ? { callDirectly } : {}),
|
|
1884
|
-
status: 'partial',
|
|
1885
|
-
message: `Approved: [${approved.join(', ')}]. Pending: [${pending.join(', ')}]. Denied: [${denied.join(', ')}]. Failed to create approval URL: ${err instanceof Error ? err.message : String(err)}. Use aidentity_call_tool for pending actions â you will be prompted to approve.${callDirectlyNote}`,
|
|
1886
|
-
},
|
|
1887
|
-
};
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
1900
|
return {
|
|
1891
1901
|
success: true,
|
|
1892
1902
|
data: {
|
|
@@ -1894,11 +1904,9 @@ class ExecutionEngine {
|
|
|
1894
1904
|
denied,
|
|
1895
1905
|
pending,
|
|
1896
1906
|
...(callDirectly.length > 0 ? { callDirectly } : {}),
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
: `Approved: [${approved.join(', ')}]. Denied: [${denied.join(', ')}].` +
|
|
1901
|
-
callDirectlyNote,
|
|
1907
|
+
// Nothing to call and nothing denied (an empty request) is the only "approved".
|
|
1908
|
+
status: denied.length === 0 && callDirectly.length === 0 ? 'approved' : 'partial',
|
|
1909
|
+
message: `Approved: [${approved.join(', ')}]. Denied: [${denied.join(', ')}].` + callDirectlyNote,
|
|
1902
1910
|
},
|
|
1903
1911
|
};
|
|
1904
1912
|
}
|