@astrasyncai/verification-gateway 3.10.0 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-interface/interface.d.mts +1 -1
- package/dist/adapter-interface/interface.d.ts +1 -1
- package/dist/adapters/express.js +1 -1
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +1 -1
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.js +1 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +1 -1
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.js +1 -1
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +1 -1
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.js +1 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +1 -1
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +317 -35
- package/dist/bin/astrasync-codex-hook.js +5107 -0
- package/dist/bin/astrasync-guard.js +430 -40
- package/dist/bin/astrasync.js +453 -41
- package/dist/browser/background.js +279 -24
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +279 -24
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +1 -1
- package/dist/browser/browser-adapter.d.ts +1 -1
- package/dist/claude-code/claude-code-adapter.d.mts +1 -1
- package/dist/claude-code/claude-code-adapter.d.ts +1 -1
- package/dist/claude-code/claude-code-adapter.js +9 -1
- package/dist/claude-code/claude-code-adapter.js.map +1 -1
- package/dist/claude-code/claude-code-adapter.mjs +9 -1
- package/dist/claude-code/claude-code-adapter.mjs.map +1 -1
- package/dist/cli/index.d.mts +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/codex/index.d.mts +230 -0
- package/dist/codex/index.d.ts +230 -0
- package/dist/codex/index.js +5225 -0
- package/dist/codex/index.js.map +1 -0
- package/dist/codex/index.mjs +5197 -0
- package/dist/codex/index.mjs.map +1 -0
- package/dist/cursor/cursor-adapter.d.mts +1 -1
- package/dist/cursor/cursor-adapter.d.ts +1 -1
- package/dist/cursor/extension.d.mts +1 -1
- package/dist/cursor/extension.d.ts +1 -1
- package/dist/cursor/extension.js +279 -24
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +279 -24
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/gateway/gateway.d.mts +32 -2
- package/dist/gateway/gateway.d.ts +32 -2
- package/dist/gateway/gateway.js +279 -24
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +279 -24
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +1 -1
- package/dist/local-evaluator/evaluator.d.ts +1 -1
- package/dist/local-evaluator/evaluator.js +165 -7
- package/dist/local-evaluator/evaluator.js.map +1 -1
- package/dist/local-evaluator/evaluator.mjs +165 -7
- package/dist/local-evaluator/evaluator.mjs.map +1 -1
- package/dist/{types-D0lCtFQ7.d.mts → types-BV6abBnF.d.mts} +6 -0
- package/dist/{types-YbiXYKx1.d.ts → types-C23_uaY8.d.ts} +6 -0
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +1 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
|
@@ -261,7 +261,9 @@ var HIGH_RISK_COMMANDS = [
|
|
|
261
261
|
"git push",
|
|
262
262
|
"npm publish",
|
|
263
263
|
"docker",
|
|
264
|
-
"kubectl"
|
|
264
|
+
"kubectl",
|
|
265
|
+
"gh pr create",
|
|
266
|
+
"gh pr merge"
|
|
265
267
|
];
|
|
266
268
|
var SENSITIVE_PATHS = [
|
|
267
269
|
".ssh",
|
|
@@ -280,6 +282,164 @@ var SENSITIVE_PATHS = [
|
|
|
280
282
|
".pypirc"
|
|
281
283
|
];
|
|
282
284
|
|
|
285
|
+
// src/local-evaluator/command-matcher.ts
|
|
286
|
+
var WRAPPERS = /* @__PURE__ */ new Set([
|
|
287
|
+
"sudo",
|
|
288
|
+
"doas",
|
|
289
|
+
"env",
|
|
290
|
+
"nohup",
|
|
291
|
+
"time",
|
|
292
|
+
"timeout",
|
|
293
|
+
"nice",
|
|
294
|
+
"ionice",
|
|
295
|
+
"stdbuf",
|
|
296
|
+
"xargs",
|
|
297
|
+
"command",
|
|
298
|
+
"exec",
|
|
299
|
+
"builtin"
|
|
300
|
+
]);
|
|
301
|
+
var ASSIGN_RE = /^[a-z_][a-z0-9_]*=/;
|
|
302
|
+
var MAX_WRAPPER_HOPS = 4;
|
|
303
|
+
var MAX_RECURSION_DEPTH = 3;
|
|
304
|
+
var MAX_COMMAND_LENGTH = 1e5;
|
|
305
|
+
var LOCAL_HOST_RE = /^(localhost|127\.0\.0\.1|::1|[a-z0-9.-]*\.localhost)$/;
|
|
306
|
+
function buildRiskList(entries) {
|
|
307
|
+
const singleWord = /* @__PURE__ */ new Set();
|
|
308
|
+
const multiWord = [];
|
|
309
|
+
for (const entry of entries) {
|
|
310
|
+
const words = entry.toLowerCase().trim().split(/\s+/);
|
|
311
|
+
if (words.length === 1) singleWord.add(words[0]);
|
|
312
|
+
else multiWord.push(words);
|
|
313
|
+
}
|
|
314
|
+
multiWord.sort((a, b) => b.length - a.length);
|
|
315
|
+
return { singleWord, multiWord };
|
|
316
|
+
}
|
|
317
|
+
function stripHeredocBodies(text) {
|
|
318
|
+
const lines = text.split("\n");
|
|
319
|
+
const kept = [];
|
|
320
|
+
let terminator = null;
|
|
321
|
+
for (const line of lines) {
|
|
322
|
+
if (terminator !== null) {
|
|
323
|
+
if (line.trim() === terminator) terminator = null;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
kept.push(line);
|
|
327
|
+
const heredoc = line.match(/<<-?\s*['"]?(\w+)['"]?/);
|
|
328
|
+
if (heredoc) terminator = heredoc[1];
|
|
329
|
+
}
|
|
330
|
+
return kept.join("\n");
|
|
331
|
+
}
|
|
332
|
+
function extractDollarSubstitutions(text, collect) {
|
|
333
|
+
let result = text;
|
|
334
|
+
let start = result.indexOf("$(");
|
|
335
|
+
let iterations = 0;
|
|
336
|
+
while (start !== -1 && iterations < 50) {
|
|
337
|
+
iterations++;
|
|
338
|
+
let depth = 0;
|
|
339
|
+
let end = result.length;
|
|
340
|
+
for (let i = start + 1; i < result.length; i++) {
|
|
341
|
+
if (result[i] === "(") depth++;
|
|
342
|
+
else if (result[i] === ")") {
|
|
343
|
+
depth--;
|
|
344
|
+
if (depth === 0) {
|
|
345
|
+
end = i;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
collect(result.slice(start + 2, end));
|
|
351
|
+
result = `${result.slice(0, start)} ${result.slice(Math.min(end + 1, result.length))}`;
|
|
352
|
+
start = result.indexOf("$(");
|
|
353
|
+
}
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
function extractBacktickSubstitutions(text, collect) {
|
|
357
|
+
if (!text.includes("`")) return text;
|
|
358
|
+
const chunks = text.split("`");
|
|
359
|
+
const kept = [];
|
|
360
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
361
|
+
if (i % 2 === 1) collect(chunks[i]);
|
|
362
|
+
else kept.push(chunks[i]);
|
|
363
|
+
}
|
|
364
|
+
return kept.join(" ");
|
|
365
|
+
}
|
|
366
|
+
function basename(token) {
|
|
367
|
+
const slash = token.lastIndexOf("/");
|
|
368
|
+
return slash === -1 ? token : token.slice(slash + 1);
|
|
369
|
+
}
|
|
370
|
+
function matchSegment(segment, list) {
|
|
371
|
+
const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
|
|
372
|
+
let i = 0;
|
|
373
|
+
let hops = 0;
|
|
374
|
+
while (i < tokens.length) {
|
|
375
|
+
while (i < tokens.length && (tokens[i] === "export" || ASSIGN_RE.test(tokens[i]))) i++;
|
|
376
|
+
if (i >= tokens.length) return null;
|
|
377
|
+
const cmd = basename(tokens[i]);
|
|
378
|
+
const significant = [cmd, ...tokens.slice(i + 1).filter((t) => !t.startsWith("-"))];
|
|
379
|
+
for (const entry of list.multiWord) {
|
|
380
|
+
if (entry.length <= significant.length && entry.every((w, j) => significant[j] === w)) {
|
|
381
|
+
return entry.join(" ");
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (list.singleWord.has(cmd)) return cmd;
|
|
385
|
+
if (WRAPPERS.has(cmd) && hops < MAX_WRAPPER_HOPS) {
|
|
386
|
+
hops++;
|
|
387
|
+
i++;
|
|
388
|
+
while (i < tokens.length && (tokens[i].startsWith("-") || ASSIGN_RE.test(tokens[i]))) i++;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
function collectMatches(command, list, matches, depth) {
|
|
396
|
+
if (depth > MAX_RECURSION_DEPTH || command.length > MAX_COMMAND_LENGTH) return;
|
|
397
|
+
let text = command.toLowerCase();
|
|
398
|
+
text = stripHeredocBodies(text);
|
|
399
|
+
const recurse = (inner) => collectMatches(inner, list, matches, depth + 1);
|
|
400
|
+
text = extractDollarSubstitutions(text, recurse);
|
|
401
|
+
text = extractBacktickSubstitutions(text, recurse);
|
|
402
|
+
text = text.replace(/'[^']*'/g, " ").replace(/"[^"]*"/g, " ");
|
|
403
|
+
text = text.replace(/(^|\s)#[^\n]*/g, " ");
|
|
404
|
+
const segments = text.split(/\|\||&&|[;|&\n]|[({]/);
|
|
405
|
+
for (const segment of segments) {
|
|
406
|
+
const matched = matchSegment(segment, list);
|
|
407
|
+
if (matched) matches.add(matched);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function matchHighRiskCommands(command, highRiskCommands = HIGH_RISK_COMMANDS) {
|
|
411
|
+
if (!command) return [];
|
|
412
|
+
const matches = /* @__PURE__ */ new Set();
|
|
413
|
+
collectMatches(command, buildRiskList(highRiskCommands), matches, 0);
|
|
414
|
+
return [...matches];
|
|
415
|
+
}
|
|
416
|
+
function isLocalhostOnlyNetworkCommand(command) {
|
|
417
|
+
const text = command.toLowerCase();
|
|
418
|
+
const tokens = text.split(/\s+/).map((t) => t.replace(/^["'`]+|["'`,;)]+$/g, ""));
|
|
419
|
+
let localCount = 0;
|
|
420
|
+
for (const token of tokens) {
|
|
421
|
+
let host = null;
|
|
422
|
+
if (token.includes("://")) {
|
|
423
|
+
let rest = token.slice(token.indexOf("://") + 3);
|
|
424
|
+
const at = rest.indexOf("@");
|
|
425
|
+
if (at !== -1) rest = rest.slice(at + 1);
|
|
426
|
+
host = rest.split(/[/?#]/)[0];
|
|
427
|
+
} else if (/^[a-z0-9.[\]:-]+:\d+(\/.*)?$/.test(token)) {
|
|
428
|
+
host = token.split("/")[0];
|
|
429
|
+
} else if (/^(localhost|127\.0\.0\.1|\[?::1\]?)(\/.*)?$/.test(token)) {
|
|
430
|
+
host = token.split("/")[0];
|
|
431
|
+
}
|
|
432
|
+
if (host === null) continue;
|
|
433
|
+
const bare = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "");
|
|
434
|
+
if (LOCAL_HOST_RE.test(bare)) {
|
|
435
|
+
localCount++;
|
|
436
|
+
} else {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return localCount > 0;
|
|
441
|
+
}
|
|
442
|
+
|
|
283
443
|
// src/local-evaluator/evaluator.ts
|
|
284
444
|
var LocalEvaluator = class {
|
|
285
445
|
constructor(policy) {
|
|
@@ -430,12 +590,10 @@ var LocalEvaluator = class {
|
|
|
430
590
|
return score;
|
|
431
591
|
}
|
|
432
592
|
if (context.purpose === "shell.exec" && context.target) {
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
break;
|
|
438
|
-
}
|
|
593
|
+
const matched = matchHighRiskCommands(context.target);
|
|
594
|
+
const localProbeOnly = matched.length > 0 && matched.every((cmd) => cmd === "curl" || cmd === "wget") && isLocalhostOnlyNetworkCommand(context.target);
|
|
595
|
+
if (matched.length > 0 && !localProbeOnly) {
|
|
596
|
+
score = Math.max(score, 80);
|
|
439
597
|
}
|
|
440
598
|
}
|
|
441
599
|
if ((context.purpose === "file.read" || context.purpose === "file.write" || context.purpose === "file.delete") && context.target) {
|
|
@@ -3746,7 +3904,7 @@ function getTrustLevel(score) {
|
|
|
3746
3904
|
}
|
|
3747
3905
|
|
|
3748
3906
|
// src/version.ts
|
|
3749
|
-
var SDK_VERSION = "3.
|
|
3907
|
+
var SDK_VERSION = "3.11.0";
|
|
3750
3908
|
|
|
3751
3909
|
// src/well-known.ts
|
|
3752
3910
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -4264,10 +4422,12 @@ function toGatewayConfig(config) {
|
|
|
4264
4422
|
};
|
|
4265
4423
|
}
|
|
4266
4424
|
function toVerificationRequest(context, astraId) {
|
|
4425
|
+
const dotIndex = context.purpose.indexOf(".");
|
|
4426
|
+
const dotted = dotIndex > 0;
|
|
4267
4427
|
return {
|
|
4268
4428
|
credentials: { astraId },
|
|
4269
|
-
purpose: context.purpose,
|
|
4270
|
-
action: context.action,
|
|
4429
|
+
purpose: dotted ? context.purpose.slice(0, dotIndex) : context.purpose,
|
|
4430
|
+
action: dotted ? context.purpose : context.action,
|
|
4271
4431
|
resourceType: context.resourceType,
|
|
4272
4432
|
resource: context.target,
|
|
4273
4433
|
transactionValue: context.transactionValue,
|
|
@@ -4307,8 +4467,75 @@ async function verifyOnline(config, context, astraId) {
|
|
|
4307
4467
|
// src/gateway/modes/hybrid.ts
|
|
4308
4468
|
import { existsSync, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
4309
4469
|
import { dirname } from "path";
|
|
4470
|
+
|
|
4471
|
+
// src/gateway/redact.ts
|
|
4472
|
+
var marker = (type2) => `[REDACTED:${type2}]`;
|
|
4473
|
+
var REDACTION_PATTERNS = [
|
|
4474
|
+
// Multi-line blocks first so later single-line patterns don't shred them.
|
|
4475
|
+
{
|
|
4476
|
+
type: "private-key",
|
|
4477
|
+
re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g
|
|
4478
|
+
},
|
|
4479
|
+
// URL userinfo credentials (https://user:pass@, x-access-token:ghp_…@).
|
|
4480
|
+
{
|
|
4481
|
+
type: "url-credentials",
|
|
4482
|
+
re: /([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi,
|
|
4483
|
+
replacement: `$1${marker("url-credentials")}@`
|
|
4484
|
+
},
|
|
4485
|
+
// Known token formats.
|
|
4486
|
+
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{20,255}\b/g },
|
|
4487
|
+
{ type: "github-token", re: /\bgithub_pat_[A-Za-z0-9_]{20,255}\b/g },
|
|
4488
|
+
{ type: "astrasync-key", re: /\bkya_[A-Fa-f0-9]{32,128}\b/g },
|
|
4489
|
+
{ type: "openai-key", re: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
|
|
4490
|
+
{ type: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b/g },
|
|
4491
|
+
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
|
|
4492
|
+
// Bearer/token headers.
|
|
4493
|
+
{
|
|
4494
|
+
type: "bearer-token",
|
|
4495
|
+
re: /\b(bearer\s+)[a-z0-9._~+/=-]{16,}/gi,
|
|
4496
|
+
replacement: `$1${marker("bearer-token")}`
|
|
4497
|
+
},
|
|
4498
|
+
// Generic KEY=value / key: value assignments with secret-ish names.
|
|
4499
|
+
{
|
|
4500
|
+
type: "assigned-secret",
|
|
4501
|
+
re: /\b((?:password|passwd|secret|token|api[_-]?key|apikey|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[=:]\s*)(['"]?)[^\s'"&;]{8,}\2/gi,
|
|
4502
|
+
replacement: `$1$2${marker("assigned-secret")}$2`
|
|
4503
|
+
}
|
|
4504
|
+
];
|
|
4505
|
+
function redactSecrets(text) {
|
|
4506
|
+
let result = text;
|
|
4507
|
+
for (const { type: type2, re, replacement } of REDACTION_PATTERNS) {
|
|
4508
|
+
result = result.replace(re, replacement ?? marker(type2));
|
|
4509
|
+
}
|
|
4510
|
+
return result;
|
|
4511
|
+
}
|
|
4512
|
+
function redactDeep(value) {
|
|
4513
|
+
if (typeof value === "string") {
|
|
4514
|
+
return redactSecrets(value);
|
|
4515
|
+
}
|
|
4516
|
+
if (Array.isArray(value)) {
|
|
4517
|
+
return value.map((item) => redactDeep(item));
|
|
4518
|
+
}
|
|
4519
|
+
if (value !== null && typeof value === "object" && !(value instanceof Date)) {
|
|
4520
|
+
const out = {};
|
|
4521
|
+
for (const [k, v] of Object.entries(value)) {
|
|
4522
|
+
out[k] = redactDeep(v);
|
|
4523
|
+
}
|
|
4524
|
+
return out;
|
|
4525
|
+
}
|
|
4526
|
+
return value;
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
// src/gateway/modes/hybrid.ts
|
|
4310
4530
|
var MAX_QUEUE_SIZE = 1e3;
|
|
4311
4531
|
var MAX_RETRIES = 3;
|
|
4532
|
+
var FLUSH_TIMEOUT = /* @__PURE__ */ Symbol("flush-timeout");
|
|
4533
|
+
function delay(ms) {
|
|
4534
|
+
return new Promise((resolve) => {
|
|
4535
|
+
const timer = setTimeout(() => resolve(FLUSH_TIMEOUT), ms);
|
|
4536
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
4537
|
+
});
|
|
4538
|
+
}
|
|
4312
4539
|
var HybridSyncQueue = class {
|
|
4313
4540
|
constructor(config, persistPath) {
|
|
4314
4541
|
this.queue = [];
|
|
@@ -4329,12 +4556,12 @@ var HybridSyncQueue = class {
|
|
|
4329
4556
|
/**
|
|
4330
4557
|
* Stop periodic sync and flush remaining entries.
|
|
4331
4558
|
*/
|
|
4332
|
-
async stop() {
|
|
4559
|
+
async stop(flushOptions = {}) {
|
|
4333
4560
|
if (this.timer) {
|
|
4334
4561
|
clearInterval(this.timer);
|
|
4335
4562
|
this.timer = null;
|
|
4336
4563
|
}
|
|
4337
|
-
await this.flush();
|
|
4564
|
+
await this.flush(flushOptions);
|
|
4338
4565
|
this.saveToDisk();
|
|
4339
4566
|
}
|
|
4340
4567
|
/**
|
|
@@ -4346,8 +4573,8 @@ var HybridSyncQueue = class {
|
|
|
4346
4573
|
}
|
|
4347
4574
|
this.queue.push({
|
|
4348
4575
|
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
4349
|
-
context,
|
|
4350
|
-
decision,
|
|
4576
|
+
context: redactDeep(context),
|
|
4577
|
+
decision: redactDeep(decision),
|
|
4351
4578
|
timestamp: /* @__PURE__ */ new Date(),
|
|
4352
4579
|
retryCount: 0,
|
|
4353
4580
|
status: "pending"
|
|
@@ -4357,16 +4584,21 @@ var HybridSyncQueue = class {
|
|
|
4357
4584
|
/**
|
|
4358
4585
|
* Flush pending entries to the API.
|
|
4359
4586
|
*/
|
|
4360
|
-
async flush() {
|
|
4587
|
+
async flush(options = {}) {
|
|
4361
4588
|
if (this.processing) return;
|
|
4362
4589
|
this.processing = true;
|
|
4363
4590
|
try {
|
|
4364
4591
|
const pending = this.queue.filter((e) => e.status === "pending");
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4592
|
+
const batch = typeof options.limit === "number" ? pending.slice(0, options.limit) : pending;
|
|
4593
|
+
for (const entry of batch) {
|
|
4594
|
+
const attempt = verifyOnline(this.config, entry.context, this.config.agentId).then(() => "synced").catch(() => "error");
|
|
4595
|
+
const result = options.perEntryTimeoutMs ? await Promise.race([attempt, delay(options.perEntryTimeoutMs)]) : await attempt;
|
|
4596
|
+
if (result === FLUSH_TIMEOUT) {
|
|
4597
|
+
break;
|
|
4598
|
+
}
|
|
4599
|
+
if (result === "synced") {
|
|
4368
4600
|
entry.status = "synced";
|
|
4369
|
-
}
|
|
4601
|
+
} else {
|
|
4370
4602
|
entry.retryCount++;
|
|
4371
4603
|
if (entry.retryCount >= MAX_RETRIES) {
|
|
4372
4604
|
entry.status = "failed";
|
|
@@ -4443,8 +4675,22 @@ var TraceLogger = class {
|
|
|
4443
4675
|
id: this.generateId(),
|
|
4444
4676
|
timestamp: /* @__PURE__ */ new Date(),
|
|
4445
4677
|
type: "evaluation",
|
|
4446
|
-
context,
|
|
4447
|
-
decision
|
|
4678
|
+
context: redactDeep(context),
|
|
4679
|
+
decision: redactDeep(decision)
|
|
4680
|
+
});
|
|
4681
|
+
}
|
|
4682
|
+
/**
|
|
4683
|
+
* Log a tool call the guard saw but did not govern. One line per skip
|
|
4684
|
+
* keeps coverage holes (unmapped platform tools) visible in the traces
|
|
4685
|
+
* instead of silently indistinguishable from ALLOW.
|
|
4686
|
+
*/
|
|
4687
|
+
logSkipped(toolName, reason) {
|
|
4688
|
+
if (!this.enabled) return;
|
|
4689
|
+
this.write({
|
|
4690
|
+
id: this.generateId(),
|
|
4691
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4692
|
+
type: "skipped",
|
|
4693
|
+
metadata: { toolName, reason }
|
|
4448
4694
|
});
|
|
4449
4695
|
}
|
|
4450
4696
|
/**
|
|
@@ -4561,10 +4807,12 @@ var AstraSyncGateway = class {
|
|
|
4561
4807
|
}
|
|
4562
4808
|
/**
|
|
4563
4809
|
* Graceful shutdown. Flushes sync queue and cleans up resources.
|
|
4810
|
+
* Stateless callers (hooks) pass bounded flush options so sync never
|
|
4811
|
+
* sits on a tool call's critical path.
|
|
4564
4812
|
*/
|
|
4565
|
-
async shutdown() {
|
|
4813
|
+
async shutdown(options) {
|
|
4566
4814
|
if (this.syncQueue) {
|
|
4567
|
-
await this.syncQueue.stop();
|
|
4815
|
+
await this.syncQueue.stop(options?.syncFlush ?? {});
|
|
4568
4816
|
this.syncQueue = null;
|
|
4569
4817
|
}
|
|
4570
4818
|
this.evaluator = null;
|
|
@@ -4587,7 +4835,7 @@ var AstraSyncGateway = class {
|
|
|
4587
4835
|
let decision;
|
|
4588
4836
|
switch (this.config.mode) {
|
|
4589
4837
|
case "online":
|
|
4590
|
-
decision = await verifyOnline(this.config, context, astraId);
|
|
4838
|
+
decision = await verifyOnline(this.config, context, astraId ?? this.config.agentId);
|
|
4591
4839
|
break;
|
|
4592
4840
|
case "local":
|
|
4593
4841
|
if (!this.evaluator) throw new Error("Local evaluator not initialized");
|
|
@@ -4642,6 +4890,13 @@ var AstraSyncGateway = class {
|
|
|
4642
4890
|
getSyncStatus() {
|
|
4643
4891
|
return this.syncQueue?.getStatus() || null;
|
|
4644
4892
|
}
|
|
4893
|
+
/**
|
|
4894
|
+
* Record a tool call the calling adapter saw but did not govern
|
|
4895
|
+
* (unmapped tool, skipTools, MCP with governMcp off). Trace-only.
|
|
4896
|
+
*/
|
|
4897
|
+
logSkippedTool(toolName, reason) {
|
|
4898
|
+
this.traceLogger?.logSkipped(toolName, reason);
|
|
4899
|
+
}
|
|
4645
4900
|
};
|
|
4646
4901
|
|
|
4647
4902
|
// src/cursor/extension.ts
|