@astrasyncai/verification-gateway 3.11.0 → 3.12.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 +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +22 -3
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +22 -3
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +22 -3
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +22 -3
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +22 -3
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +22 -3
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +22 -3
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +22 -3
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/bin/astrasync-claude-hook.js +84 -21
- package/dist/bin/astrasync-codex-hook.js +84 -21
- package/dist/bin/astrasync-guard.js +84 -21
- package/dist/bin/astrasync.js +85 -21
- package/dist/browser/background.js +84 -21
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +84 -21
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/claude-code/claude-code-adapter.d.mts +2 -2
- package/dist/claude-code/claude-code-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/codex/index.d.mts +2 -2
- package/dist/codex/index.d.ts +2 -2
- package/dist/codex/index.js +84 -21
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +84 -21
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +84 -21
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +84 -21
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/{express-DCXa1oqj.d.mts → express-B39o89gf.d.mts} +1 -1
- package/dist/{express-ClNtDhhc.d.ts → express-BuxKNO_q.d.ts} +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +84 -21
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +84 -21
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-CfHurO1P.d.ts → index-BG62SXso.d.ts} +1 -1
- package/dist/{index-D2ztkumS.d.ts → index-CLHdqs2M.d.ts} +1 -1
- package/dist/{index-Dr_XiN65.d.mts → index-CqydB4ks.d.mts} +1 -1
- package/dist/{index-BrNKDmiR.d.mts → index-DME3w3lf.d.mts} +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +42 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +41 -3
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +11 -2
- package/dist/local-evaluator/evaluator.d.ts +11 -2
- package/dist/local-evaluator/evaluator.js +20 -9
- package/dist/local-evaluator/evaluator.js.map +1 -1
- package/dist/local-evaluator/evaluator.mjs +20 -9
- package/dist/local-evaluator/evaluator.mjs.map +1 -1
- package/dist/{nextjs-DcQIk6Zj.d.mts → nextjs-D74W7wt-.d.mts} +1 -1
- package/dist/{nextjs-CEBVBsdi.d.ts → nextjs-Ddlw_J1J.d.ts} +1 -1
- package/dist/{sdk-CZkbSOeO.d.mts → sdk-Bn6bj7kt.d.mts} +1 -1
- package/dist/{sdk-H0JCLW2y.d.ts → sdk-CT7gdkfR.d.ts} +1 -1
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-sy3tq8lp.d.mts → types-BntuzEEn.d.mts} +103 -1
- package/dist/{types-BV6abBnF.d.mts → types-DHu7m9HI.d.ts} +7 -2
- package/dist/{types-C23_uaY8.d.ts → types-Djw4GLtz.d.mts} +7 -2
- package/dist/{types-9tns4wyl.d.ts → types-SDu4Llbe.d.ts} +103 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +13 -2
- package/dist/verify.d.ts +13 -2
- package/dist/verify.js +42 -3
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +41 -3
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -150,8 +150,9 @@ function extractBacktickSubstitutions(text, collect) {
|
|
|
150
150
|
return kept.join(" ");
|
|
151
151
|
}
|
|
152
152
|
function basename(token) {
|
|
153
|
-
const slash = token.lastIndexOf("/");
|
|
154
|
-
|
|
153
|
+
const slash = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
|
|
154
|
+
const name = slash === -1 ? token : token.slice(slash + 1);
|
|
155
|
+
return name.replace(/\.(exe|cmd|bat|ps1)$/i, "");
|
|
155
156
|
}
|
|
156
157
|
function matchSegment(segment, list) {
|
|
157
158
|
const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
|
|
@@ -284,7 +285,9 @@ var LocalEvaluator = class {
|
|
|
284
285
|
}
|
|
285
286
|
return {
|
|
286
287
|
recommendation: "ALLOW",
|
|
287
|
-
|
|
288
|
+
// "evaluated": dimensions absent from the policy are skipped, not
|
|
289
|
+
// failed — evaluatedDimensions below records which ones ran.
|
|
290
|
+
reason: "All evaluated PDLSS checks passed",
|
|
288
291
|
evaluatedDimensions: {
|
|
289
292
|
purpose: true,
|
|
290
293
|
scope: !!this.policy.scope,
|
|
@@ -383,7 +386,7 @@ var LocalEvaluator = class {
|
|
|
383
386
|
}
|
|
384
387
|
}
|
|
385
388
|
if ((context.purpose === "file.read" || context.purpose === "file.write" || context.purpose === "file.delete") && context.target) {
|
|
386
|
-
const targetLower = context.target.toLowerCase();
|
|
389
|
+
const targetLower = context.target.toLowerCase().replace(/\\/g, "/");
|
|
387
390
|
for (const sensitivePath of SENSITIVE_PATHS) {
|
|
388
391
|
if (targetLower.includes(sensitivePath.toLowerCase())) {
|
|
389
392
|
score = Math.max(score, 50);
|
|
@@ -412,12 +415,20 @@ var LocalEvaluator = class {
|
|
|
412
415
|
matchesAnyPattern(value, patterns) {
|
|
413
416
|
return patterns.some((pattern) => this.matchGlob(value, pattern));
|
|
414
417
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
418
|
+
homePrefix() {
|
|
419
|
+
if (this.cachedHomePrefix !== void 0) return this.cachedHomePrefix;
|
|
420
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
421
|
+
const home = env?.HOME || env?.USERPROFILE;
|
|
422
|
+
this.cachedHomePrefix = home ? home.replace(/\\/g, "/") : null;
|
|
423
|
+
return this.cachedHomePrefix;
|
|
424
|
+
}
|
|
420
425
|
matchGlob(value, pattern) {
|
|
426
|
+
value = value.replace(/\\/g, "/");
|
|
427
|
+
pattern = pattern.replace(/\\/g, "/");
|
|
428
|
+
if (pattern === "~" || pattern.startsWith("~/")) {
|
|
429
|
+
const home = this.homePrefix();
|
|
430
|
+
if (home) pattern = home + pattern.slice(1);
|
|
431
|
+
}
|
|
421
432
|
if (pattern === value) return true;
|
|
422
433
|
const starCount = (pattern.match(/\*/g) ?? []).length;
|
|
423
434
|
if (starCount > 8) {
|
|
@@ -3690,7 +3701,7 @@ function getTrustLevel(score) {
|
|
|
3690
3701
|
}
|
|
3691
3702
|
|
|
3692
3703
|
// src/version.ts
|
|
3693
|
-
var SDK_VERSION = "3.
|
|
3704
|
+
var SDK_VERSION = "3.12.0";
|
|
3694
3705
|
|
|
3695
3706
|
// src/well-known.ts
|
|
3696
3707
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -3857,6 +3868,7 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
3857
3868
|
}
|
|
3858
3869
|
] : void 0,
|
|
3859
3870
|
correlationId: options.correlationId,
|
|
3871
|
+
attemptId: options.attemptId,
|
|
3860
3872
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
3861
3873
|
};
|
|
3862
3874
|
}
|
|
@@ -3886,6 +3898,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3886
3898
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
3887
3899
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
3888
3900
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
3901
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
3902
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
3889
3903
|
body.sdkVersion = SDK_VERSION;
|
|
3890
3904
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
3891
3905
|
const meta = {
|
|
@@ -3913,6 +3927,9 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3913
3927
|
if (response.status === 410) {
|
|
3914
3928
|
return {
|
|
3915
3929
|
success: true,
|
|
3930
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
3931
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
3932
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
3916
3933
|
access: {
|
|
3917
3934
|
allowed: false,
|
|
3918
3935
|
accessLevel: "none",
|
|
@@ -3931,7 +3948,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3931
3948
|
return {
|
|
3932
3949
|
success: false,
|
|
3933
3950
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
3934
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
3951
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
3952
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
3935
3953
|
};
|
|
3936
3954
|
}
|
|
3937
3955
|
return data;
|
|
@@ -3965,7 +3983,13 @@ async function verify(config, request, options) {
|
|
|
3965
3983
|
if (mergedConfig.debug) {
|
|
3966
3984
|
console.log("[VerificationGateway] Returning cached result");
|
|
3967
3985
|
}
|
|
3968
|
-
|
|
3986
|
+
const hit = { ...cached };
|
|
3987
|
+
if (request.attemptId) {
|
|
3988
|
+
hit.attemptId = request.attemptId;
|
|
3989
|
+
} else {
|
|
3990
|
+
delete hit.attemptId;
|
|
3991
|
+
}
|
|
3992
|
+
return hit;
|
|
3969
3993
|
}
|
|
3970
3994
|
}
|
|
3971
3995
|
const enrichedRequest = { ...request };
|
|
@@ -3985,6 +4009,7 @@ async function verify(config, request, options) {
|
|
|
3985
4009
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
3986
4010
|
source: "api_error",
|
|
3987
4011
|
correlationId: apiResponse.correlationId,
|
|
4012
|
+
attemptId: apiResponse.attemptId,
|
|
3988
4013
|
urls
|
|
3989
4014
|
});
|
|
3990
4015
|
}
|
|
@@ -4020,6 +4045,9 @@ async function verify(config, request, options) {
|
|
|
4020
4045
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4021
4046
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4022
4047
|
correlationId: apiResponse.correlationId,
|
|
4048
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
4049
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
4050
|
+
attemptId: apiResponse.attemptId,
|
|
4023
4051
|
recommendation: apiResponse.recommendation,
|
|
4024
4052
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4025
4053
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4071,6 +4099,8 @@ async function verify(config, request, options) {
|
|
|
4071
4099
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4072
4100
|
// (no session row exists for unverified callers).
|
|
4073
4101
|
correlationId: apiResponse.correlationId,
|
|
4102
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
4103
|
+
attemptId: apiResponse.attemptId,
|
|
4074
4104
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4075
4105
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4076
4106
|
recommendation: apiResponse.recommendation,
|
|
@@ -4454,13 +4484,29 @@ var TraceLogger = class {
|
|
|
4454
4484
|
*/
|
|
4455
4485
|
logEvaluation(context, decision) {
|
|
4456
4486
|
if (!this.enabled) return;
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4487
|
+
let event;
|
|
4488
|
+
try {
|
|
4489
|
+
event = {
|
|
4490
|
+
id: this.generateId(),
|
|
4491
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4492
|
+
type: "evaluation",
|
|
4493
|
+
context: redactDeep(context),
|
|
4494
|
+
decision: redactDeep(decision)
|
|
4495
|
+
};
|
|
4496
|
+
} catch (err) {
|
|
4497
|
+
event = {
|
|
4498
|
+
id: this.generateId(),
|
|
4499
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4500
|
+
type: "error",
|
|
4501
|
+
metadata: {
|
|
4502
|
+
error: `trace redaction failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
4503
|
+
recommendation: decision.recommendation,
|
|
4504
|
+
purpose: context.purpose,
|
|
4505
|
+
action: context.action
|
|
4506
|
+
}
|
|
4507
|
+
};
|
|
4508
|
+
}
|
|
4509
|
+
this.write(event);
|
|
4464
4510
|
}
|
|
4465
4511
|
/**
|
|
4466
4512
|
* Log a tool call the guard saw but did not govern. One line per skip
|
|
@@ -4502,17 +4548,34 @@ var TraceLogger = class {
|
|
|
4502
4548
|
});
|
|
4503
4549
|
}
|
|
4504
4550
|
write(event) {
|
|
4551
|
+
let line;
|
|
4552
|
+
try {
|
|
4553
|
+
line = JSON.stringify(event) + "\n";
|
|
4554
|
+
} catch {
|
|
4555
|
+
return;
|
|
4556
|
+
}
|
|
4505
4557
|
try {
|
|
4506
4558
|
const filePath = this.getCurrentFilePath();
|
|
4507
|
-
const line = JSON.stringify(event) + "\n";
|
|
4508
4559
|
if ((0, import_fs3.existsSync)(filePath)) {
|
|
4509
4560
|
const stats = (0, import_fs3.statSync)(filePath);
|
|
4510
4561
|
if (stats.size > MAX_FILE_SIZE) {
|
|
4511
4562
|
this.rotate();
|
|
4512
4563
|
}
|
|
4513
4564
|
}
|
|
4514
|
-
(0
|
|
4565
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
4566
|
+
try {
|
|
4567
|
+
(0, import_fs3.appendFileSync)(filePath, line);
|
|
4568
|
+
return;
|
|
4569
|
+
} catch {
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
const fallbackPath = filePath.replace(/\.jsonl$/, `-r${process.pid}.jsonl`);
|
|
4573
|
+
(0, import_fs3.appendFileSync)(fallbackPath, line);
|
|
4515
4574
|
} catch {
|
|
4575
|
+
try {
|
|
4576
|
+
console.error(`[AstraSync TraceLogger] failed to persist trace line: ${line.trim()}`);
|
|
4577
|
+
} catch {
|
|
4578
|
+
}
|
|
4516
4579
|
}
|
|
4517
4580
|
}
|
|
4518
4581
|
getCurrentFilePath() {
|
|
@@ -149,8 +149,9 @@ function extractBacktickSubstitutions(text, collect) {
|
|
|
149
149
|
return kept.join(" ");
|
|
150
150
|
}
|
|
151
151
|
function basename(token) {
|
|
152
|
-
const slash = token.lastIndexOf("/");
|
|
153
|
-
|
|
152
|
+
const slash = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
|
|
153
|
+
const name = slash === -1 ? token : token.slice(slash + 1);
|
|
154
|
+
return name.replace(/\.(exe|cmd|bat|ps1)$/i, "");
|
|
154
155
|
}
|
|
155
156
|
function matchSegment(segment, list) {
|
|
156
157
|
const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
|
|
@@ -283,7 +284,9 @@ var LocalEvaluator = class {
|
|
|
283
284
|
}
|
|
284
285
|
return {
|
|
285
286
|
recommendation: "ALLOW",
|
|
286
|
-
|
|
287
|
+
// "evaluated": dimensions absent from the policy are skipped, not
|
|
288
|
+
// failed — evaluatedDimensions below records which ones ran.
|
|
289
|
+
reason: "All evaluated PDLSS checks passed",
|
|
287
290
|
evaluatedDimensions: {
|
|
288
291
|
purpose: true,
|
|
289
292
|
scope: !!this.policy.scope,
|
|
@@ -382,7 +385,7 @@ var LocalEvaluator = class {
|
|
|
382
385
|
}
|
|
383
386
|
}
|
|
384
387
|
if ((context.purpose === "file.read" || context.purpose === "file.write" || context.purpose === "file.delete") && context.target) {
|
|
385
|
-
const targetLower = context.target.toLowerCase();
|
|
388
|
+
const targetLower = context.target.toLowerCase().replace(/\\/g, "/");
|
|
386
389
|
for (const sensitivePath of SENSITIVE_PATHS) {
|
|
387
390
|
if (targetLower.includes(sensitivePath.toLowerCase())) {
|
|
388
391
|
score = Math.max(score, 50);
|
|
@@ -411,12 +414,20 @@ var LocalEvaluator = class {
|
|
|
411
414
|
matchesAnyPattern(value, patterns) {
|
|
412
415
|
return patterns.some((pattern) => this.matchGlob(value, pattern));
|
|
413
416
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
417
|
+
homePrefix() {
|
|
418
|
+
if (this.cachedHomePrefix !== void 0) return this.cachedHomePrefix;
|
|
419
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
420
|
+
const home = env?.HOME || env?.USERPROFILE;
|
|
421
|
+
this.cachedHomePrefix = home ? home.replace(/\\/g, "/") : null;
|
|
422
|
+
return this.cachedHomePrefix;
|
|
423
|
+
}
|
|
419
424
|
matchGlob(value, pattern) {
|
|
425
|
+
value = value.replace(/\\/g, "/");
|
|
426
|
+
pattern = pattern.replace(/\\/g, "/");
|
|
427
|
+
if (pattern === "~" || pattern.startsWith("~/")) {
|
|
428
|
+
const home = this.homePrefix();
|
|
429
|
+
if (home) pattern = home + pattern.slice(1);
|
|
430
|
+
}
|
|
420
431
|
if (pattern === value) return true;
|
|
421
432
|
const starCount = (pattern.match(/\*/g) ?? []).length;
|
|
422
433
|
if (starCount > 8) {
|
|
@@ -3689,7 +3700,7 @@ function getTrustLevel(score) {
|
|
|
3689
3700
|
}
|
|
3690
3701
|
|
|
3691
3702
|
// src/version.ts
|
|
3692
|
-
var SDK_VERSION = "3.
|
|
3703
|
+
var SDK_VERSION = "3.12.0";
|
|
3693
3704
|
|
|
3694
3705
|
// src/well-known.ts
|
|
3695
3706
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -3856,6 +3867,7 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
3856
3867
|
}
|
|
3857
3868
|
] : void 0,
|
|
3858
3869
|
correlationId: options.correlationId,
|
|
3870
|
+
attemptId: options.attemptId,
|
|
3859
3871
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
3860
3872
|
};
|
|
3861
3873
|
}
|
|
@@ -3885,6 +3897,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3885
3897
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
3886
3898
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
3887
3899
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
3900
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
3901
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
3888
3902
|
body.sdkVersion = SDK_VERSION;
|
|
3889
3903
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
3890
3904
|
const meta = {
|
|
@@ -3912,6 +3926,9 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3912
3926
|
if (response.status === 410) {
|
|
3913
3927
|
return {
|
|
3914
3928
|
success: true,
|
|
3929
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
3930
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
3931
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
3915
3932
|
access: {
|
|
3916
3933
|
allowed: false,
|
|
3917
3934
|
accessLevel: "none",
|
|
@@ -3930,7 +3947,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3930
3947
|
return {
|
|
3931
3948
|
success: false,
|
|
3932
3949
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
3933
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
3950
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
3951
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
3934
3952
|
};
|
|
3935
3953
|
}
|
|
3936
3954
|
return data;
|
|
@@ -3964,7 +3982,13 @@ async function verify(config, request, options) {
|
|
|
3964
3982
|
if (mergedConfig.debug) {
|
|
3965
3983
|
console.log("[VerificationGateway] Returning cached result");
|
|
3966
3984
|
}
|
|
3967
|
-
|
|
3985
|
+
const hit = { ...cached };
|
|
3986
|
+
if (request.attemptId) {
|
|
3987
|
+
hit.attemptId = request.attemptId;
|
|
3988
|
+
} else {
|
|
3989
|
+
delete hit.attemptId;
|
|
3990
|
+
}
|
|
3991
|
+
return hit;
|
|
3968
3992
|
}
|
|
3969
3993
|
}
|
|
3970
3994
|
const enrichedRequest = { ...request };
|
|
@@ -3984,6 +4008,7 @@ async function verify(config, request, options) {
|
|
|
3984
4008
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
3985
4009
|
source: "api_error",
|
|
3986
4010
|
correlationId: apiResponse.correlationId,
|
|
4011
|
+
attemptId: apiResponse.attemptId,
|
|
3987
4012
|
urls
|
|
3988
4013
|
});
|
|
3989
4014
|
}
|
|
@@ -4019,6 +4044,9 @@ async function verify(config, request, options) {
|
|
|
4019
4044
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4020
4045
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4021
4046
|
correlationId: apiResponse.correlationId,
|
|
4047
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
4048
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
4049
|
+
attemptId: apiResponse.attemptId,
|
|
4022
4050
|
recommendation: apiResponse.recommendation,
|
|
4023
4051
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4024
4052
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4070,6 +4098,8 @@ async function verify(config, request, options) {
|
|
|
4070
4098
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4071
4099
|
// (no session row exists for unverified callers).
|
|
4072
4100
|
correlationId: apiResponse.correlationId,
|
|
4101
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
4102
|
+
attemptId: apiResponse.attemptId,
|
|
4073
4103
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4074
4104
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4075
4105
|
recommendation: apiResponse.recommendation,
|
|
@@ -4453,13 +4483,29 @@ var TraceLogger = class {
|
|
|
4453
4483
|
*/
|
|
4454
4484
|
logEvaluation(context, decision) {
|
|
4455
4485
|
if (!this.enabled) return;
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4486
|
+
let event;
|
|
4487
|
+
try {
|
|
4488
|
+
event = {
|
|
4489
|
+
id: this.generateId(),
|
|
4490
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4491
|
+
type: "evaluation",
|
|
4492
|
+
context: redactDeep(context),
|
|
4493
|
+
decision: redactDeep(decision)
|
|
4494
|
+
};
|
|
4495
|
+
} catch (err) {
|
|
4496
|
+
event = {
|
|
4497
|
+
id: this.generateId(),
|
|
4498
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4499
|
+
type: "error",
|
|
4500
|
+
metadata: {
|
|
4501
|
+
error: `trace redaction failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
4502
|
+
recommendation: decision.recommendation,
|
|
4503
|
+
purpose: context.purpose,
|
|
4504
|
+
action: context.action
|
|
4505
|
+
}
|
|
4506
|
+
};
|
|
4507
|
+
}
|
|
4508
|
+
this.write(event);
|
|
4463
4509
|
}
|
|
4464
4510
|
/**
|
|
4465
4511
|
* Log a tool call the guard saw but did not govern. One line per skip
|
|
@@ -4501,17 +4547,34 @@ var TraceLogger = class {
|
|
|
4501
4547
|
});
|
|
4502
4548
|
}
|
|
4503
4549
|
write(event) {
|
|
4550
|
+
let line;
|
|
4551
|
+
try {
|
|
4552
|
+
line = JSON.stringify(event) + "\n";
|
|
4553
|
+
} catch {
|
|
4554
|
+
return;
|
|
4555
|
+
}
|
|
4504
4556
|
try {
|
|
4505
4557
|
const filePath = this.getCurrentFilePath();
|
|
4506
|
-
const line = JSON.stringify(event) + "\n";
|
|
4507
4558
|
if ((0, import_fs3.existsSync)(filePath)) {
|
|
4508
4559
|
const stats = (0, import_fs3.statSync)(filePath);
|
|
4509
4560
|
if (stats.size > MAX_FILE_SIZE) {
|
|
4510
4561
|
this.rotate();
|
|
4511
4562
|
}
|
|
4512
4563
|
}
|
|
4513
|
-
(0
|
|
4564
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
4565
|
+
try {
|
|
4566
|
+
(0, import_fs3.appendFileSync)(filePath, line);
|
|
4567
|
+
return;
|
|
4568
|
+
} catch {
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
const fallbackPath = filePath.replace(/\.jsonl$/, `-r${process.pid}.jsonl`);
|
|
4572
|
+
(0, import_fs3.appendFileSync)(fallbackPath, line);
|
|
4514
4573
|
} catch {
|
|
4574
|
+
try {
|
|
4575
|
+
console.error(`[AstraSync TraceLogger] failed to persist trace line: ${line.trim()}`);
|
|
4576
|
+
} catch {
|
|
4577
|
+
}
|
|
4515
4578
|
}
|
|
4516
4579
|
}
|
|
4517
4580
|
getCurrentFilePath() {
|
|
@@ -4288,8 +4288,9 @@ function extractBacktickSubstitutions(text, collect) {
|
|
|
4288
4288
|
return kept.join(" ");
|
|
4289
4289
|
}
|
|
4290
4290
|
function basename(token) {
|
|
4291
|
-
const slash = token.lastIndexOf("/");
|
|
4292
|
-
|
|
4291
|
+
const slash = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
|
|
4292
|
+
const name = slash === -1 ? token : token.slice(slash + 1);
|
|
4293
|
+
return name.replace(/\.(exe|cmd|bat|ps1)$/i, "");
|
|
4293
4294
|
}
|
|
4294
4295
|
function matchSegment(segment, list) {
|
|
4295
4296
|
const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
|
|
@@ -4422,7 +4423,9 @@ var LocalEvaluator = class {
|
|
|
4422
4423
|
}
|
|
4423
4424
|
return {
|
|
4424
4425
|
recommendation: "ALLOW",
|
|
4425
|
-
|
|
4426
|
+
// "evaluated": dimensions absent from the policy are skipped, not
|
|
4427
|
+
// failed — evaluatedDimensions below records which ones ran.
|
|
4428
|
+
reason: "All evaluated PDLSS checks passed",
|
|
4426
4429
|
evaluatedDimensions: {
|
|
4427
4430
|
purpose: true,
|
|
4428
4431
|
scope: !!this.policy.scope,
|
|
@@ -4521,7 +4524,7 @@ var LocalEvaluator = class {
|
|
|
4521
4524
|
}
|
|
4522
4525
|
}
|
|
4523
4526
|
if ((context.purpose === "file.read" || context.purpose === "file.write" || context.purpose === "file.delete") && context.target) {
|
|
4524
|
-
const targetLower = context.target.toLowerCase();
|
|
4527
|
+
const targetLower = context.target.toLowerCase().replace(/\\/g, "/");
|
|
4525
4528
|
for (const sensitivePath of SENSITIVE_PATHS) {
|
|
4526
4529
|
if (targetLower.includes(sensitivePath.toLowerCase())) {
|
|
4527
4530
|
score = Math.max(score, 50);
|
|
@@ -4550,12 +4553,20 @@ var LocalEvaluator = class {
|
|
|
4550
4553
|
matchesAnyPattern(value, patterns) {
|
|
4551
4554
|
return patterns.some((pattern) => this.matchGlob(value, pattern));
|
|
4552
4555
|
}
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4556
|
+
homePrefix() {
|
|
4557
|
+
if (this.cachedHomePrefix !== void 0) return this.cachedHomePrefix;
|
|
4558
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
4559
|
+
const home = env?.HOME || env?.USERPROFILE;
|
|
4560
|
+
this.cachedHomePrefix = home ? home.replace(/\\/g, "/") : null;
|
|
4561
|
+
return this.cachedHomePrefix;
|
|
4562
|
+
}
|
|
4558
4563
|
matchGlob(value, pattern) {
|
|
4564
|
+
value = value.replace(/\\/g, "/");
|
|
4565
|
+
pattern = pattern.replace(/\\/g, "/");
|
|
4566
|
+
if (pattern === "~" || pattern.startsWith("~/")) {
|
|
4567
|
+
const home = this.homePrefix();
|
|
4568
|
+
if (home) pattern = home + pattern.slice(1);
|
|
4569
|
+
}
|
|
4559
4570
|
if (pattern === value) return true;
|
|
4560
4571
|
const starCount = (pattern.match(/\*/g) ?? []).length;
|
|
4561
4572
|
if (starCount > 8) {
|
|
@@ -4598,7 +4609,7 @@ function getTrustLevel(score) {
|
|
|
4598
4609
|
}
|
|
4599
4610
|
|
|
4600
4611
|
// src/version.ts
|
|
4601
|
-
var SDK_VERSION = "3.
|
|
4612
|
+
var SDK_VERSION = "3.12.0";
|
|
4602
4613
|
|
|
4603
4614
|
// src/well-known.ts
|
|
4604
4615
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -4765,6 +4776,7 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
4765
4776
|
}
|
|
4766
4777
|
] : void 0,
|
|
4767
4778
|
correlationId: options.correlationId,
|
|
4779
|
+
attemptId: options.attemptId,
|
|
4768
4780
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
4769
4781
|
};
|
|
4770
4782
|
}
|
|
@@ -4794,6 +4806,8 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4794
4806
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
4795
4807
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
4796
4808
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
4809
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
4810
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
4797
4811
|
body.sdkVersion = SDK_VERSION;
|
|
4798
4812
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
4799
4813
|
const meta = {
|
|
@@ -4821,6 +4835,9 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4821
4835
|
if (response.status === 410) {
|
|
4822
4836
|
return {
|
|
4823
4837
|
success: true,
|
|
4838
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
4839
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
4840
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
4824
4841
|
access: {
|
|
4825
4842
|
allowed: false,
|
|
4826
4843
|
accessLevel: "none",
|
|
@@ -4839,7 +4856,8 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4839
4856
|
return {
|
|
4840
4857
|
success: false,
|
|
4841
4858
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
4842
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
4859
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4860
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
4843
4861
|
};
|
|
4844
4862
|
}
|
|
4845
4863
|
return data;
|
|
@@ -4873,7 +4891,13 @@ async function verify(config, request2, options) {
|
|
|
4873
4891
|
if (mergedConfig.debug) {
|
|
4874
4892
|
console.log("[VerificationGateway] Returning cached result");
|
|
4875
4893
|
}
|
|
4876
|
-
|
|
4894
|
+
const hit = { ...cached };
|
|
4895
|
+
if (request2.attemptId) {
|
|
4896
|
+
hit.attemptId = request2.attemptId;
|
|
4897
|
+
} else {
|
|
4898
|
+
delete hit.attemptId;
|
|
4899
|
+
}
|
|
4900
|
+
return hit;
|
|
4877
4901
|
}
|
|
4878
4902
|
}
|
|
4879
4903
|
const enrichedRequest = { ...request2 };
|
|
@@ -4893,6 +4917,7 @@ async function verify(config, request2, options) {
|
|
|
4893
4917
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
4894
4918
|
source: "api_error",
|
|
4895
4919
|
correlationId: apiResponse.correlationId,
|
|
4920
|
+
attemptId: apiResponse.attemptId,
|
|
4896
4921
|
urls
|
|
4897
4922
|
});
|
|
4898
4923
|
}
|
|
@@ -4928,6 +4953,9 @@ async function verify(config, request2, options) {
|
|
|
4928
4953
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4929
4954
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4930
4955
|
correlationId: apiResponse.correlationId,
|
|
4956
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
4957
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
4958
|
+
attemptId: apiResponse.attemptId,
|
|
4931
4959
|
recommendation: apiResponse.recommendation,
|
|
4932
4960
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4933
4961
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4979,6 +5007,8 @@ async function verify(config, request2, options) {
|
|
|
4979
5007
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4980
5008
|
// (no session row exists for unverified callers).
|
|
4981
5009
|
correlationId: apiResponse.correlationId,
|
|
5010
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
5011
|
+
attemptId: apiResponse.attemptId,
|
|
4982
5012
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4983
5013
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4984
5014
|
recommendation: apiResponse.recommendation,
|
|
@@ -5362,13 +5392,29 @@ var TraceLogger = class {
|
|
|
5362
5392
|
*/
|
|
5363
5393
|
logEvaluation(context, decision) {
|
|
5364
5394
|
if (!this.enabled) return;
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5395
|
+
let event;
|
|
5396
|
+
try {
|
|
5397
|
+
event = {
|
|
5398
|
+
id: this.generateId(),
|
|
5399
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
5400
|
+
type: "evaluation",
|
|
5401
|
+
context: redactDeep(context),
|
|
5402
|
+
decision: redactDeep(decision)
|
|
5403
|
+
};
|
|
5404
|
+
} catch (err) {
|
|
5405
|
+
event = {
|
|
5406
|
+
id: this.generateId(),
|
|
5407
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
5408
|
+
type: "error",
|
|
5409
|
+
metadata: {
|
|
5410
|
+
error: `trace redaction failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
5411
|
+
recommendation: decision.recommendation,
|
|
5412
|
+
purpose: context.purpose,
|
|
5413
|
+
action: context.action
|
|
5414
|
+
}
|
|
5415
|
+
};
|
|
5416
|
+
}
|
|
5417
|
+
this.write(event);
|
|
5372
5418
|
}
|
|
5373
5419
|
/**
|
|
5374
5420
|
* Log a tool call the guard saw but did not govern. One line per skip
|
|
@@ -5410,17 +5456,34 @@ var TraceLogger = class {
|
|
|
5410
5456
|
});
|
|
5411
5457
|
}
|
|
5412
5458
|
write(event) {
|
|
5459
|
+
let line;
|
|
5460
|
+
try {
|
|
5461
|
+
line = JSON.stringify(event) + "\n";
|
|
5462
|
+
} catch {
|
|
5463
|
+
return;
|
|
5464
|
+
}
|
|
5413
5465
|
try {
|
|
5414
5466
|
const filePath = this.getCurrentFilePath();
|
|
5415
|
-
const line = JSON.stringify(event) + "\n";
|
|
5416
5467
|
if ((0, import_fs3.existsSync)(filePath)) {
|
|
5417
5468
|
const stats = (0, import_fs3.statSync)(filePath);
|
|
5418
5469
|
if (stats.size > MAX_FILE_SIZE) {
|
|
5419
5470
|
this.rotate();
|
|
5420
5471
|
}
|
|
5421
5472
|
}
|
|
5422
|
-
(0
|
|
5473
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
5474
|
+
try {
|
|
5475
|
+
(0, import_fs3.appendFileSync)(filePath, line);
|
|
5476
|
+
return;
|
|
5477
|
+
} catch {
|
|
5478
|
+
}
|
|
5479
|
+
}
|
|
5480
|
+
const fallbackPath = filePath.replace(/\.jsonl$/, `-r${process.pid}.jsonl`);
|
|
5481
|
+
(0, import_fs3.appendFileSync)(fallbackPath, line);
|
|
5423
5482
|
} catch {
|
|
5483
|
+
try {
|
|
5484
|
+
console.error(`[AstraSync TraceLogger] failed to persist trace line: ${line.trim()}`);
|
|
5485
|
+
} catch {
|
|
5486
|
+
}
|
|
5424
5487
|
}
|
|
5425
5488
|
}
|
|
5426
5489
|
getCurrentFilePath() {
|