@silmaril-security/sdk 0.7.6 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +59 -3
- package/dist/adapters/deepagents.cjs +19 -0
- package/dist/adapters/deepagents.cjs.map +1 -1
- package/dist/adapters/deepagents.d.cts +1 -1
- package/dist/adapters/deepagents.d.ts +1 -1
- package/dist/adapters/deepagents.js +19 -0
- package/dist/adapters/deepagents.js.map +1 -1
- package/dist/adapters/langchain.cjs +19 -0
- package/dist/adapters/langchain.cjs.map +1 -1
- package/dist/adapters/langchain.d.cts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/langchain.js +19 -0
- package/dist/adapters/langchain.js.map +1 -1
- package/dist/adapters/vercel.cjs.map +1 -1
- package/dist/adapters/vercel.d.cts +1 -1
- package/dist/adapters/vercel.d.ts +1 -1
- package/dist/adapters/vercel.js.map +1 -1
- package/dist/{firewall-CRADRBLY.d.cts → firewall-DqjD6aXD.d.cts} +14 -1
- package/dist/{firewall-CRADRBLY.d.ts → firewall-DqjD6aXD.d.ts} +14 -1
- package/dist/index.cjs +142 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +141 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
36
36
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
37
|
|
|
38
38
|
// src/exceptions.ts
|
|
39
|
+
function isReviewCompatibilityError(error) {
|
|
40
|
+
if (typeof error !== "object" && typeof error !== "function" || error === null) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return Object.getOwnPropertyDescriptor(
|
|
45
|
+
error,
|
|
46
|
+
REVIEW_COMPATIBILITY_ERROR_BRAND
|
|
47
|
+
)?.value === true;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
39
52
|
function parseErrorBody(body) {
|
|
40
53
|
try {
|
|
41
54
|
const parsed = JSON.parse(body);
|
|
@@ -52,7 +65,7 @@ function parseErrorBody(body) {
|
|
|
52
65
|
return { details: void 0, error: void 0, apiMessage: void 0 };
|
|
53
66
|
}
|
|
54
67
|
}
|
|
55
|
-
var MAX_PROMPT_DISPLAY_LEN, FirewallBlockedException, PromptBlockedException, SilmarilApiError;
|
|
68
|
+
var MAX_PROMPT_DISPLAY_LEN, FirewallBlockedException, PromptBlockedException, REVIEW_COMPATIBILITY_ERROR_BRAND, ReviewCompatibilityError, SilmarilApiError;
|
|
56
69
|
var init_exceptions = __esm({
|
|
57
70
|
"src/exceptions.ts"() {
|
|
58
71
|
"use strict";
|
|
@@ -88,6 +101,27 @@ var init_exceptions = __esm({
|
|
|
88
101
|
}
|
|
89
102
|
};
|
|
90
103
|
PromptBlockedException = FirewallBlockedException;
|
|
104
|
+
REVIEW_COMPATIBILITY_ERROR_BRAND = /* @__PURE__ */ Symbol.for(
|
|
105
|
+
"@silmaril-security/sdk/ReviewCompatibilityError"
|
|
106
|
+
);
|
|
107
|
+
ReviewCompatibilityError = class _ReviewCompatibilityError extends Error {
|
|
108
|
+
requestedReview;
|
|
109
|
+
acknowledgedReview;
|
|
110
|
+
constructor(requestedReview, acknowledgedReview) {
|
|
111
|
+
const detail = acknowledgedReview === void 0 ? "the response omitted its acknowledgement" : "the response acknowledgement did not match";
|
|
112
|
+
super(`Silmaril review compatibility error: ${detail} for requested ${requestedReview} review`);
|
|
113
|
+
this.name = "ReviewCompatibilityError";
|
|
114
|
+
this.requestedReview = requestedReview;
|
|
115
|
+
this.acknowledgedReview = acknowledgedReview;
|
|
116
|
+
Object.defineProperty(this, REVIEW_COMPATIBILITY_ERROR_BRAND, {
|
|
117
|
+
value: true,
|
|
118
|
+
enumerable: false,
|
|
119
|
+
configurable: false,
|
|
120
|
+
writable: false
|
|
121
|
+
});
|
|
122
|
+
Object.setPrototypeOf(this, _ReviewCompatibilityError.prototype);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
91
125
|
SilmarilApiError = class _SilmarilApiError extends Error {
|
|
92
126
|
status;
|
|
93
127
|
statusText;
|
|
@@ -304,6 +338,9 @@ async function createLangChainHandler(firewall, options = {}) {
|
|
|
304
338
|
...toolName !== void 0 ? { toolName } : {}
|
|
305
339
|
});
|
|
306
340
|
} catch (err) {
|
|
341
|
+
if (isReviewCompatibilityError(err)) {
|
|
342
|
+
throw err;
|
|
343
|
+
}
|
|
307
344
|
if (!failOpen) {
|
|
308
345
|
throw err;
|
|
309
346
|
}
|
|
@@ -458,6 +495,7 @@ __export(src_exports, {
|
|
|
458
495
|
Outcome: () => Outcome,
|
|
459
496
|
PRIMARY_OUTCOMES: () => PRIMARY_OUTCOMES,
|
|
460
497
|
PromptBlockedException: () => PromptBlockedException,
|
|
498
|
+
ReviewCompatibilityError: () => ReviewCompatibilityError,
|
|
461
499
|
SilmarilApiError: () => SilmarilApiError,
|
|
462
500
|
isHarmfulOutcome: () => isHarmfulOutcome,
|
|
463
501
|
isPrimaryOutcome: () => isPrimaryOutcome,
|
|
@@ -818,12 +856,32 @@ function sanitizeText(text) {
|
|
|
818
856
|
}
|
|
819
857
|
|
|
820
858
|
// src/firewall.ts
|
|
821
|
-
var SDK_VERSION = "0.7.
|
|
859
|
+
var SDK_VERSION = "0.7.8";
|
|
822
860
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
823
861
|
var DEFAULT_MAX_RETRIES = 5;
|
|
824
862
|
var MAX_BACKOFF_SECONDS = 30;
|
|
825
863
|
var MAX_ERROR_BODY_BYTES = 1 << 16;
|
|
826
864
|
var MAX_TIMEOUT_MS = 2147483647;
|
|
865
|
+
function validateReview(value, name) {
|
|
866
|
+
if (value === void 0) {
|
|
867
|
+
return void 0;
|
|
868
|
+
}
|
|
869
|
+
if (value !== "standard" && value !== "deep") {
|
|
870
|
+
throw new Error(`Firewall: ${name} must be standard or deep`);
|
|
871
|
+
}
|
|
872
|
+
return value;
|
|
873
|
+
}
|
|
874
|
+
function resolveReview(perCallReview, clientReview) {
|
|
875
|
+
return perCallReview === void 0 ? clientReview : validateReview(perCallReview, "review");
|
|
876
|
+
}
|
|
877
|
+
function verifyReviewAcknowledgement(acknowledgedReview, requestedReview) {
|
|
878
|
+
if (requestedReview !== void 0 && acknowledgedReview !== requestedReview) {
|
|
879
|
+
throw new ReviewCompatibilityError(requestedReview, acknowledgedReview);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function reviewAcknowledgementFromResponse(response) {
|
|
883
|
+
return isRecord2(response) ? response.review : void 0;
|
|
884
|
+
}
|
|
827
885
|
function resolveMode(value, requestedMode) {
|
|
828
886
|
let responseMode;
|
|
829
887
|
if (value === "shadow" || value === "warn" || value === "block") {
|
|
@@ -836,7 +894,7 @@ function resolveMode(value, requestedMode) {
|
|
|
836
894
|
function legacyMode(shadowMode) {
|
|
837
895
|
return shadowMode === void 0 ? void 0 : shadowMode ? "shadow" : "block";
|
|
838
896
|
}
|
|
839
|
-
function blockResultFromResponse(data, requestedMode) {
|
|
897
|
+
function blockResultFromResponse(data, requestedMode, requestedReview) {
|
|
840
898
|
if (data.prediction !== "BENIGN" && data.prediction !== "MALICIOUS") {
|
|
841
899
|
throw new Error("Firewall: response prediction must be BENIGN or MALICIOUS");
|
|
842
900
|
}
|
|
@@ -845,6 +903,9 @@ function blockResultFromResponse(data, requestedMode) {
|
|
|
845
903
|
score: Number(data.score),
|
|
846
904
|
threshold: Number(data.threshold)
|
|
847
905
|
};
|
|
906
|
+
if (requestedReview !== void 0) {
|
|
907
|
+
result.review = requestedReview;
|
|
908
|
+
}
|
|
848
909
|
const mode = resolveMode(data.mode, requestedMode);
|
|
849
910
|
if (mode !== void 0) {
|
|
850
911
|
result.mode = mode;
|
|
@@ -870,7 +931,7 @@ function blockResultFromResponse(data, requestedMode) {
|
|
|
870
931
|
result.detectorCounts = detectorCounts;
|
|
871
932
|
}
|
|
872
933
|
}
|
|
873
|
-
if (data.governance !== void 0) {
|
|
934
|
+
if (data.governance !== void 0 && data.governance !== null) {
|
|
874
935
|
result.governance = governanceDecisionFromResponse(data.governance);
|
|
875
936
|
}
|
|
876
937
|
return Object.freeze(result);
|
|
@@ -894,8 +955,20 @@ function withSdkMetadata(metadata, info) {
|
|
|
894
955
|
};
|
|
895
956
|
return payload;
|
|
896
957
|
}
|
|
958
|
+
var GOVERNANCE_RESOURCE_KINDS = [
|
|
959
|
+
"agent",
|
|
960
|
+
"tool",
|
|
961
|
+
"mcp_server",
|
|
962
|
+
"mcp_tool",
|
|
963
|
+
"plugin",
|
|
964
|
+
"skill",
|
|
965
|
+
"extension"
|
|
966
|
+
];
|
|
967
|
+
function isGovernanceResourceKind(value) {
|
|
968
|
+
return typeof value === "string" && GOVERNANCE_RESOURCE_KINDS.includes(value);
|
|
969
|
+
}
|
|
897
970
|
function governanceResourceToWire(resource) {
|
|
898
|
-
if (!
|
|
971
|
+
if (!isGovernanceResourceKind(resource.kind)) {
|
|
899
972
|
throw new Error("Firewall: invalid governance resource kind");
|
|
900
973
|
}
|
|
901
974
|
if (typeof resource.id !== "string" || !resource.id.trim()) {
|
|
@@ -914,6 +987,38 @@ function governanceResourceToWire(resource) {
|
|
|
914
987
|
...resource.parentId === void 0 ? {} : { parent_id: resource.parentId }
|
|
915
988
|
};
|
|
916
989
|
}
|
|
990
|
+
function governanceResourceFromResponse(value) {
|
|
991
|
+
if (!isRecord2(value)) {
|
|
992
|
+
throw new Error("Firewall: response governance resource must be an object");
|
|
993
|
+
}
|
|
994
|
+
if (!isGovernanceResourceKind(value.kind)) {
|
|
995
|
+
throw new Error("Firewall: response governance resource has an invalid kind");
|
|
996
|
+
}
|
|
997
|
+
if (typeof value.id !== "string" || !value.id.trim()) {
|
|
998
|
+
throw new Error("Firewall: response governance resource id must be a non-empty string");
|
|
999
|
+
}
|
|
1000
|
+
if (value.kind === "mcp_tool") {
|
|
1001
|
+
if (typeof value.parent_id !== "string" || !value.parent_id.trim()) {
|
|
1002
|
+
throw new Error(
|
|
1003
|
+
"Firewall: response governance mcp_tool resource requires a non-empty parent_id"
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
return Object.freeze({
|
|
1007
|
+
kind: value.kind,
|
|
1008
|
+
id: value.id,
|
|
1009
|
+
parentId: value.parent_id
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
if (value.parent_id !== void 0 && value.parent_id !== null) {
|
|
1013
|
+
throw new Error(
|
|
1014
|
+
"Firewall: response governance parent_id is valid only for mcp_tool resources"
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
return Object.freeze({
|
|
1018
|
+
kind: value.kind,
|
|
1019
|
+
id: value.id
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
917
1022
|
function governanceContextToWire(context) {
|
|
918
1023
|
return {
|
|
919
1024
|
...context.agent === void 0 ? {} : { agent: context.agent },
|
|
@@ -932,13 +1037,25 @@ function governanceDecisionFromResponse(value) {
|
|
|
932
1037
|
if (typeof value.policy_version !== "string" || value.policy_version.length === 0) {
|
|
933
1038
|
throw new Error("Firewall: response governance policy_version must be a non-empty string");
|
|
934
1039
|
}
|
|
935
|
-
if (value.rule_id !== void 0 && typeof value.rule_id !== "string") {
|
|
1040
|
+
if (value.rule_id !== void 0 && value.rule_id !== null && typeof value.rule_id !== "string") {
|
|
936
1041
|
throw new Error("Firewall: response governance rule_id must be a string when provided");
|
|
937
1042
|
}
|
|
1043
|
+
if (value.identity_revision !== void 0 && value.identity_revision !== null && typeof value.identity_revision !== "string") {
|
|
1044
|
+
throw new Error(
|
|
1045
|
+
"Firewall: response governance identity_revision must be a string when provided"
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
if (value.reason !== void 0 && value.reason !== null && typeof value.reason !== "string") {
|
|
1049
|
+
throw new Error("Firewall: response governance reason must be a string when provided");
|
|
1050
|
+
}
|
|
1051
|
+
const resource = value.resource === void 0 || value.resource === null ? void 0 : governanceResourceFromResponse(value.resource);
|
|
938
1052
|
return Object.freeze({
|
|
939
1053
|
action: value.action,
|
|
940
|
-
...value.rule_id === void 0 ? {} : { ruleId: value.rule_id },
|
|
941
|
-
policyVersion: value.policy_version
|
|
1054
|
+
...value.rule_id === void 0 || value.rule_id === null ? {} : { ruleId: value.rule_id },
|
|
1055
|
+
policyVersion: value.policy_version,
|
|
1056
|
+
...resource === void 0 ? {} : { resource },
|
|
1057
|
+
...value.identity_revision === void 0 || value.identity_revision === null ? {} : { identityRevision: value.identity_revision },
|
|
1058
|
+
...value.reason === void 0 || value.reason === null ? {} : { reason: value.reason }
|
|
942
1059
|
});
|
|
943
1060
|
}
|
|
944
1061
|
async function readCappedErrorBody(response) {
|
|
@@ -1063,6 +1180,7 @@ var Firewall = class {
|
|
|
1063
1180
|
timeoutMs;
|
|
1064
1181
|
shadowMode;
|
|
1065
1182
|
mode;
|
|
1183
|
+
review;
|
|
1066
1184
|
headers;
|
|
1067
1185
|
constructor(options) {
|
|
1068
1186
|
if (!options.apiKey) {
|
|
@@ -1083,6 +1201,7 @@ var Firewall = class {
|
|
|
1083
1201
|
);
|
|
1084
1202
|
}
|
|
1085
1203
|
this.mode = options.mode ?? legacyMode(options.shadowMode);
|
|
1204
|
+
this.review = validateReview(options.review, "review");
|
|
1086
1205
|
this.shadowMode = this.mode === "shadow";
|
|
1087
1206
|
this.headers = Object.freeze({
|
|
1088
1207
|
"x-api-key": this.apiKey,
|
|
@@ -1122,9 +1241,13 @@ var Firewall = class {
|
|
|
1122
1241
|
texts: texts.map((text) => sanitizeText(text))
|
|
1123
1242
|
};
|
|
1124
1243
|
const requestedMode = options.mode ?? this.mode;
|
|
1244
|
+
const requestedReview = resolveReview(options.review, this.review);
|
|
1125
1245
|
if (requestedMode !== void 0) {
|
|
1126
1246
|
payload.mode = requestedMode;
|
|
1127
1247
|
}
|
|
1248
|
+
if (requestedReview !== void 0) {
|
|
1249
|
+
payload.review = requestedReview;
|
|
1250
|
+
}
|
|
1128
1251
|
if (options.hooks && options.hooks.length > 0) {
|
|
1129
1252
|
payload.hooks = options.hooks.map((h) => String(h));
|
|
1130
1253
|
}
|
|
@@ -1144,6 +1267,7 @@ var Firewall = class {
|
|
|
1144
1267
|
);
|
|
1145
1268
|
}
|
|
1146
1269
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1270
|
+
verifyReviewAcknowledgement(reviewAcknowledgementFromResponse(data), requestedReview);
|
|
1147
1271
|
if (!Array.isArray(data.predictions)) {
|
|
1148
1272
|
throw new Error("Firewall: response predictions must be an array");
|
|
1149
1273
|
}
|
|
@@ -1152,7 +1276,9 @@ var Firewall = class {
|
|
|
1152
1276
|
`Firewall: response predictions length ${data.predictions.length} does not match submitted texts length ${payload.texts.length}`
|
|
1153
1277
|
);
|
|
1154
1278
|
}
|
|
1155
|
-
return data.predictions.map(
|
|
1279
|
+
return data.predictions.map(
|
|
1280
|
+
(p) => blockResultFromResponse(p, requestedMode, requestedReview)
|
|
1281
|
+
);
|
|
1156
1282
|
}
|
|
1157
1283
|
asLangChainHandler(options = {}) {
|
|
1158
1284
|
return Promise.resolve().then(() => (init_langchain(), langchain_exports)).then(
|
|
@@ -1202,9 +1328,13 @@ var Firewall = class {
|
|
|
1202
1328
|
async classifySingle(text, options, metadataInfo) {
|
|
1203
1329
|
const payload = { text };
|
|
1204
1330
|
const requestedMode = options.mode ?? this.mode;
|
|
1331
|
+
const requestedReview = resolveReview(options.review, this.review);
|
|
1205
1332
|
if (requestedMode !== void 0) {
|
|
1206
1333
|
payload.mode = requestedMode;
|
|
1207
1334
|
}
|
|
1335
|
+
if (requestedReview !== void 0) {
|
|
1336
|
+
payload.review = requestedReview;
|
|
1337
|
+
}
|
|
1208
1338
|
if (options.hook !== void 0) {
|
|
1209
1339
|
payload.hook = options.hook;
|
|
1210
1340
|
}
|
|
@@ -1219,7 +1349,8 @@ var Firewall = class {
|
|
|
1219
1349
|
...options.governance === void 0 ? {} : { governance: options.governance }
|
|
1220
1350
|
});
|
|
1221
1351
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1222
|
-
|
|
1352
|
+
verifyReviewAcknowledgement(reviewAcknowledgementFromResponse(data), requestedReview);
|
|
1353
|
+
return blockResultFromResponse(data, requestedMode, requestedReview);
|
|
1223
1354
|
}
|
|
1224
1355
|
};
|
|
1225
1356
|
|
|
@@ -1243,6 +1374,7 @@ init_hooks();
|
|
|
1243
1374
|
Outcome,
|
|
1244
1375
|
PRIMARY_OUTCOMES,
|
|
1245
1376
|
PromptBlockedException,
|
|
1377
|
+
ReviewCompatibilityError,
|
|
1246
1378
|
SilmarilApiError,
|
|
1247
1379
|
isHarmfulOutcome,
|
|
1248
1380
|
isPrimaryOutcome,
|