evolcore 0.0.29 → 0.0.30
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/CHANGELOG.md +7 -0
- package/dist/agents/codex-runner.js +61 -14
- package/dist/aun/aid/agentmd.js +224 -19
- package/dist/aun/aid/index.js +2 -1
- package/dist/aun/aid/managed-operation.js +70 -4
- package/dist/aun/group/index.js +1 -0
- package/dist/{core → aun}/group/invite-service.js +4 -4
- package/dist/channels/daemon.js +1 -1
- package/dist/cli/agent-command.js +7 -7
- package/dist/cli/aun-commands.js +97 -37
- package/dist/cli/data-command.js +2 -1
- package/dist/cli/managed-command-guard.js +2 -2
- package/dist/cli/model.js +1 -1
- package/dist/cli/response.js +1 -1
- package/dist/cli/trigger-command.js +52 -29
- package/dist/config/boot-log.js +95 -1
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/peer-role-resolver.js +21 -0
- package/dist/core/agent-ipc-registration.js +409 -0
- package/dist/core/agent-runtime.js +435 -0
- package/dist/core/auth/delegation-authorization.js +58 -0
- package/dist/core/auth/operation-catalog.js +8 -0
- package/dist/core/bootstrap-service.js +65 -1
- package/dist/core/channel-runtime.js +435 -0
- package/dist/core/command/command-handler.js +4 -1
- package/dist/core/daemon-bootstrap.js +151 -0
- package/dist/core/daemon-control.js +205 -0
- package/dist/core/daemon-lifecycle.js +225 -0
- package/dist/core/data-migration.js +4 -1
- package/dist/core/handoff/ipc-registration.js +156 -0
- package/dist/core/ipc-registration.js +457 -0
- package/dist/core/memory/consolidation-trigger.js +8 -0
- package/dist/core/memory/consolidation.js +838 -0
- package/dist/core/message/aun-ipc-sender.js +226 -0
- package/dist/core/message/outbound.js +165 -0
- package/dist/core/permission/approval-gateway.js +13 -0
- package/dist/core/permission/ec-command-parser.js +80 -35
- package/dist/core/permission/sandbox-runtime.js +23 -2
- package/dist/core/permission/tool-error-code.js +1 -0
- package/dist/core/permission/tool-policy.js +61 -24
- package/dist/core/session/session-idle-monitor.js +17 -0
- package/dist/index.js +352 -4841
- package/dist/ipc.js +2 -1
- package/dist/stats/db.js +24 -0
- package/dist/stats/index.js +1 -1
- package/dist/stats/writer.js +25 -1
- package/dist/trigger/application-service.js +157 -0
- package/dist/trigger/authorization.js +371 -0
- package/dist/trigger/ipc-service.js +406 -0
- package/dist/trigger/local-files.js +133 -0
- package/dist/trigger/manager.js +235 -22
- package/dist/trigger/scheduler.js +30 -5
- package/dist/trigger/script-executor.js +176 -39
- package/dist/trigger/script-sandbox.js +458 -0
- package/dist/trigger/system-definitions.js +188 -0
- package/dist/trigger/validation.js +0 -3
- package/dist/utils/aid-bind.js +1 -1
- package/dist/utils/evolcore-version.js +74 -0
- package/dist/utils/logger.js +16 -0
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/model.md +3 -2
- package/kits/docs/evolcore/rpc.md +4 -0
- package/kits/docs/evolcore/trigger.md +15 -1
- package/kits/schemas/relation-config.schema.9.json +1 -1
- package/kits/templates/system-fragments/commands.md +0 -1
- package/package.json +1 -1
- package/dist/core/memory/launch-consolidation.js +0 -395
package/dist/trigger/manager.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import crypto from 'crypto';
|
|
3
4
|
import { agentTriggersDir } from '../paths.js';
|
|
4
5
|
import { assertExplicitAunDeliveryRoutes, definitionRevision, normalizeTriggerDefinition, resolveScriptPath, safeRelativePath, } from './validation.js';
|
|
5
|
-
import { atomicWriteJson } from '../core/session/session-fs-store.js';
|
|
6
6
|
import { TriggerHistoryStore } from './history.js';
|
|
7
|
+
import { decodeTriggerScriptFile } from './local-files.js';
|
|
7
8
|
export class TriggerDefinitionManager {
|
|
8
9
|
agentAid;
|
|
9
10
|
rootDir;
|
|
@@ -12,6 +13,7 @@ export class TriggerDefinitionManager {
|
|
|
12
13
|
this.agentAid = agentAid;
|
|
13
14
|
this.rootDir = rootDir;
|
|
14
15
|
fs.mkdirSync(this.rootDir, { recursive: true });
|
|
16
|
+
assertRealDirectory(this.rootDir, 'Trigger root');
|
|
15
17
|
this.history = new TriggerHistoryStore(rootDir, agentAid);
|
|
16
18
|
for (const definition of this.list({ all: true })) {
|
|
17
19
|
this.history.ensureDefinitionSnapshot(definition);
|
|
@@ -63,9 +65,16 @@ export class TriggerDefinitionManager {
|
|
|
63
65
|
if (fs.existsSync(dir))
|
|
64
66
|
throw new Error(`trigger directory already exists: ${definition.id}`);
|
|
65
67
|
fs.mkdirSync(dir, { recursive: true });
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
try {
|
|
69
|
+
this.writeFiles(dir, files, definition, () => {
|
|
70
|
+
this.validateScriptFile(definition, dir);
|
|
71
|
+
this.writeDefinition(definition);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
69
78
|
this.clearActive(definition.id);
|
|
70
79
|
this.history.recordDefinition('trigger.created', definition);
|
|
71
80
|
return definition;
|
|
@@ -91,9 +100,10 @@ export class TriggerDefinitionManager {
|
|
|
91
100
|
this.assertUnique(updated, triggerId);
|
|
92
101
|
const dir = this.triggerDir(triggerId);
|
|
93
102
|
fs.mkdirSync(dir, { recursive: true });
|
|
94
|
-
this.writeFiles(dir, files)
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
this.writeFiles(dir, files, updated, () => {
|
|
104
|
+
this.validateScriptFile(updated, dir);
|
|
105
|
+
this.writeDefinition(updated);
|
|
106
|
+
});
|
|
97
107
|
this.history.recordDefinition('trigger.updated', updated, {
|
|
98
108
|
previousRevision: definitionRevision(existing),
|
|
99
109
|
});
|
|
@@ -119,7 +129,7 @@ export class TriggerDefinitionManager {
|
|
|
119
129
|
return definition;
|
|
120
130
|
}
|
|
121
131
|
triggerDir(triggerId) {
|
|
122
|
-
return path.join(this.rootDir,
|
|
132
|
+
return path.join(this.rootDir, safeTriggerId(triggerId));
|
|
123
133
|
}
|
|
124
134
|
definitionPath(triggerId) {
|
|
125
135
|
return path.join(this.triggerDir(triggerId), 'trigger.json');
|
|
@@ -191,7 +201,25 @@ export class TriggerDefinitionManager {
|
|
|
191
201
|
writeDefinition(definition) {
|
|
192
202
|
const dir = this.triggerDir(definition.id);
|
|
193
203
|
fs.mkdirSync(dir, { recursive: true });
|
|
194
|
-
|
|
204
|
+
assertSafeDirectoryPath(this.rootDir, dir);
|
|
205
|
+
const target = this.definitionPath(definition.id);
|
|
206
|
+
const existing = lstatOptional(target);
|
|
207
|
+
if (existing && (!existing.isFile() || existing.isSymbolicLink() || existing.nlink !== 1)) {
|
|
208
|
+
throw new Error('Trigger definition target must be a regular, unlinked file');
|
|
209
|
+
}
|
|
210
|
+
const temporary = path.join(dir, `.ec-trigger-definition-${crypto.randomBytes(12).toString('hex')}.tmp`);
|
|
211
|
+
try {
|
|
212
|
+
writeNewFile(temporary, JSON.stringify(definition, null, 2) + '\n');
|
|
213
|
+
assertSafeDirectoryPath(this.rootDir, dir);
|
|
214
|
+
assertUnchangedTarget(target, existing);
|
|
215
|
+
fs.renameSync(temporary, target);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
try {
|
|
219
|
+
fs.unlinkSync(temporary);
|
|
220
|
+
}
|
|
221
|
+
catch { }
|
|
222
|
+
}
|
|
195
223
|
}
|
|
196
224
|
listTriggerIds() {
|
|
197
225
|
let entries;
|
|
@@ -230,28 +258,98 @@ export class TriggerDefinitionManager {
|
|
|
230
258
|
const record = triggers[triggerId];
|
|
231
259
|
return isRecord(record) ? record : undefined;
|
|
232
260
|
}
|
|
233
|
-
writeFiles(dir, files) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
261
|
+
writeFiles(dir, files, definition, afterWrite) {
|
|
262
|
+
if (!Array.isArray(files) || files.length > 1)
|
|
263
|
+
throw new Error('a Trigger can upload only its configured script file');
|
|
264
|
+
if (files.length === 0) {
|
|
265
|
+
afterWrite();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (definition.execution.type !== 'script' || !definition.execution.script) {
|
|
269
|
+
throw new Error('uploaded Trigger files require execution.type=script');
|
|
270
|
+
}
|
|
271
|
+
assertRealDirectory(dir, 'Trigger directory');
|
|
272
|
+
const expectedRelative = safeScriptRelativePath(definition.execution.script.path);
|
|
273
|
+
const file = files[0];
|
|
274
|
+
if (!file || typeof file !== 'object')
|
|
275
|
+
throw new Error('invalid Trigger script upload');
|
|
276
|
+
const relative = safeScriptRelativePath(file.relativePath);
|
|
277
|
+
const normalize = (value) => process.platform === 'win32' ? value.toLowerCase() : value;
|
|
278
|
+
if (normalize(relative) !== normalize(expectedRelative)) {
|
|
279
|
+
throw new Error('uploaded file must match execution.script.path');
|
|
280
|
+
}
|
|
281
|
+
const contents = decodeTriggerScriptFile(file.contentBase64);
|
|
282
|
+
const target = path.resolve(dir, relative);
|
|
283
|
+
assertPathWithinDirectory(dir, target);
|
|
284
|
+
const parent = ensureSafeDirectoryPath(dir, path.dirname(target));
|
|
285
|
+
const existing = lstatOptional(target);
|
|
286
|
+
if (existing && (!existing.isFile() || existing.isSymbolicLink() || existing.nlink !== 1)) {
|
|
287
|
+
throw new Error('Trigger script target must be a regular, unlinked file');
|
|
288
|
+
}
|
|
289
|
+
const temporary = path.join(parent, `.ec-trigger-upload-${crypto.randomBytes(12).toString('hex')}.tmp`);
|
|
290
|
+
const backup = path.join(parent, `.ec-trigger-rollback-${crypto.randomBytes(12).toString('hex')}.tmp`);
|
|
291
|
+
let backedUp = false;
|
|
292
|
+
let installed = false;
|
|
293
|
+
let installedFile;
|
|
294
|
+
let committed = false;
|
|
295
|
+
try {
|
|
296
|
+
writeNewFile(temporary, contents);
|
|
297
|
+
assertSafeDirectoryPath(dir, parent);
|
|
298
|
+
assertUnchangedTarget(target, existing);
|
|
299
|
+
if (existing) {
|
|
300
|
+
fs.copyFileSync(target, backup, fs.constants.COPYFILE_EXCL);
|
|
301
|
+
backedUp = true;
|
|
302
|
+
assertUnchangedTarget(target, existing);
|
|
303
|
+
}
|
|
304
|
+
fs.renameSync(temporary, target);
|
|
305
|
+
installed = true;
|
|
306
|
+
installedFile = fs.lstatSync(target);
|
|
307
|
+
afterWrite();
|
|
308
|
+
committed = true;
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
if (installed) {
|
|
312
|
+
try {
|
|
313
|
+
assertSafeDirectoryPath(dir, parent);
|
|
314
|
+
assertUnchangedTarget(target, installedFile);
|
|
315
|
+
fs.unlinkSync(target);
|
|
316
|
+
if (backedUp) {
|
|
317
|
+
fs.renameSync(backup, target);
|
|
318
|
+
backedUp = false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (rollbackError) {
|
|
322
|
+
throw new AggregateError([error, rollbackError], 'Trigger script update failed and the previous file could not be restored');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
finally {
|
|
328
|
+
try {
|
|
329
|
+
fs.unlinkSync(temporary);
|
|
330
|
+
}
|
|
331
|
+
catch { }
|
|
332
|
+
if (backedUp && (committed || !installed)) {
|
|
333
|
+
try {
|
|
334
|
+
fs.unlinkSync(backup);
|
|
335
|
+
}
|
|
336
|
+
catch { }
|
|
240
337
|
}
|
|
241
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
242
|
-
fs.writeFileSync(target, Buffer.from(file.contentBase64, 'base64'));
|
|
243
338
|
}
|
|
244
339
|
}
|
|
245
340
|
validateScriptFile(definition, dir) {
|
|
246
341
|
if (definition.execution.type !== 'script')
|
|
247
342
|
return;
|
|
248
|
-
const
|
|
343
|
+
const relative = safeScriptRelativePath(definition.execution.script.path);
|
|
344
|
+
const scriptAbs = resolveScriptPath(dir, relative);
|
|
249
345
|
if (!fs.existsSync(scriptAbs)) {
|
|
250
346
|
throw new Error(`script file not found: ${definition.execution.script.path}`);
|
|
251
347
|
}
|
|
252
|
-
const stat = fs.
|
|
253
|
-
if (!stat.isFile())
|
|
254
|
-
throw new Error(`script.path
|
|
348
|
+
const stat = fs.lstatSync(scriptAbs);
|
|
349
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1) {
|
|
350
|
+
throw new Error(`script.path must be a regular unlinked file: ${definition.execution.script.path}`);
|
|
351
|
+
}
|
|
352
|
+
assertSafeDirectoryPath(dir, path.dirname(scriptAbs));
|
|
255
353
|
}
|
|
256
354
|
assertAgent(definition) {
|
|
257
355
|
if (definition.agentAid !== this.agentAid) {
|
|
@@ -269,6 +367,121 @@ export class TriggerDefinitionManager {
|
|
|
269
367
|
}
|
|
270
368
|
}
|
|
271
369
|
}
|
|
370
|
+
const RESERVED_TRIGGER_FILES = new Set([
|
|
371
|
+
'trigger.json',
|
|
372
|
+
'active.json',
|
|
373
|
+
'history.jsonl',
|
|
374
|
+
'schedule.json',
|
|
375
|
+
'limits.json',
|
|
376
|
+
]);
|
|
377
|
+
function safeTriggerId(value) {
|
|
378
|
+
if (typeof value !== 'string' || !value || value.includes('/') || value.includes('\\')
|
|
379
|
+
|| value.includes(':') || value.includes('\0') || value === '.' || value === '..') {
|
|
380
|
+
throw new Error(`invalid Trigger ID: ${value}`);
|
|
381
|
+
}
|
|
382
|
+
const normalized = safeRelativePath(value);
|
|
383
|
+
if (normalized.includes('/') || normalized.includes('\\') || normalized.includes(':')
|
|
384
|
+
|| normalized.endsWith('.') || normalized.endsWith(' ')) {
|
|
385
|
+
throw new Error(`invalid Trigger ID: ${value}`);
|
|
386
|
+
}
|
|
387
|
+
if (/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(normalized)) {
|
|
388
|
+
throw new Error(`invalid Trigger ID: ${value}`);
|
|
389
|
+
}
|
|
390
|
+
return normalized;
|
|
391
|
+
}
|
|
392
|
+
function assertPathWithinDirectory(root, candidate) {
|
|
393
|
+
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
394
|
+
if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
395
|
+
throw new Error(`file escapes Trigger directory: ${candidate}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
function lstatOptional(value) {
|
|
399
|
+
try {
|
|
400
|
+
return fs.lstatSync(value);
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
if (error?.code === 'ENOENT')
|
|
404
|
+
return undefined;
|
|
405
|
+
throw error;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function writeNewFile(target, contents) {
|
|
409
|
+
const descriptor = fs.openSync(target, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, 0o600);
|
|
410
|
+
try {
|
|
411
|
+
fs.writeFileSync(descriptor, contents);
|
|
412
|
+
fs.fsyncSync(descriptor);
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
fs.closeSync(descriptor);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function assertUnchangedTarget(target, expected) {
|
|
419
|
+
const current = lstatOptional(target);
|
|
420
|
+
if (!expected && current)
|
|
421
|
+
throw new Error('Trigger file target appeared during update');
|
|
422
|
+
if (expected && (!current || !current.isFile() || current.isSymbolicLink() || current.nlink !== 1
|
|
423
|
+
|| current.dev !== expected.dev || current.ino !== expected.ino || current.size !== expected.size
|
|
424
|
+
|| current.mtimeMs !== expected.mtimeMs || current.ctimeMs !== expected.ctimeMs)) {
|
|
425
|
+
throw new Error('Trigger file target changed during update');
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function assertRealDirectory(value, label) {
|
|
429
|
+
const stat = fs.lstatSync(value);
|
|
430
|
+
const canonical = fs.realpathSync.native(value);
|
|
431
|
+
const lexical = path.resolve(value);
|
|
432
|
+
const equal = process.platform === 'win32'
|
|
433
|
+
? canonical.toLowerCase() === lexical.toLowerCase()
|
|
434
|
+
: canonical === lexical;
|
|
435
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || !equal) {
|
|
436
|
+
throw new Error(`${label} must not be a symbolic link or junction`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function ensureSafeDirectoryPath(root, target) {
|
|
440
|
+
const absoluteRoot = path.resolve(root);
|
|
441
|
+
const absoluteTarget = path.resolve(target);
|
|
442
|
+
if (absoluteTarget !== absoluteRoot)
|
|
443
|
+
assertPathWithinDirectory(absoluteRoot, absoluteTarget);
|
|
444
|
+
const relative = path.relative(absoluteRoot, absoluteTarget);
|
|
445
|
+
let current = absoluteRoot;
|
|
446
|
+
assertRealDirectory(current, 'Trigger directory');
|
|
447
|
+
for (const segment of relative.split(path.sep).filter(Boolean)) {
|
|
448
|
+
current = path.join(current, segment);
|
|
449
|
+
try {
|
|
450
|
+
fs.mkdirSync(current);
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
if (error?.code !== 'EEXIST')
|
|
454
|
+
throw error;
|
|
455
|
+
}
|
|
456
|
+
assertRealDirectory(current, 'Trigger script parent');
|
|
457
|
+
}
|
|
458
|
+
return current;
|
|
459
|
+
}
|
|
460
|
+
function assertSafeDirectoryPath(root, target) {
|
|
461
|
+
const absoluteRoot = path.resolve(root);
|
|
462
|
+
const absoluteTarget = path.resolve(target);
|
|
463
|
+
if (absoluteTarget !== absoluteRoot)
|
|
464
|
+
assertPathWithinDirectory(absoluteRoot, absoluteTarget);
|
|
465
|
+
let current = absoluteRoot;
|
|
466
|
+
assertRealDirectory(current, 'Trigger directory');
|
|
467
|
+
for (const segment of path.relative(absoluteRoot, absoluteTarget).split(path.sep).filter(Boolean)) {
|
|
468
|
+
current = path.join(current, segment);
|
|
469
|
+
assertRealDirectory(current, 'Trigger script parent');
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function safeScriptRelativePath(value) {
|
|
473
|
+
if (typeof value !== 'string' || /[\0\r\n:<>"|?*]/.test(value)
|
|
474
|
+
|| value.replace(/\\/g, '/').split('/').some(segment => segment === '..'
|
|
475
|
+
|| (/[. ]$/.test(segment) && segment !== '.')
|
|
476
|
+
|| /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(segment))) {
|
|
477
|
+
throw new Error('invalid Trigger script relative path');
|
|
478
|
+
}
|
|
479
|
+
const relative = safeRelativePath(value);
|
|
480
|
+
if (relative.split('/').some(segment => RESERVED_TRIGGER_FILES.has(segment.toLowerCase()))) {
|
|
481
|
+
throw new Error('script path conflicts with reserved Trigger state');
|
|
482
|
+
}
|
|
483
|
+
return relative;
|
|
484
|
+
}
|
|
272
485
|
function optionalString(value) {
|
|
273
486
|
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
274
487
|
}
|
|
@@ -758,6 +758,27 @@ export class TriggerRuntimeScheduler {
|
|
|
758
758
|
}
|
|
759
759
|
async runRecordedExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt, previousAttempt) {
|
|
760
760
|
const attemptId = `${runId}:attempt:${attempt}`;
|
|
761
|
+
const executionAuthorization = this.runtime.authorizeExecution?.(definition);
|
|
762
|
+
if (executionAuthorization && !executionAuthorization.allowed) {
|
|
763
|
+
const reply = errorReply(runId, 0, 'authorization_denied', executionAuthorization.reason || 'Trigger execution authorization denied');
|
|
764
|
+
const execution = {
|
|
765
|
+
script: null,
|
|
766
|
+
processing: { mode: definition.execution.type },
|
|
767
|
+
reply,
|
|
768
|
+
};
|
|
769
|
+
if (!dryRun) {
|
|
770
|
+
this.state.startExecutionAttempt?.(definition.id, runId, {
|
|
771
|
+
attempt,
|
|
772
|
+
attemptId,
|
|
773
|
+
startedAt: Date.now(),
|
|
774
|
+
});
|
|
775
|
+
this.state.completeExecutionAttempt?.(definition.id, runId, attemptId, {
|
|
776
|
+
status: 'failed',
|
|
777
|
+
error: { code: 'authorization_denied', message: reply.error?.text || 'Trigger execution authorization denied' },
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
return execution;
|
|
781
|
+
}
|
|
761
782
|
if (!dryRun) {
|
|
762
783
|
this.state.startExecutionAttempt?.(definition.id, runId, {
|
|
763
784
|
attempt,
|
|
@@ -766,7 +787,7 @@ export class TriggerRuntimeScheduler {
|
|
|
766
787
|
});
|
|
767
788
|
}
|
|
768
789
|
try {
|
|
769
|
-
const execution = await this.runExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt, previousAttempt);
|
|
790
|
+
const execution = await this.runExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt, previousAttempt, executionAuthorization);
|
|
770
791
|
if (!dryRun) {
|
|
771
792
|
const summary = attemptSummaryFromExecution(attempt, attemptId, execution);
|
|
772
793
|
this.state.completeExecutionAttempt?.(definition.id, runId, attemptId, summary);
|
|
@@ -783,7 +804,7 @@ export class TriggerRuntimeScheduler {
|
|
|
783
804
|
throw error;
|
|
784
805
|
}
|
|
785
806
|
}
|
|
786
|
-
async runExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt = 1, previousAttempt) {
|
|
807
|
+
async runExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt = 1, previousAttempt, executionAuthorization) {
|
|
787
808
|
if (signal.aborted) {
|
|
788
809
|
return {
|
|
789
810
|
script: null,
|
|
@@ -792,7 +813,7 @@ export class TriggerRuntimeScheduler {
|
|
|
792
813
|
};
|
|
793
814
|
}
|
|
794
815
|
if (definition.execution.type === 'script') {
|
|
795
|
-
const script = await this.runScriptOnce(definition, runId, firedAt, sourcePayload, signal);
|
|
816
|
+
const script = await this.runScriptOnce(definition, runId, firedAt, sourcePayload, signal, executionAuthorization);
|
|
796
817
|
const processing = {
|
|
797
818
|
mode: 'script',
|
|
798
819
|
scriptPath: definition.execution.script?.path,
|
|
@@ -961,13 +982,15 @@ export class TriggerRuntimeScheduler {
|
|
|
961
982
|
};
|
|
962
983
|
}
|
|
963
984
|
}
|
|
964
|
-
async runScriptOnce(definition, runId, firedAt, sourcePayload, signal) {
|
|
985
|
+
async runScriptOnce(definition, runId, firedAt, sourcePayload, signal, executionAuthorization) {
|
|
965
986
|
return await this.scriptExecutor.execute({
|
|
966
987
|
trigger: definition,
|
|
967
988
|
triggerDir: this.manager.triggerDir(definition.id),
|
|
968
989
|
runId,
|
|
969
990
|
firedAt,
|
|
970
991
|
sourcePayload,
|
|
992
|
+
projectPath: this.runtime.projectPath,
|
|
993
|
+
executionAuthorization,
|
|
971
994
|
signal,
|
|
972
995
|
});
|
|
973
996
|
}
|
|
@@ -1906,7 +1929,9 @@ function branchFromReply(reply) {
|
|
|
1906
1929
|
return 'onFailure';
|
|
1907
1930
|
}
|
|
1908
1931
|
function shouldRetryExecution(reply) {
|
|
1909
|
-
return reply.outcome === 'error'
|
|
1932
|
+
return reply.outcome === 'error'
|
|
1933
|
+
? reply.error?.reason !== 'authorization_denied'
|
|
1934
|
+
: reply.outcome === 'timeout' || reply.outcome === 'interrupted';
|
|
1910
1935
|
}
|
|
1911
1936
|
function triggerCancellationReason(signal) {
|
|
1912
1937
|
const reason = signal.reason instanceof Error
|