@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
package/dist/gateway/gateway.mjs
CHANGED
|
@@ -18,7 +18,9 @@ var HIGH_RISK_COMMANDS = [
|
|
|
18
18
|
"git push",
|
|
19
19
|
"npm publish",
|
|
20
20
|
"docker",
|
|
21
|
-
"kubectl"
|
|
21
|
+
"kubectl",
|
|
22
|
+
"gh pr create",
|
|
23
|
+
"gh pr merge"
|
|
22
24
|
];
|
|
23
25
|
var SENSITIVE_PATHS = [
|
|
24
26
|
".ssh",
|
|
@@ -37,6 +39,164 @@ var SENSITIVE_PATHS = [
|
|
|
37
39
|
".pypirc"
|
|
38
40
|
];
|
|
39
41
|
|
|
42
|
+
// src/local-evaluator/command-matcher.ts
|
|
43
|
+
var WRAPPERS = /* @__PURE__ */ new Set([
|
|
44
|
+
"sudo",
|
|
45
|
+
"doas",
|
|
46
|
+
"env",
|
|
47
|
+
"nohup",
|
|
48
|
+
"time",
|
|
49
|
+
"timeout",
|
|
50
|
+
"nice",
|
|
51
|
+
"ionice",
|
|
52
|
+
"stdbuf",
|
|
53
|
+
"xargs",
|
|
54
|
+
"command",
|
|
55
|
+
"exec",
|
|
56
|
+
"builtin"
|
|
57
|
+
]);
|
|
58
|
+
var ASSIGN_RE = /^[a-z_][a-z0-9_]*=/;
|
|
59
|
+
var MAX_WRAPPER_HOPS = 4;
|
|
60
|
+
var MAX_RECURSION_DEPTH = 3;
|
|
61
|
+
var MAX_COMMAND_LENGTH = 1e5;
|
|
62
|
+
var LOCAL_HOST_RE = /^(localhost|127\.0\.0\.1|::1|[a-z0-9.-]*\.localhost)$/;
|
|
63
|
+
function buildRiskList(entries) {
|
|
64
|
+
const singleWord = /* @__PURE__ */ new Set();
|
|
65
|
+
const multiWord = [];
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
const words = entry.toLowerCase().trim().split(/\s+/);
|
|
68
|
+
if (words.length === 1) singleWord.add(words[0]);
|
|
69
|
+
else multiWord.push(words);
|
|
70
|
+
}
|
|
71
|
+
multiWord.sort((a, b) => b.length - a.length);
|
|
72
|
+
return { singleWord, multiWord };
|
|
73
|
+
}
|
|
74
|
+
function stripHeredocBodies(text) {
|
|
75
|
+
const lines = text.split("\n");
|
|
76
|
+
const kept = [];
|
|
77
|
+
let terminator = null;
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
if (terminator !== null) {
|
|
80
|
+
if (line.trim() === terminator) terminator = null;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
kept.push(line);
|
|
84
|
+
const heredoc = line.match(/<<-?\s*['"]?(\w+)['"]?/);
|
|
85
|
+
if (heredoc) terminator = heredoc[1];
|
|
86
|
+
}
|
|
87
|
+
return kept.join("\n");
|
|
88
|
+
}
|
|
89
|
+
function extractDollarSubstitutions(text, collect) {
|
|
90
|
+
let result = text;
|
|
91
|
+
let start = result.indexOf("$(");
|
|
92
|
+
let iterations = 0;
|
|
93
|
+
while (start !== -1 && iterations < 50) {
|
|
94
|
+
iterations++;
|
|
95
|
+
let depth = 0;
|
|
96
|
+
let end = result.length;
|
|
97
|
+
for (let i = start + 1; i < result.length; i++) {
|
|
98
|
+
if (result[i] === "(") depth++;
|
|
99
|
+
else if (result[i] === ")") {
|
|
100
|
+
depth--;
|
|
101
|
+
if (depth === 0) {
|
|
102
|
+
end = i;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
collect(result.slice(start + 2, end));
|
|
108
|
+
result = `${result.slice(0, start)} ${result.slice(Math.min(end + 1, result.length))}`;
|
|
109
|
+
start = result.indexOf("$(");
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
function extractBacktickSubstitutions(text, collect) {
|
|
114
|
+
if (!text.includes("`")) return text;
|
|
115
|
+
const chunks = text.split("`");
|
|
116
|
+
const kept = [];
|
|
117
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
118
|
+
if (i % 2 === 1) collect(chunks[i]);
|
|
119
|
+
else kept.push(chunks[i]);
|
|
120
|
+
}
|
|
121
|
+
return kept.join(" ");
|
|
122
|
+
}
|
|
123
|
+
function basename(token) {
|
|
124
|
+
const slash = token.lastIndexOf("/");
|
|
125
|
+
return slash === -1 ? token : token.slice(slash + 1);
|
|
126
|
+
}
|
|
127
|
+
function matchSegment(segment, list) {
|
|
128
|
+
const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
|
|
129
|
+
let i = 0;
|
|
130
|
+
let hops = 0;
|
|
131
|
+
while (i < tokens.length) {
|
|
132
|
+
while (i < tokens.length && (tokens[i] === "export" || ASSIGN_RE.test(tokens[i]))) i++;
|
|
133
|
+
if (i >= tokens.length) return null;
|
|
134
|
+
const cmd = basename(tokens[i]);
|
|
135
|
+
const significant = [cmd, ...tokens.slice(i + 1).filter((t) => !t.startsWith("-"))];
|
|
136
|
+
for (const entry of list.multiWord) {
|
|
137
|
+
if (entry.length <= significant.length && entry.every((w, j) => significant[j] === w)) {
|
|
138
|
+
return entry.join(" ");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (list.singleWord.has(cmd)) return cmd;
|
|
142
|
+
if (WRAPPERS.has(cmd) && hops < MAX_WRAPPER_HOPS) {
|
|
143
|
+
hops++;
|
|
144
|
+
i++;
|
|
145
|
+
while (i < tokens.length && (tokens[i].startsWith("-") || ASSIGN_RE.test(tokens[i]))) i++;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
function collectMatches(command, list, matches, depth) {
|
|
153
|
+
if (depth > MAX_RECURSION_DEPTH || command.length > MAX_COMMAND_LENGTH) return;
|
|
154
|
+
let text = command.toLowerCase();
|
|
155
|
+
text = stripHeredocBodies(text);
|
|
156
|
+
const recurse = (inner) => collectMatches(inner, list, matches, depth + 1);
|
|
157
|
+
text = extractDollarSubstitutions(text, recurse);
|
|
158
|
+
text = extractBacktickSubstitutions(text, recurse);
|
|
159
|
+
text = text.replace(/'[^']*'/g, " ").replace(/"[^"]*"/g, " ");
|
|
160
|
+
text = text.replace(/(^|\s)#[^\n]*/g, " ");
|
|
161
|
+
const segments = text.split(/\|\||&&|[;|&\n]|[({]/);
|
|
162
|
+
for (const segment of segments) {
|
|
163
|
+
const matched = matchSegment(segment, list);
|
|
164
|
+
if (matched) matches.add(matched);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function matchHighRiskCommands(command, highRiskCommands = HIGH_RISK_COMMANDS) {
|
|
168
|
+
if (!command) return [];
|
|
169
|
+
const matches = /* @__PURE__ */ new Set();
|
|
170
|
+
collectMatches(command, buildRiskList(highRiskCommands), matches, 0);
|
|
171
|
+
return [...matches];
|
|
172
|
+
}
|
|
173
|
+
function isLocalhostOnlyNetworkCommand(command) {
|
|
174
|
+
const text = command.toLowerCase();
|
|
175
|
+
const tokens = text.split(/\s+/).map((t) => t.replace(/^["'`]+|["'`,;)]+$/g, ""));
|
|
176
|
+
let localCount = 0;
|
|
177
|
+
for (const token of tokens) {
|
|
178
|
+
let host = null;
|
|
179
|
+
if (token.includes("://")) {
|
|
180
|
+
let rest = token.slice(token.indexOf("://") + 3);
|
|
181
|
+
const at = rest.indexOf("@");
|
|
182
|
+
if (at !== -1) rest = rest.slice(at + 1);
|
|
183
|
+
host = rest.split(/[/?#]/)[0];
|
|
184
|
+
} else if (/^[a-z0-9.[\]:-]+:\d+(\/.*)?$/.test(token)) {
|
|
185
|
+
host = token.split("/")[0];
|
|
186
|
+
} else if (/^(localhost|127\.0\.0\.1|\[?::1\]?)(\/.*)?$/.test(token)) {
|
|
187
|
+
host = token.split("/")[0];
|
|
188
|
+
}
|
|
189
|
+
if (host === null) continue;
|
|
190
|
+
const bare = host.replace(/:\d+$/, "").replace(/^\[|\]$/g, "");
|
|
191
|
+
if (LOCAL_HOST_RE.test(bare)) {
|
|
192
|
+
localCount++;
|
|
193
|
+
} else {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return localCount > 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
40
200
|
// src/local-evaluator/evaluator.ts
|
|
41
201
|
var LocalEvaluator = class {
|
|
42
202
|
constructor(policy) {
|
|
@@ -187,12 +347,10 @@ var LocalEvaluator = class {
|
|
|
187
347
|
return score;
|
|
188
348
|
}
|
|
189
349
|
if (context.purpose === "shell.exec" && context.target) {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
350
|
+
const matched = matchHighRiskCommands(context.target);
|
|
351
|
+
const localProbeOnly = matched.length > 0 && matched.every((cmd) => cmd === "curl" || cmd === "wget") && isLocalhostOnlyNetworkCommand(context.target);
|
|
352
|
+
if (matched.length > 0 && !localProbeOnly) {
|
|
353
|
+
score = Math.max(score, 80);
|
|
196
354
|
}
|
|
197
355
|
}
|
|
198
356
|
if ((context.purpose === "file.read" || context.purpose === "file.write" || context.purpose === "file.delete") && context.target) {
|
|
@@ -3503,7 +3661,7 @@ function getTrustLevel(score) {
|
|
|
3503
3661
|
}
|
|
3504
3662
|
|
|
3505
3663
|
// src/version.ts
|
|
3506
|
-
var SDK_VERSION = "3.
|
|
3664
|
+
var SDK_VERSION = "3.11.0";
|
|
3507
3665
|
|
|
3508
3666
|
// src/well-known.ts
|
|
3509
3667
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -4021,10 +4179,12 @@ function toGatewayConfig(config) {
|
|
|
4021
4179
|
};
|
|
4022
4180
|
}
|
|
4023
4181
|
function toVerificationRequest(context, astraId) {
|
|
4182
|
+
const dotIndex = context.purpose.indexOf(".");
|
|
4183
|
+
const dotted = dotIndex > 0;
|
|
4024
4184
|
return {
|
|
4025
4185
|
credentials: { astraId },
|
|
4026
|
-
purpose: context.purpose,
|
|
4027
|
-
action: context.action,
|
|
4186
|
+
purpose: dotted ? context.purpose.slice(0, dotIndex) : context.purpose,
|
|
4187
|
+
action: dotted ? context.purpose : context.action,
|
|
4028
4188
|
resourceType: context.resourceType,
|
|
4029
4189
|
resource: context.target,
|
|
4030
4190
|
transactionValue: context.transactionValue,
|
|
@@ -4064,8 +4224,75 @@ async function verifyOnline(config, context, astraId) {
|
|
|
4064
4224
|
// src/gateway/modes/hybrid.ts
|
|
4065
4225
|
import { existsSync, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
4066
4226
|
import { dirname } from "path";
|
|
4227
|
+
|
|
4228
|
+
// src/gateway/redact.ts
|
|
4229
|
+
var marker = (type2) => `[REDACTED:${type2}]`;
|
|
4230
|
+
var REDACTION_PATTERNS = [
|
|
4231
|
+
// Multi-line blocks first so later single-line patterns don't shred them.
|
|
4232
|
+
{
|
|
4233
|
+
type: "private-key",
|
|
4234
|
+
re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g
|
|
4235
|
+
},
|
|
4236
|
+
// URL userinfo credentials (https://user:pass@, x-access-token:ghp_…@).
|
|
4237
|
+
{
|
|
4238
|
+
type: "url-credentials",
|
|
4239
|
+
re: /([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi,
|
|
4240
|
+
replacement: `$1${marker("url-credentials")}@`
|
|
4241
|
+
},
|
|
4242
|
+
// Known token formats.
|
|
4243
|
+
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{20,255}\b/g },
|
|
4244
|
+
{ type: "github-token", re: /\bgithub_pat_[A-Za-z0-9_]{20,255}\b/g },
|
|
4245
|
+
{ type: "astrasync-key", re: /\bkya_[A-Fa-f0-9]{32,128}\b/g },
|
|
4246
|
+
{ type: "openai-key", re: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
|
|
4247
|
+
{ type: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b/g },
|
|
4248
|
+
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
|
|
4249
|
+
// Bearer/token headers.
|
|
4250
|
+
{
|
|
4251
|
+
type: "bearer-token",
|
|
4252
|
+
re: /\b(bearer\s+)[a-z0-9._~+/=-]{16,}/gi,
|
|
4253
|
+
replacement: `$1${marker("bearer-token")}`
|
|
4254
|
+
},
|
|
4255
|
+
// Generic KEY=value / key: value assignments with secret-ish names.
|
|
4256
|
+
{
|
|
4257
|
+
type: "assigned-secret",
|
|
4258
|
+
re: /\b((?:password|passwd|secret|token|api[_-]?key|apikey|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[=:]\s*)(['"]?)[^\s'"&;]{8,}\2/gi,
|
|
4259
|
+
replacement: `$1$2${marker("assigned-secret")}$2`
|
|
4260
|
+
}
|
|
4261
|
+
];
|
|
4262
|
+
function redactSecrets(text) {
|
|
4263
|
+
let result = text;
|
|
4264
|
+
for (const { type: type2, re, replacement } of REDACTION_PATTERNS) {
|
|
4265
|
+
result = result.replace(re, replacement ?? marker(type2));
|
|
4266
|
+
}
|
|
4267
|
+
return result;
|
|
4268
|
+
}
|
|
4269
|
+
function redactDeep(value) {
|
|
4270
|
+
if (typeof value === "string") {
|
|
4271
|
+
return redactSecrets(value);
|
|
4272
|
+
}
|
|
4273
|
+
if (Array.isArray(value)) {
|
|
4274
|
+
return value.map((item) => redactDeep(item));
|
|
4275
|
+
}
|
|
4276
|
+
if (value !== null && typeof value === "object" && !(value instanceof Date)) {
|
|
4277
|
+
const out = {};
|
|
4278
|
+
for (const [k, v] of Object.entries(value)) {
|
|
4279
|
+
out[k] = redactDeep(v);
|
|
4280
|
+
}
|
|
4281
|
+
return out;
|
|
4282
|
+
}
|
|
4283
|
+
return value;
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4286
|
+
// src/gateway/modes/hybrid.ts
|
|
4067
4287
|
var MAX_QUEUE_SIZE = 1e3;
|
|
4068
4288
|
var MAX_RETRIES = 3;
|
|
4289
|
+
var FLUSH_TIMEOUT = /* @__PURE__ */ Symbol("flush-timeout");
|
|
4290
|
+
function delay(ms) {
|
|
4291
|
+
return new Promise((resolve) => {
|
|
4292
|
+
const timer = setTimeout(() => resolve(FLUSH_TIMEOUT), ms);
|
|
4293
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
4294
|
+
});
|
|
4295
|
+
}
|
|
4069
4296
|
var HybridSyncQueue = class {
|
|
4070
4297
|
constructor(config, persistPath) {
|
|
4071
4298
|
this.queue = [];
|
|
@@ -4086,12 +4313,12 @@ var HybridSyncQueue = class {
|
|
|
4086
4313
|
/**
|
|
4087
4314
|
* Stop periodic sync and flush remaining entries.
|
|
4088
4315
|
*/
|
|
4089
|
-
async stop() {
|
|
4316
|
+
async stop(flushOptions = {}) {
|
|
4090
4317
|
if (this.timer) {
|
|
4091
4318
|
clearInterval(this.timer);
|
|
4092
4319
|
this.timer = null;
|
|
4093
4320
|
}
|
|
4094
|
-
await this.flush();
|
|
4321
|
+
await this.flush(flushOptions);
|
|
4095
4322
|
this.saveToDisk();
|
|
4096
4323
|
}
|
|
4097
4324
|
/**
|
|
@@ -4103,8 +4330,8 @@ var HybridSyncQueue = class {
|
|
|
4103
4330
|
}
|
|
4104
4331
|
this.queue.push({
|
|
4105
4332
|
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
4106
|
-
context,
|
|
4107
|
-
decision,
|
|
4333
|
+
context: redactDeep(context),
|
|
4334
|
+
decision: redactDeep(decision),
|
|
4108
4335
|
timestamp: /* @__PURE__ */ new Date(),
|
|
4109
4336
|
retryCount: 0,
|
|
4110
4337
|
status: "pending"
|
|
@@ -4114,16 +4341,21 @@ var HybridSyncQueue = class {
|
|
|
4114
4341
|
/**
|
|
4115
4342
|
* Flush pending entries to the API.
|
|
4116
4343
|
*/
|
|
4117
|
-
async flush() {
|
|
4344
|
+
async flush(options = {}) {
|
|
4118
4345
|
if (this.processing) return;
|
|
4119
4346
|
this.processing = true;
|
|
4120
4347
|
try {
|
|
4121
4348
|
const pending = this.queue.filter((e) => e.status === "pending");
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4349
|
+
const batch = typeof options.limit === "number" ? pending.slice(0, options.limit) : pending;
|
|
4350
|
+
for (const entry of batch) {
|
|
4351
|
+
const attempt = verifyOnline(this.config, entry.context, this.config.agentId).then(() => "synced").catch(() => "error");
|
|
4352
|
+
const result = options.perEntryTimeoutMs ? await Promise.race([attempt, delay(options.perEntryTimeoutMs)]) : await attempt;
|
|
4353
|
+
if (result === FLUSH_TIMEOUT) {
|
|
4354
|
+
break;
|
|
4355
|
+
}
|
|
4356
|
+
if (result === "synced") {
|
|
4125
4357
|
entry.status = "synced";
|
|
4126
|
-
}
|
|
4358
|
+
} else {
|
|
4127
4359
|
entry.retryCount++;
|
|
4128
4360
|
if (entry.retryCount >= MAX_RETRIES) {
|
|
4129
4361
|
entry.status = "failed";
|
|
@@ -4200,8 +4432,22 @@ var TraceLogger = class {
|
|
|
4200
4432
|
id: this.generateId(),
|
|
4201
4433
|
timestamp: /* @__PURE__ */ new Date(),
|
|
4202
4434
|
type: "evaluation",
|
|
4203
|
-
context,
|
|
4204
|
-
decision
|
|
4435
|
+
context: redactDeep(context),
|
|
4436
|
+
decision: redactDeep(decision)
|
|
4437
|
+
});
|
|
4438
|
+
}
|
|
4439
|
+
/**
|
|
4440
|
+
* Log a tool call the guard saw but did not govern. One line per skip
|
|
4441
|
+
* keeps coverage holes (unmapped platform tools) visible in the traces
|
|
4442
|
+
* instead of silently indistinguishable from ALLOW.
|
|
4443
|
+
*/
|
|
4444
|
+
logSkipped(toolName, reason) {
|
|
4445
|
+
if (!this.enabled) return;
|
|
4446
|
+
this.write({
|
|
4447
|
+
id: this.generateId(),
|
|
4448
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4449
|
+
type: "skipped",
|
|
4450
|
+
metadata: { toolName, reason }
|
|
4205
4451
|
});
|
|
4206
4452
|
}
|
|
4207
4453
|
/**
|
|
@@ -4318,10 +4564,12 @@ var AstraSyncGateway = class {
|
|
|
4318
4564
|
}
|
|
4319
4565
|
/**
|
|
4320
4566
|
* Graceful shutdown. Flushes sync queue and cleans up resources.
|
|
4567
|
+
* Stateless callers (hooks) pass bounded flush options so sync never
|
|
4568
|
+
* sits on a tool call's critical path.
|
|
4321
4569
|
*/
|
|
4322
|
-
async shutdown() {
|
|
4570
|
+
async shutdown(options) {
|
|
4323
4571
|
if (this.syncQueue) {
|
|
4324
|
-
await this.syncQueue.stop();
|
|
4572
|
+
await this.syncQueue.stop(options?.syncFlush ?? {});
|
|
4325
4573
|
this.syncQueue = null;
|
|
4326
4574
|
}
|
|
4327
4575
|
this.evaluator = null;
|
|
@@ -4344,7 +4592,7 @@ var AstraSyncGateway = class {
|
|
|
4344
4592
|
let decision;
|
|
4345
4593
|
switch (this.config.mode) {
|
|
4346
4594
|
case "online":
|
|
4347
|
-
decision = await verifyOnline(this.config, context, astraId);
|
|
4595
|
+
decision = await verifyOnline(this.config, context, astraId ?? this.config.agentId);
|
|
4348
4596
|
break;
|
|
4349
4597
|
case "local":
|
|
4350
4598
|
if (!this.evaluator) throw new Error("Local evaluator not initialized");
|
|
@@ -4399,6 +4647,13 @@ var AstraSyncGateway = class {
|
|
|
4399
4647
|
getSyncStatus() {
|
|
4400
4648
|
return this.syncQueue?.getStatus() || null;
|
|
4401
4649
|
}
|
|
4650
|
+
/**
|
|
4651
|
+
* Record a tool call the calling adapter saw but did not govern
|
|
4652
|
+
* (unmapped tool, skipTools, MCP with governMcp off). Trace-only.
|
|
4653
|
+
*/
|
|
4654
|
+
logSkippedTool(toolName, reason) {
|
|
4655
|
+
this.traceLogger?.logSkipped(toolName, reason);
|
|
4656
|
+
}
|
|
4402
4657
|
};
|
|
4403
4658
|
export {
|
|
4404
4659
|
AstraSyncGateway
|