@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.js
CHANGED
|
@@ -14,6 +14,19 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/exceptions.ts
|
|
17
|
+
function isReviewCompatibilityError(error) {
|
|
18
|
+
if (typeof error !== "object" && typeof error !== "function" || error === null) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return Object.getOwnPropertyDescriptor(
|
|
23
|
+
error,
|
|
24
|
+
REVIEW_COMPATIBILITY_ERROR_BRAND
|
|
25
|
+
)?.value === true;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
17
30
|
function parseErrorBody(body) {
|
|
18
31
|
try {
|
|
19
32
|
const parsed = JSON.parse(body);
|
|
@@ -30,7 +43,7 @@ function parseErrorBody(body) {
|
|
|
30
43
|
return { details: void 0, error: void 0, apiMessage: void 0 };
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
|
-
var MAX_PROMPT_DISPLAY_LEN, FirewallBlockedException, PromptBlockedException, SilmarilApiError;
|
|
46
|
+
var MAX_PROMPT_DISPLAY_LEN, FirewallBlockedException, PromptBlockedException, REVIEW_COMPATIBILITY_ERROR_BRAND, ReviewCompatibilityError, SilmarilApiError;
|
|
34
47
|
var init_exceptions = __esm({
|
|
35
48
|
"src/exceptions.ts"() {
|
|
36
49
|
"use strict";
|
|
@@ -66,6 +79,27 @@ var init_exceptions = __esm({
|
|
|
66
79
|
}
|
|
67
80
|
};
|
|
68
81
|
PromptBlockedException = FirewallBlockedException;
|
|
82
|
+
REVIEW_COMPATIBILITY_ERROR_BRAND = /* @__PURE__ */ Symbol.for(
|
|
83
|
+
"@silmaril-security/sdk/ReviewCompatibilityError"
|
|
84
|
+
);
|
|
85
|
+
ReviewCompatibilityError = class _ReviewCompatibilityError extends Error {
|
|
86
|
+
requestedReview;
|
|
87
|
+
acknowledgedReview;
|
|
88
|
+
constructor(requestedReview, acknowledgedReview) {
|
|
89
|
+
const detail = acknowledgedReview === void 0 ? "the response omitted its acknowledgement" : "the response acknowledgement did not match";
|
|
90
|
+
super(`Silmaril review compatibility error: ${detail} for requested ${requestedReview} review`);
|
|
91
|
+
this.name = "ReviewCompatibilityError";
|
|
92
|
+
this.requestedReview = requestedReview;
|
|
93
|
+
this.acknowledgedReview = acknowledgedReview;
|
|
94
|
+
Object.defineProperty(this, REVIEW_COMPATIBILITY_ERROR_BRAND, {
|
|
95
|
+
value: true,
|
|
96
|
+
enumerable: false,
|
|
97
|
+
configurable: false,
|
|
98
|
+
writable: false
|
|
99
|
+
});
|
|
100
|
+
Object.setPrototypeOf(this, _ReviewCompatibilityError.prototype);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
69
103
|
SilmarilApiError = class _SilmarilApiError extends Error {
|
|
70
104
|
status;
|
|
71
105
|
statusText;
|
|
@@ -282,6 +316,9 @@ async function createLangChainHandler(firewall, options = {}) {
|
|
|
282
316
|
...toolName !== void 0 ? { toolName } : {}
|
|
283
317
|
});
|
|
284
318
|
} catch (err) {
|
|
319
|
+
if (isReviewCompatibilityError(err)) {
|
|
320
|
+
throw err;
|
|
321
|
+
}
|
|
285
322
|
if (!failOpen) {
|
|
286
323
|
throw err;
|
|
287
324
|
}
|
|
@@ -766,12 +803,32 @@ function sanitizeText(text) {
|
|
|
766
803
|
}
|
|
767
804
|
|
|
768
805
|
// src/firewall.ts
|
|
769
|
-
var SDK_VERSION = "0.7.
|
|
806
|
+
var SDK_VERSION = "0.7.8";
|
|
770
807
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
771
808
|
var DEFAULT_MAX_RETRIES = 5;
|
|
772
809
|
var MAX_BACKOFF_SECONDS = 30;
|
|
773
810
|
var MAX_ERROR_BODY_BYTES = 1 << 16;
|
|
774
811
|
var MAX_TIMEOUT_MS = 2147483647;
|
|
812
|
+
function validateReview(value, name) {
|
|
813
|
+
if (value === void 0) {
|
|
814
|
+
return void 0;
|
|
815
|
+
}
|
|
816
|
+
if (value !== "standard" && value !== "deep") {
|
|
817
|
+
throw new Error(`Firewall: ${name} must be standard or deep`);
|
|
818
|
+
}
|
|
819
|
+
return value;
|
|
820
|
+
}
|
|
821
|
+
function resolveReview(perCallReview, clientReview) {
|
|
822
|
+
return perCallReview === void 0 ? clientReview : validateReview(perCallReview, "review");
|
|
823
|
+
}
|
|
824
|
+
function verifyReviewAcknowledgement(acknowledgedReview, requestedReview) {
|
|
825
|
+
if (requestedReview !== void 0 && acknowledgedReview !== requestedReview) {
|
|
826
|
+
throw new ReviewCompatibilityError(requestedReview, acknowledgedReview);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
function reviewAcknowledgementFromResponse(response) {
|
|
830
|
+
return isRecord2(response) ? response.review : void 0;
|
|
831
|
+
}
|
|
775
832
|
function resolveMode(value, requestedMode) {
|
|
776
833
|
let responseMode;
|
|
777
834
|
if (value === "shadow" || value === "warn" || value === "block") {
|
|
@@ -784,7 +841,7 @@ function resolveMode(value, requestedMode) {
|
|
|
784
841
|
function legacyMode(shadowMode) {
|
|
785
842
|
return shadowMode === void 0 ? void 0 : shadowMode ? "shadow" : "block";
|
|
786
843
|
}
|
|
787
|
-
function blockResultFromResponse(data, requestedMode) {
|
|
844
|
+
function blockResultFromResponse(data, requestedMode, requestedReview) {
|
|
788
845
|
if (data.prediction !== "BENIGN" && data.prediction !== "MALICIOUS") {
|
|
789
846
|
throw new Error("Firewall: response prediction must be BENIGN or MALICIOUS");
|
|
790
847
|
}
|
|
@@ -793,6 +850,9 @@ function blockResultFromResponse(data, requestedMode) {
|
|
|
793
850
|
score: Number(data.score),
|
|
794
851
|
threshold: Number(data.threshold)
|
|
795
852
|
};
|
|
853
|
+
if (requestedReview !== void 0) {
|
|
854
|
+
result.review = requestedReview;
|
|
855
|
+
}
|
|
796
856
|
const mode = resolveMode(data.mode, requestedMode);
|
|
797
857
|
if (mode !== void 0) {
|
|
798
858
|
result.mode = mode;
|
|
@@ -818,7 +878,7 @@ function blockResultFromResponse(data, requestedMode) {
|
|
|
818
878
|
result.detectorCounts = detectorCounts;
|
|
819
879
|
}
|
|
820
880
|
}
|
|
821
|
-
if (data.governance !== void 0) {
|
|
881
|
+
if (data.governance !== void 0 && data.governance !== null) {
|
|
822
882
|
result.governance = governanceDecisionFromResponse(data.governance);
|
|
823
883
|
}
|
|
824
884
|
return Object.freeze(result);
|
|
@@ -842,8 +902,20 @@ function withSdkMetadata(metadata, info) {
|
|
|
842
902
|
};
|
|
843
903
|
return payload;
|
|
844
904
|
}
|
|
905
|
+
var GOVERNANCE_RESOURCE_KINDS = [
|
|
906
|
+
"agent",
|
|
907
|
+
"tool",
|
|
908
|
+
"mcp_server",
|
|
909
|
+
"mcp_tool",
|
|
910
|
+
"plugin",
|
|
911
|
+
"skill",
|
|
912
|
+
"extension"
|
|
913
|
+
];
|
|
914
|
+
function isGovernanceResourceKind(value) {
|
|
915
|
+
return typeof value === "string" && GOVERNANCE_RESOURCE_KINDS.includes(value);
|
|
916
|
+
}
|
|
845
917
|
function governanceResourceToWire(resource) {
|
|
846
|
-
if (!
|
|
918
|
+
if (!isGovernanceResourceKind(resource.kind)) {
|
|
847
919
|
throw new Error("Firewall: invalid governance resource kind");
|
|
848
920
|
}
|
|
849
921
|
if (typeof resource.id !== "string" || !resource.id.trim()) {
|
|
@@ -862,6 +934,38 @@ function governanceResourceToWire(resource) {
|
|
|
862
934
|
...resource.parentId === void 0 ? {} : { parent_id: resource.parentId }
|
|
863
935
|
};
|
|
864
936
|
}
|
|
937
|
+
function governanceResourceFromResponse(value) {
|
|
938
|
+
if (!isRecord2(value)) {
|
|
939
|
+
throw new Error("Firewall: response governance resource must be an object");
|
|
940
|
+
}
|
|
941
|
+
if (!isGovernanceResourceKind(value.kind)) {
|
|
942
|
+
throw new Error("Firewall: response governance resource has an invalid kind");
|
|
943
|
+
}
|
|
944
|
+
if (typeof value.id !== "string" || !value.id.trim()) {
|
|
945
|
+
throw new Error("Firewall: response governance resource id must be a non-empty string");
|
|
946
|
+
}
|
|
947
|
+
if (value.kind === "mcp_tool") {
|
|
948
|
+
if (typeof value.parent_id !== "string" || !value.parent_id.trim()) {
|
|
949
|
+
throw new Error(
|
|
950
|
+
"Firewall: response governance mcp_tool resource requires a non-empty parent_id"
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
return Object.freeze({
|
|
954
|
+
kind: value.kind,
|
|
955
|
+
id: value.id,
|
|
956
|
+
parentId: value.parent_id
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
if (value.parent_id !== void 0 && value.parent_id !== null) {
|
|
960
|
+
throw new Error(
|
|
961
|
+
"Firewall: response governance parent_id is valid only for mcp_tool resources"
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
return Object.freeze({
|
|
965
|
+
kind: value.kind,
|
|
966
|
+
id: value.id
|
|
967
|
+
});
|
|
968
|
+
}
|
|
865
969
|
function governanceContextToWire(context) {
|
|
866
970
|
return {
|
|
867
971
|
...context.agent === void 0 ? {} : { agent: context.agent },
|
|
@@ -880,13 +984,25 @@ function governanceDecisionFromResponse(value) {
|
|
|
880
984
|
if (typeof value.policy_version !== "string" || value.policy_version.length === 0) {
|
|
881
985
|
throw new Error("Firewall: response governance policy_version must be a non-empty string");
|
|
882
986
|
}
|
|
883
|
-
if (value.rule_id !== void 0 && typeof value.rule_id !== "string") {
|
|
987
|
+
if (value.rule_id !== void 0 && value.rule_id !== null && typeof value.rule_id !== "string") {
|
|
884
988
|
throw new Error("Firewall: response governance rule_id must be a string when provided");
|
|
885
989
|
}
|
|
990
|
+
if (value.identity_revision !== void 0 && value.identity_revision !== null && typeof value.identity_revision !== "string") {
|
|
991
|
+
throw new Error(
|
|
992
|
+
"Firewall: response governance identity_revision must be a string when provided"
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
if (value.reason !== void 0 && value.reason !== null && typeof value.reason !== "string") {
|
|
996
|
+
throw new Error("Firewall: response governance reason must be a string when provided");
|
|
997
|
+
}
|
|
998
|
+
const resource = value.resource === void 0 || value.resource === null ? void 0 : governanceResourceFromResponse(value.resource);
|
|
886
999
|
return Object.freeze({
|
|
887
1000
|
action: value.action,
|
|
888
|
-
...value.rule_id === void 0 ? {} : { ruleId: value.rule_id },
|
|
889
|
-
policyVersion: value.policy_version
|
|
1001
|
+
...value.rule_id === void 0 || value.rule_id === null ? {} : { ruleId: value.rule_id },
|
|
1002
|
+
policyVersion: value.policy_version,
|
|
1003
|
+
...resource === void 0 ? {} : { resource },
|
|
1004
|
+
...value.identity_revision === void 0 || value.identity_revision === null ? {} : { identityRevision: value.identity_revision },
|
|
1005
|
+
...value.reason === void 0 || value.reason === null ? {} : { reason: value.reason }
|
|
890
1006
|
});
|
|
891
1007
|
}
|
|
892
1008
|
async function readCappedErrorBody(response) {
|
|
@@ -1011,6 +1127,7 @@ var Firewall = class {
|
|
|
1011
1127
|
timeoutMs;
|
|
1012
1128
|
shadowMode;
|
|
1013
1129
|
mode;
|
|
1130
|
+
review;
|
|
1014
1131
|
headers;
|
|
1015
1132
|
constructor(options) {
|
|
1016
1133
|
if (!options.apiKey) {
|
|
@@ -1031,6 +1148,7 @@ var Firewall = class {
|
|
|
1031
1148
|
);
|
|
1032
1149
|
}
|
|
1033
1150
|
this.mode = options.mode ?? legacyMode(options.shadowMode);
|
|
1151
|
+
this.review = validateReview(options.review, "review");
|
|
1034
1152
|
this.shadowMode = this.mode === "shadow";
|
|
1035
1153
|
this.headers = Object.freeze({
|
|
1036
1154
|
"x-api-key": this.apiKey,
|
|
@@ -1070,9 +1188,13 @@ var Firewall = class {
|
|
|
1070
1188
|
texts: texts.map((text) => sanitizeText(text))
|
|
1071
1189
|
};
|
|
1072
1190
|
const requestedMode = options.mode ?? this.mode;
|
|
1191
|
+
const requestedReview = resolveReview(options.review, this.review);
|
|
1073
1192
|
if (requestedMode !== void 0) {
|
|
1074
1193
|
payload.mode = requestedMode;
|
|
1075
1194
|
}
|
|
1195
|
+
if (requestedReview !== void 0) {
|
|
1196
|
+
payload.review = requestedReview;
|
|
1197
|
+
}
|
|
1076
1198
|
if (options.hooks && options.hooks.length > 0) {
|
|
1077
1199
|
payload.hooks = options.hooks.map((h) => String(h));
|
|
1078
1200
|
}
|
|
@@ -1092,6 +1214,7 @@ var Firewall = class {
|
|
|
1092
1214
|
);
|
|
1093
1215
|
}
|
|
1094
1216
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1217
|
+
verifyReviewAcknowledgement(reviewAcknowledgementFromResponse(data), requestedReview);
|
|
1095
1218
|
if (!Array.isArray(data.predictions)) {
|
|
1096
1219
|
throw new Error("Firewall: response predictions must be an array");
|
|
1097
1220
|
}
|
|
@@ -1100,7 +1223,9 @@ var Firewall = class {
|
|
|
1100
1223
|
`Firewall: response predictions length ${data.predictions.length} does not match submitted texts length ${payload.texts.length}`
|
|
1101
1224
|
);
|
|
1102
1225
|
}
|
|
1103
|
-
return data.predictions.map(
|
|
1226
|
+
return data.predictions.map(
|
|
1227
|
+
(p) => blockResultFromResponse(p, requestedMode, requestedReview)
|
|
1228
|
+
);
|
|
1104
1229
|
}
|
|
1105
1230
|
asLangChainHandler(options = {}) {
|
|
1106
1231
|
return Promise.resolve().then(() => (init_langchain(), langchain_exports)).then(
|
|
@@ -1150,9 +1275,13 @@ var Firewall = class {
|
|
|
1150
1275
|
async classifySingle(text, options, metadataInfo) {
|
|
1151
1276
|
const payload = { text };
|
|
1152
1277
|
const requestedMode = options.mode ?? this.mode;
|
|
1278
|
+
const requestedReview = resolveReview(options.review, this.review);
|
|
1153
1279
|
if (requestedMode !== void 0) {
|
|
1154
1280
|
payload.mode = requestedMode;
|
|
1155
1281
|
}
|
|
1282
|
+
if (requestedReview !== void 0) {
|
|
1283
|
+
payload.review = requestedReview;
|
|
1284
|
+
}
|
|
1156
1285
|
if (options.hook !== void 0) {
|
|
1157
1286
|
payload.hook = options.hook;
|
|
1158
1287
|
}
|
|
@@ -1167,7 +1296,8 @@ var Firewall = class {
|
|
|
1167
1296
|
...options.governance === void 0 ? {} : { governance: options.governance }
|
|
1168
1297
|
});
|
|
1169
1298
|
const data = await this.postWithRetry(payload, options.signal);
|
|
1170
|
-
|
|
1299
|
+
verifyReviewAcknowledgement(reviewAcknowledgementFromResponse(data), requestedReview);
|
|
1300
|
+
return blockResultFromResponse(data, requestedMode, requestedReview);
|
|
1171
1301
|
}
|
|
1172
1302
|
};
|
|
1173
1303
|
|
|
@@ -1190,6 +1320,7 @@ export {
|
|
|
1190
1320
|
Outcome,
|
|
1191
1321
|
PRIMARY_OUTCOMES,
|
|
1192
1322
|
PromptBlockedException,
|
|
1323
|
+
ReviewCompatibilityError,
|
|
1193
1324
|
SilmarilApiError,
|
|
1194
1325
|
isHarmfulOutcome,
|
|
1195
1326
|
isPrimaryOutcome,
|