@atbash/sdk 0.16.6-dev.0 → 0.17.0-dev.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/browser.d.mts +53 -0
- package/dist/browser.mjs +252 -95
- package/dist/index.d.mts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +258 -96
- package/dist/index.mjs +258 -96
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -3205,7 +3205,7 @@ function loadAgentFromFile(keyPath) {
|
|
|
3205
3205
|
// src-ts/normalize.ts
|
|
3206
3206
|
function normalizeVerdict(raw2) {
|
|
3207
3207
|
if (raw2 === null || raw2 === void 0) return "No verdict";
|
|
3208
|
-
const v = String(raw2).toUpperCase();
|
|
3208
|
+
const v = String(raw2).trim().toUpperCase();
|
|
3209
3209
|
if (v === "ALLOW" || v === "GREEN") return "ALLOW";
|
|
3210
3210
|
if (v === "HOLD" || v === "YELLOW") return "HOLD";
|
|
3211
3211
|
if (v === "BLOCK" || v === "RED") return "BLOCK";
|
|
@@ -3242,17 +3242,58 @@ function allowSignalsPermit(data) {
|
|
|
3242
3242
|
}
|
|
3243
3243
|
return signals.length === 0 || signals.every((value) => value === true);
|
|
3244
3244
|
}
|
|
3245
|
+
function explicitRefusal(data) {
|
|
3246
|
+
let hold = false;
|
|
3247
|
+
for (const source of decisionSources(data)) {
|
|
3248
|
+
const verdict = verdictOf(source);
|
|
3249
|
+
if (verdict === "BLOCK" || verdict === "RED") return "BLOCK";
|
|
3250
|
+
if (verdict === "HOLD" || verdict === "YELLOW") hold = true;
|
|
3251
|
+
const actionType = actionTypeOf(source);
|
|
3252
|
+
if (actionType === "block") return "BLOCK";
|
|
3253
|
+
if (actionType === "hold_for_user_confirm") hold = true;
|
|
3254
|
+
}
|
|
3255
|
+
if (!allowSignalsPermit(data)) return "BLOCK";
|
|
3256
|
+
return hold ? "HOLD" : "";
|
|
3257
|
+
}
|
|
3258
|
+
function decisionSources(data) {
|
|
3259
|
+
return [data, isRecord(data.decision) ? data.decision : {}];
|
|
3260
|
+
}
|
|
3261
|
+
function verdictOf(source) {
|
|
3262
|
+
return typeof source.verdict === "string" ? source.verdict.trim().toUpperCase() : "";
|
|
3263
|
+
}
|
|
3264
|
+
function actionTypeRank(actionType) {
|
|
3265
|
+
if (actionType === "block") return 4;
|
|
3266
|
+
if (actionType === "hold_for_user_confirm") return 3;
|
|
3267
|
+
if (actionType === "") return 1;
|
|
3268
|
+
if (actionType === "allow") return 0;
|
|
3269
|
+
return 2;
|
|
3270
|
+
}
|
|
3271
|
+
function actionTypeOf(source) {
|
|
3272
|
+
let winner = "";
|
|
3273
|
+
for (const key3 of ["action_type", "actionType"]) {
|
|
3274
|
+
const raw2 = source[key3];
|
|
3275
|
+
if (raw2 === void 0 || raw2 === null) continue;
|
|
3276
|
+
const actionType = normalizeActionType(raw2);
|
|
3277
|
+
if (actionTypeRank(actionType) > actionTypeRank(winner)) winner = actionType;
|
|
3278
|
+
}
|
|
3279
|
+
return winner;
|
|
3280
|
+
}
|
|
3245
3281
|
function wireActionType(data) {
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3282
|
+
for (const source of decisionSources(data)) {
|
|
3283
|
+
const actionType = actionTypeOf(source);
|
|
3284
|
+
if (actionType !== "") return actionType;
|
|
3285
|
+
}
|
|
3286
|
+
return "";
|
|
3249
3287
|
}
|
|
3250
3288
|
function isAuditTier(data) {
|
|
3251
3289
|
const absentVerdict = data.verdict === null || data.verdict === void 0;
|
|
3252
3290
|
return absentVerdict && data.status === "logged";
|
|
3253
3291
|
}
|
|
3292
|
+
function isAuditTierBody(data) {
|
|
3293
|
+
return isAuditTier(data);
|
|
3294
|
+
}
|
|
3254
3295
|
function canonicalAllow(data) {
|
|
3255
|
-
if (
|
|
3296
|
+
if (explicitRefusal(data) !== "") return false;
|
|
3256
3297
|
const actionType = wireActionType(data);
|
|
3257
3298
|
if (actionType && actionType !== "allow") return false;
|
|
3258
3299
|
if (isAuditTier(data)) return true;
|
|
@@ -3494,6 +3535,10 @@ var Atbash = class _Atbash {
|
|
|
3494
3535
|
orgEncryptionPubKey;
|
|
3495
3536
|
/** When true (default), `auditToolCall` denies on any error. */
|
|
3496
3537
|
failClosed;
|
|
3538
|
+
/** When true (default), an unenforced (audit-tier) answer is refused. */
|
|
3539
|
+
requireEnforcement;
|
|
3540
|
+
/** Overall deadline for one auditToolCall decision, in ms. */
|
|
3541
|
+
decisionTimeoutMs;
|
|
3497
3542
|
/** Org key learned from the last agent-exists check, for this agent only. */
|
|
3498
3543
|
_orgKeyFromChain = null;
|
|
3499
3544
|
debug;
|
|
@@ -3567,6 +3612,8 @@ var Atbash = class _Atbash {
|
|
|
3567
3612
|
this.verifyPubKey = validated.verifyPubKey ?? void 0;
|
|
3568
3613
|
this.orgEncryptionPubKey = options.orgEncryptionPubKey;
|
|
3569
3614
|
this.failClosed = options.failClosed !== false;
|
|
3615
|
+
this.requireEnforcement = options.requireEnforcement !== false;
|
|
3616
|
+
this.decisionTimeoutMs = options.decisionTimeoutMs ?? DEFAULT_DECISION_TIMEOUT_MS;
|
|
3570
3617
|
this.debug = options.debug === true;
|
|
3571
3618
|
this.logger = options.logger ?? {};
|
|
3572
3619
|
this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 12e4);
|
|
@@ -3657,6 +3704,8 @@ var Atbash = class _Atbash {
|
|
|
3657
3704
|
orgName: options.orgName,
|
|
3658
3705
|
verifyPubKey: validated.verifyPubKey ?? void 0,
|
|
3659
3706
|
failClosed: options.failClosed,
|
|
3707
|
+
requireEnforcement: options.requireEnforcement,
|
|
3708
|
+
decisionTimeoutMs: options.decisionTimeoutMs,
|
|
3660
3709
|
// ATBASH_DEBUG lets an operator turn diagnostics on without editing a
|
|
3661
3710
|
// host's plugin config, which is usually the harder half.
|
|
3662
3711
|
debug: options.debug ?? /^(1|true|yes)$/i.test(resolve("debug")),
|
|
@@ -3855,34 +3904,16 @@ var Atbash = class _Atbash {
|
|
|
3855
3904
|
}
|
|
3856
3905
|
if (!resp.ok) throw await this.httpError(resp);
|
|
3857
3906
|
const bodyBytes = Buffer.from(await resp.arrayBuffer());
|
|
3858
|
-
const verifyPubKey = options.verifyPubKey
|
|
3907
|
+
const verifyPubKey = this.effectiveVerifyKey(options.verifyPubKey);
|
|
3859
3908
|
if (verifyPubKey !== void 0) {
|
|
3860
|
-
|
|
3861
|
-
if (!sig) {
|
|
3862
|
-
throw new SignatureVerificationError(
|
|
3863
|
-
"missing X-Atbash-Signature header"
|
|
3864
|
-
);
|
|
3865
|
-
}
|
|
3866
|
-
let ok;
|
|
3867
|
-
try {
|
|
3868
|
-
ok = native.verifySignature(bodyBytes, sig, verifyPubKey);
|
|
3869
|
-
} catch (err) {
|
|
3870
|
-
throw new SignatureVerificationError(
|
|
3871
|
-
`signature verification threw: ${errorMessage(err)}`
|
|
3872
|
-
);
|
|
3873
|
-
}
|
|
3874
|
-
if (!ok) {
|
|
3875
|
-
throw new SignatureVerificationError(
|
|
3876
|
-
"signature does not verify against configured verifyPubKey"
|
|
3877
|
-
);
|
|
3878
|
-
}
|
|
3909
|
+
verifyResponseSignature(bodyBytes, resp, verifyPubKey);
|
|
3879
3910
|
}
|
|
3880
3911
|
const data = parseJson(bodyBytes);
|
|
3881
3912
|
const rawScore = data.score;
|
|
3882
3913
|
const score = typeof rawScore === "number" && Number.isInteger(rawScore) && rawScore >= 1 && rawScore <= 10 ? rawScore : void 0;
|
|
3883
3914
|
return {
|
|
3884
3915
|
verdict: normalizeVerdict(data.verdict),
|
|
3885
|
-
allow:
|
|
3916
|
+
allow: this.executable(data),
|
|
3886
3917
|
actionType: normalizeActionType(data.action_type),
|
|
3887
3918
|
reason: String(data.reason ?? ""),
|
|
3888
3919
|
confidence: Number(data.confidence ?? 0),
|
|
@@ -3893,7 +3924,8 @@ var Atbash = class _Atbash {
|
|
|
3893
3924
|
enforced: Boolean(data.enforced),
|
|
3894
3925
|
enforcementMode: String(data.enforcement_mode ?? ""),
|
|
3895
3926
|
status: String(data.status ?? ""),
|
|
3896
|
-
score
|
|
3927
|
+
score,
|
|
3928
|
+
refusal: explicitRefusal(data)
|
|
3897
3929
|
};
|
|
3898
3930
|
}
|
|
3899
3931
|
/* ── audit_tool_call (redact → judge → decision) ───────────────────────── */
|
|
@@ -3926,77 +3958,125 @@ var Atbash = class _Atbash {
|
|
|
3926
3958
|
}
|
|
3927
3959
|
try {
|
|
3928
3960
|
this.logger.info?.("[atbash] judge API called", { tool: toolName });
|
|
3929
|
-
const result = await
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
}
|
|
3944
|
-
return {
|
|
3945
|
-
allow: true,
|
|
3946
|
-
verdict: "ALLOW",
|
|
3947
|
-
reason: result.reason || "audit tier \u2014 request logged on-chain, no AI enforcement",
|
|
3948
|
-
toolCallId: result.toolCallId
|
|
3949
|
-
};
|
|
3950
|
-
}
|
|
3951
|
-
const action = result.actionType;
|
|
3952
|
-
if (action === "block") {
|
|
3961
|
+
const result = await withDeadline(
|
|
3962
|
+
this.judgeAction(actionText, contextText, {
|
|
3963
|
+
toolName,
|
|
3964
|
+
toolArgsJson: argsJson,
|
|
3965
|
+
orgName: this.orgName,
|
|
3966
|
+
// Passed through unredacted — caller vouches for the contents.
|
|
3967
|
+
resolved: input.resolved
|
|
3968
|
+
}),
|
|
3969
|
+
this.decisionTimeoutMs
|
|
3970
|
+
);
|
|
3971
|
+
return this.decide(result);
|
|
3972
|
+
} catch (err) {
|
|
3973
|
+
if (err instanceof SignatureVerificationError) {
|
|
3974
|
+
this.failJudge(errorMessage(err), err);
|
|
3953
3975
|
return {
|
|
3954
3976
|
allow: false,
|
|
3955
|
-
verdict: "
|
|
3956
|
-
reason:
|
|
3957
|
-
toolCallId: result.toolCallId
|
|
3977
|
+
verdict: "ERROR",
|
|
3978
|
+
reason: `The judge's reply failed its signature check (${errorMessage(err)}), so it was not trusted.`
|
|
3958
3979
|
};
|
|
3959
3980
|
}
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3981
|
+
return this.failJudge(errorMessage(err), err);
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
/**
|
|
3985
|
+
* The verify key for one call (R4, governor tier-2 review). A per-call key
|
|
3986
|
+
* may only narrow what the client accepts: on a client pinned to a judge
|
|
3987
|
+
* key it must be that same key, never a replacement; on an unpinned client
|
|
3988
|
+
* it adds the check.
|
|
3989
|
+
*/
|
|
3990
|
+
effectiveVerifyKey(perCall) {
|
|
3991
|
+
if (perCall === void 0) return this.verifyPubKey;
|
|
3992
|
+
const key3 = perCall.trim().toLowerCase();
|
|
3993
|
+
if (this.verifyPubKey !== void 0 && key3 !== this.verifyPubKey) {
|
|
3994
|
+
throw new SignatureVerificationError(
|
|
3995
|
+
"a per-call verifyPubKey cannot replace the judge key this client is pinned to"
|
|
3996
|
+
);
|
|
3997
|
+
}
|
|
3998
|
+
return key3;
|
|
3999
|
+
}
|
|
4000
|
+
/**
|
|
4001
|
+
* Collapse a judge result into a {@link Decision}. The most restrictive
|
|
4002
|
+
* signal wins (security review 2026-09-30, H1): `action_type`, `verdict`
|
|
4003
|
+
* and the canonical `allow` are each able to deny, and only a result where
|
|
4004
|
+
* all three agree may execute. A present `allow` / `decision.allow` that is
|
|
4005
|
+
* not exactly `true` is the judge declining to grant permission, so it
|
|
4006
|
+
* denies even under `failClosed: false` — that option relaxes *errors*, it
|
|
4007
|
+
* never overrides a refusal.
|
|
4008
|
+
*/
|
|
4009
|
+
decide(result) {
|
|
4010
|
+
const toolCallId = result.toolCallId;
|
|
4011
|
+
const deny = (verdict, reason) => ({
|
|
4012
|
+
allow: false,
|
|
4013
|
+
verdict,
|
|
4014
|
+
reason,
|
|
4015
|
+
toolCallId
|
|
4016
|
+
});
|
|
4017
|
+
const notGranted = "the judge response did not grant permission";
|
|
4018
|
+
const held = deny("HOLD", result.reason || "held for human confirmation");
|
|
4019
|
+
const blocked = deny("BLOCK", result.reason || notGranted);
|
|
4020
|
+
if (result.refusal === "BLOCK") return blocked;
|
|
4021
|
+
if (result.verdict === "No verdict") {
|
|
4022
|
+
if (result.actionType === "block") {
|
|
4023
|
+
return blocked;
|
|
4024
|
+
}
|
|
4025
|
+
if (result.actionType === "hold_for_user_confirm") {
|
|
4026
|
+
return held;
|
|
4027
|
+
}
|
|
4028
|
+
if (result.refusal === "HOLD") return held;
|
|
4029
|
+
if (result.status !== "logged") {
|
|
4030
|
+
return this.failJudge(
|
|
4031
|
+
`judge returned no verdict without an audit-tier marker (status: ${result.status || "absent"})`,
|
|
4032
|
+
void 0,
|
|
4033
|
+
toolCallId
|
|
4034
|
+
);
|
|
3967
4035
|
}
|
|
3968
|
-
if (
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
reason: result.reason,
|
|
3974
|
-
toolCallId: result.toolCallId
|
|
3975
|
-
};
|
|
3976
|
-
}
|
|
3977
|
-
if (result.verdict === "BLOCK") {
|
|
3978
|
-
return {
|
|
3979
|
-
allow: false,
|
|
3980
|
-
verdict: "BLOCK",
|
|
3981
|
-
reason: result.reason,
|
|
3982
|
-
toolCallId: result.toolCallId
|
|
3983
|
-
};
|
|
3984
|
-
}
|
|
4036
|
+
if (this.requireEnforcement) {
|
|
4037
|
+
this.logger.warn?.(
|
|
4038
|
+
"[atbash] judge did not enforce this action (audit tier) and requireEnforcement is on: denied",
|
|
4039
|
+
{ toolCallId }
|
|
4040
|
+
);
|
|
3985
4041
|
return {
|
|
3986
|
-
allow:
|
|
3987
|
-
verdict: "
|
|
3988
|
-
reason:
|
|
3989
|
-
toolCallId
|
|
4042
|
+
allow: false,
|
|
4043
|
+
verdict: "ERROR",
|
|
4044
|
+
reason: "Atbash logged this action but did not check it (audit-tier plan), and this client requires a checked decision. Upgrade the plan, or set requireEnforcement: false for log-only mode.",
|
|
4045
|
+
toolCallId
|
|
3990
4046
|
};
|
|
3991
4047
|
}
|
|
3992
|
-
return
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
4048
|
+
if (result.allow !== true) return deny("BLOCK", notGranted);
|
|
4049
|
+
return {
|
|
4050
|
+
allow: true,
|
|
4051
|
+
verdict: "ALLOW",
|
|
4052
|
+
reason: result.reason || "audit tier \u2014 request logged on-chain, no AI enforcement",
|
|
4053
|
+
toolCallId
|
|
4054
|
+
};
|
|
4055
|
+
}
|
|
4056
|
+
const action = result.actionType;
|
|
4057
|
+
if (action === "block") {
|
|
4058
|
+
return deny("BLOCK", result.reason || "Blocked by your organisation's Atbash policy.");
|
|
4059
|
+
}
|
|
4060
|
+
if (action === "hold_for_user_confirm") {
|
|
4061
|
+
return held;
|
|
4062
|
+
}
|
|
4063
|
+
if (result.refusal === "HOLD") return held;
|
|
4064
|
+
if (action === "allow") {
|
|
4065
|
+
if (result.verdict === "HOLD") return held;
|
|
4066
|
+
if (result.verdict === "BLOCK") return blocked;
|
|
4067
|
+
if (result.allow !== true) return deny("BLOCK", notGranted);
|
|
4068
|
+
return {
|
|
4069
|
+
allow: true,
|
|
4070
|
+
verdict: "ALLOW",
|
|
4071
|
+
reason: result.reason,
|
|
4072
|
+
toolCallId
|
|
4073
|
+
};
|
|
3999
4074
|
}
|
|
4075
|
+
return this.failJudge(
|
|
4076
|
+
"unrecognized action_type from judge",
|
|
4077
|
+
void 0,
|
|
4078
|
+
toolCallId
|
|
4079
|
+
);
|
|
4000
4080
|
}
|
|
4001
4081
|
/**
|
|
4002
4082
|
* One exit for every judge failure.
|
|
@@ -4008,18 +4088,30 @@ var Atbash = class _Atbash {
|
|
|
4008
4088
|
*/
|
|
4009
4089
|
failJudge(reason, cause, toolCallId) {
|
|
4010
4090
|
const api2 = cause instanceof AtbashAPIError ? cause : null;
|
|
4091
|
+
const userReason = userFacingReason(reason, api2);
|
|
4011
4092
|
const status = api2 ? ` status=${api2.status || "no-response"}` : "";
|
|
4093
|
+
const detail = this.debug ? ` detail=${truncate(reason, 500)}` : "";
|
|
4012
4094
|
const body = this.debug && api2?.body ? ` body=${truncate(api2.body, 500)}` : "";
|
|
4013
4095
|
this.logger.warn?.(
|
|
4014
|
-
`[atbash] judge API failed \u2014${status} reason=${truncate(
|
|
4096
|
+
`[atbash] judge API failed \u2014${status} reason=${truncate(userReason, 300)}${detail}${body}`,
|
|
4015
4097
|
{
|
|
4016
|
-
reason,
|
|
4017
|
-
...api2 ? { status: api2.status
|
|
4098
|
+
reason: userReason,
|
|
4099
|
+
...api2 ? { status: api2.status } : {},
|
|
4100
|
+
...this.debug && api2 ? { body: api2.body, detail: reason } : {},
|
|
4018
4101
|
endpoint: this.endpoint,
|
|
4019
4102
|
...toolCallId ? { toolCallId } : {}
|
|
4020
4103
|
}
|
|
4021
4104
|
);
|
|
4022
|
-
return this.fail(
|
|
4105
|
+
return this.fail(userReason, toolCallId);
|
|
4106
|
+
}
|
|
4107
|
+
/**
|
|
4108
|
+
* The canonical permission for a response body under this client's
|
|
4109
|
+
* settings: {@link canonicalAllow}, minus the audit tier when
|
|
4110
|
+
* `requireEnforcement` is on. Never more permissive than `auditToolCall`.
|
|
4111
|
+
*/
|
|
4112
|
+
executable(data) {
|
|
4113
|
+
if (!canonicalAllow(data)) return false;
|
|
4114
|
+
return !(this.requireEnforcement && isAuditTierBody(data));
|
|
4023
4115
|
}
|
|
4024
4116
|
fail(reason, toolCallId) {
|
|
4025
4117
|
return { allow: !this.failClosed, verdict: "ERROR", reason, toolCallId };
|
|
@@ -4045,11 +4137,16 @@ var Atbash = class _Atbash {
|
|
|
4045
4137
|
this.authHeaders(brid)
|
|
4046
4138
|
);
|
|
4047
4139
|
await this.raiseIfError(resp);
|
|
4048
|
-
const
|
|
4140
|
+
const bytes = Buffer.from(await resp.arrayBuffer());
|
|
4141
|
+
if (this.verifyPubKey !== void 0) {
|
|
4142
|
+
verifyResponseSignature(bytes, resp, this.verifyPubKey);
|
|
4143
|
+
}
|
|
4144
|
+
const parsed = tryParseJson(bytes.toString("utf-8"));
|
|
4145
|
+
const data = isRecord2(parsed) ? parsed : {};
|
|
4049
4146
|
return {
|
|
4050
4147
|
status: normalizeStatus(data.status),
|
|
4051
4148
|
verdict: normalizeVerdict(data.verdict),
|
|
4052
|
-
allow:
|
|
4149
|
+
allow: this.executable(data),
|
|
4053
4150
|
reason: String(data.reason ?? ""),
|
|
4054
4151
|
judgmentId: String(data.judgmentId ?? judgmentId),
|
|
4055
4152
|
onChain: optBool(data.onChain),
|
|
@@ -4524,6 +4621,66 @@ var Atbash = class _Atbash {
|
|
|
4524
4621
|
return native.containsEvasionCharacters(text);
|
|
4525
4622
|
}
|
|
4526
4623
|
};
|
|
4624
|
+
function userFacingReason(reason, api2) {
|
|
4625
|
+
if (api2 && api2.status > 0) {
|
|
4626
|
+
const where = ` (HTTP ${api2.status}${api2.path ? ` from ${api2.path}` : ""})`;
|
|
4627
|
+
const b = api2.body.toLowerCase();
|
|
4628
|
+
if (b.includes("agent not registered")) {
|
|
4629
|
+
return `Agent not registered with Atbash: onboard it in the Atbash dashboard${where}.`;
|
|
4630
|
+
}
|
|
4631
|
+
if (b.includes("jailed")) {
|
|
4632
|
+
return `This agent is jailed; unjail it in the Atbash dashboard${where}.`;
|
|
4633
|
+
}
|
|
4634
|
+
if (b.includes("agent has no policy") || b.includes("no policy configured")) {
|
|
4635
|
+
return `This agent has no policy; attach one in the Atbash dashboard${where}.`;
|
|
4636
|
+
}
|
|
4637
|
+
if (b.includes("audit tier") || b.includes("verdict disabled") || b.includes("verdict not supported")) {
|
|
4638
|
+
return `The organisation's plan does not include checked decisions${where}.`;
|
|
4639
|
+
}
|
|
4640
|
+
return `The Atbash judge answered with an error${where}, so the action was not approved.`;
|
|
4641
|
+
}
|
|
4642
|
+
const text = api2 ? api2.body || reason : reason;
|
|
4643
|
+
return truncate(text.replace(/https?:\/\/[^\s)]+/g, "the judge"), 300);
|
|
4644
|
+
}
|
|
4645
|
+
var DEFAULT_DECISION_TIMEOUT_MS = 6e4;
|
|
4646
|
+
async function withDeadline(p, ms) {
|
|
4647
|
+
let timer;
|
|
4648
|
+
const deadline = new Promise((_, reject) => {
|
|
4649
|
+
timer = setTimeout(
|
|
4650
|
+
() => reject(
|
|
4651
|
+
new Error(
|
|
4652
|
+
`The judge did not give a decision within ${Math.round(ms / 1e3)} s, so the action was not approved. Check the network, or raise decisionTimeoutMs.`
|
|
4653
|
+
)
|
|
4654
|
+
),
|
|
4655
|
+
ms
|
|
4656
|
+
);
|
|
4657
|
+
});
|
|
4658
|
+
p.catch(() => void 0);
|
|
4659
|
+
try {
|
|
4660
|
+
return await Promise.race([p, deadline]);
|
|
4661
|
+
} finally {
|
|
4662
|
+
clearTimeout(timer);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
function verifyResponseSignature(bodyBytes, resp, verifyPubKey) {
|
|
4666
|
+
const sig = resp.headers.get("X-Atbash-Signature");
|
|
4667
|
+
if (!sig) {
|
|
4668
|
+
throw new SignatureVerificationError("missing X-Atbash-Signature header");
|
|
4669
|
+
}
|
|
4670
|
+
let ok;
|
|
4671
|
+
try {
|
|
4672
|
+
ok = native.verifySignature(bodyBytes, sig, verifyPubKey);
|
|
4673
|
+
} catch (err) {
|
|
4674
|
+
throw new SignatureVerificationError(
|
|
4675
|
+
`signature verification threw: ${errorMessage(err)}`
|
|
4676
|
+
);
|
|
4677
|
+
}
|
|
4678
|
+
if (!ok) {
|
|
4679
|
+
throw new SignatureVerificationError(
|
|
4680
|
+
"signature does not verify against configured verifyPubKey"
|
|
4681
|
+
);
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4527
4684
|
function baseToolCall(raw2) {
|
|
4528
4685
|
return {
|
|
4529
4686
|
toolCallId: String(raw2.tool_call_id ?? ""),
|
|
@@ -4737,7 +4894,11 @@ async function scanMemory(entry, auth, opts) {
|
|
|
4737
4894
|
const atbash = new Atbash(auth.privkey, {
|
|
4738
4895
|
endpoint: opts?.endpoint,
|
|
4739
4896
|
verifyPubKey: opts?.verifyPubKey,
|
|
4740
|
-
orgName: opts?.orgName
|
|
4897
|
+
orgName: opts?.orgName,
|
|
4898
|
+
// Memory scans keep their existing audit-tier semantics (an audit-tier
|
|
4899
|
+
// scan is not a defect the scanner invents). Whether an unenforced scan
|
|
4900
|
+
// may commit memory is the memory-guard PR's decision, not H6's.
|
|
4901
|
+
requireEnforcement: false
|
|
4741
4902
|
});
|
|
4742
4903
|
const result = await atbash.judgeAction(request.prompt, request.context, {
|
|
4743
4904
|
toolName: opts?.toolName ?? "memory_write",
|
|
@@ -4773,6 +4934,7 @@ async function scanMemory(entry, auth, opts) {
|
|
|
4773
4934
|
verdict = "yellow";
|
|
4774
4935
|
}
|
|
4775
4936
|
}
|
|
4937
|
+
if (verdict === "green" && result.allow !== true) verdict = "red";
|
|
4776
4938
|
const parsed = native.parseScoreFromReason(result.reason);
|
|
4777
4939
|
const score = result.score ?? parsed.score ?? native.defaultScoreForVerdict(verdict);
|
|
4778
4940
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atbash/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0-dev.0",
|
|
4
4
|
"description": "TypeScript SDK for Atbash — the safety layer that evaluates AI agent actions against operator-defined policies before execution.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atbash",
|
|
@@ -90,10 +90,10 @@
|
|
|
90
90
|
"typescript-eslint": "^8.62.1"
|
|
91
91
|
},
|
|
92
92
|
"optionalDependencies": {
|
|
93
|
-
"@atbash/sdk-linux-x64-gnu": "0.
|
|
94
|
-
"@atbash/sdk-linux-arm64-gnu": "0.
|
|
95
|
-
"@atbash/sdk-linux-x64-musl": "0.
|
|
96
|
-
"@atbash/sdk-darwin-arm64": "0.
|
|
97
|
-
"@atbash/sdk-win32-x64-msvc": "0.
|
|
93
|
+
"@atbash/sdk-linux-x64-gnu": "0.17.0-dev.0",
|
|
94
|
+
"@atbash/sdk-linux-arm64-gnu": "0.17.0-dev.0",
|
|
95
|
+
"@atbash/sdk-linux-x64-musl": "0.17.0-dev.0",
|
|
96
|
+
"@atbash/sdk-darwin-arm64": "0.17.0-dev.0",
|
|
97
|
+
"@atbash/sdk-win32-x64-msvc": "0.17.0-dev.0"
|
|
98
98
|
}
|
|
99
99
|
}
|