@silmaril-security/sdk 0.4.2 → 0.5.1
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 +21 -0
- package/README.md +32 -27
- package/dist/adapters/langchain.cjs +1 -1
- 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 +1 -1
- package/dist/adapters/langchain.js.map +1 -1
- package/dist/adapters/vercel.cjs +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 +1 -1
- package/dist/adapters/vercel.js.map +1 -1
- package/dist/{firewall-DfZCCDU6.d.cts → firewall-D2doJsD5.d.cts} +16 -7
- package/dist/{firewall-DfZCCDU6.d.ts → firewall-D2doJsD5.d.ts} +16 -7
- package/dist/index.cjs +73 -161
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -12
- package/dist/index.d.ts +3 -12
- package/dist/index.js +72 -151
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (fn, res) => function __init() {
|
|
4
|
-
|
|
3
|
+
var __esm = (fn, res, err) => function __init() {
|
|
4
|
+
if (err) throw err[0];
|
|
5
|
+
try {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
throw err = [e], e;
|
|
9
|
+
}
|
|
5
10
|
};
|
|
6
11
|
var __export = (target, all) => {
|
|
7
12
|
for (var name in all)
|
|
@@ -273,7 +278,7 @@ async function createLangChainHandler(firewall, options = {}) {
|
|
|
273
278
|
return;
|
|
274
279
|
}
|
|
275
280
|
const threshold = result.threshold;
|
|
276
|
-
const blocked = result.
|
|
281
|
+
const blocked = result.prediction === "MALICIOUS";
|
|
277
282
|
const commonEventFields = {
|
|
278
283
|
hook: hookLabel,
|
|
279
284
|
...toolName !== void 0 ? { toolName } : {},
|
|
@@ -492,7 +497,7 @@ function createMiddleware(firewall, options = {}) {
|
|
|
492
497
|
toolName !== void 0 ? { hook, toolName } : { hook }
|
|
493
498
|
);
|
|
494
499
|
const threshold = result.threshold;
|
|
495
|
-
const blocked = result.
|
|
500
|
+
const blocked = result.prediction === "MALICIOUS";
|
|
496
501
|
const commonEventFields = {
|
|
497
502
|
hook,
|
|
498
503
|
...toolName !== void 0 ? { toolName } : {},
|
|
@@ -618,78 +623,6 @@ function createMiddleware(firewall, options = {}) {
|
|
|
618
623
|
};
|
|
619
624
|
}
|
|
620
625
|
|
|
621
|
-
// src/chunking.ts
|
|
622
|
-
var CHARS_PER_TOKEN = 4;
|
|
623
|
-
var MAX_INPUT_TOKENS = 81920;
|
|
624
|
-
var CHUNK_WINDOW = 400;
|
|
625
|
-
var CHUNK_OVERLAP = 64;
|
|
626
|
-
var MAX_INPUT_CHARS = MAX_INPUT_TOKENS * CHARS_PER_TOKEN;
|
|
627
|
-
var CHUNK_WINDOW_CHARS = CHUNK_WINDOW * CHARS_PER_TOKEN;
|
|
628
|
-
var CHUNK_OVERLAP_CHARS = CHUNK_OVERLAP * CHARS_PER_TOKEN;
|
|
629
|
-
var CHUNK_STRIDE_CHARS = CHUNK_WINDOW_CHARS - CHUNK_OVERLAP_CHARS;
|
|
630
|
-
function isHighSurrogate(code) {
|
|
631
|
-
return code >= 55296 && code <= 56319;
|
|
632
|
-
}
|
|
633
|
-
function isLowSurrogate(code) {
|
|
634
|
-
return code >= 56320 && code <= 57343;
|
|
635
|
-
}
|
|
636
|
-
function sanitizeText(text) {
|
|
637
|
-
let out = "";
|
|
638
|
-
for (let i = 0; i < text.length; i++) {
|
|
639
|
-
const code = text.charCodeAt(i);
|
|
640
|
-
if (isHighSurrogate(code)) {
|
|
641
|
-
if (i + 1 < text.length && isLowSurrogate(text.charCodeAt(i + 1))) {
|
|
642
|
-
out += text[i];
|
|
643
|
-
out += text[i + 1];
|
|
644
|
-
i++;
|
|
645
|
-
}
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
if (isLowSurrogate(code)) {
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
out += text[i];
|
|
652
|
-
}
|
|
653
|
-
return out;
|
|
654
|
-
}
|
|
655
|
-
function safeChunkStart(text, start) {
|
|
656
|
-
if (start > 0 && start < text.length && isLowSurrogate(text.charCodeAt(start)) && isHighSurrogate(text.charCodeAt(start - 1))) {
|
|
657
|
-
return start + 1;
|
|
658
|
-
}
|
|
659
|
-
return start;
|
|
660
|
-
}
|
|
661
|
-
function safeChunkEnd(text, end) {
|
|
662
|
-
if (end > 0 && end < text.length && isHighSurrogate(text.charCodeAt(end - 1)) && isLowSurrogate(text.charCodeAt(end))) {
|
|
663
|
-
return end - 1;
|
|
664
|
-
}
|
|
665
|
-
return end;
|
|
666
|
-
}
|
|
667
|
-
function chunkText(text) {
|
|
668
|
-
text = sanitizeText(text);
|
|
669
|
-
const n = text.length;
|
|
670
|
-
if (n > MAX_INPUT_CHARS) {
|
|
671
|
-
throw new Error(
|
|
672
|
-
`Input has ~${Math.floor(n / CHARS_PER_TOKEN)} tokens (${n} chars); max is ${MAX_INPUT_TOKENS} tokens (${MAX_INPUT_CHARS} chars)`
|
|
673
|
-
);
|
|
674
|
-
}
|
|
675
|
-
if (n <= CHUNK_WINDOW_CHARS) {
|
|
676
|
-
return [text];
|
|
677
|
-
}
|
|
678
|
-
const chunks = [];
|
|
679
|
-
for (let start = 0; start < n; start += CHUNK_STRIDE_CHARS) {
|
|
680
|
-
const safeStart = safeChunkStart(text, start);
|
|
681
|
-
if (safeStart >= n) {
|
|
682
|
-
break;
|
|
683
|
-
}
|
|
684
|
-
const end = safeChunkEnd(text, safeStart + CHUNK_WINDOW_CHARS);
|
|
685
|
-
chunks.push(text.slice(safeStart, end));
|
|
686
|
-
if (end >= n) {
|
|
687
|
-
break;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
return chunks;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
626
|
// src/firewall.ts
|
|
694
627
|
init_exceptions();
|
|
695
628
|
|
|
@@ -700,7 +633,13 @@ var Outcome = {
|
|
|
700
633
|
SecretExposure: "secret_exposure",
|
|
701
634
|
ControlAbuse: "control_abuse",
|
|
702
635
|
SystemCompromise: "system_compromise",
|
|
703
|
-
ServiceDisruption: "service_disruption"
|
|
636
|
+
ServiceDisruption: "service_disruption",
|
|
637
|
+
CodeGeneration: "code_generation",
|
|
638
|
+
StoryScriptGeneration: "story_script_generation",
|
|
639
|
+
GameGeneration: "game_generation",
|
|
640
|
+
WebsiteGeneration: "website_generation",
|
|
641
|
+
ClickUpTermsViolation: "clickup_terms_violation",
|
|
642
|
+
TraditionalAiAbuse: "traditional_ai_abuse"
|
|
704
643
|
};
|
|
705
644
|
var PRIMARY_OUTCOMES = [
|
|
706
645
|
Outcome.Benign,
|
|
@@ -708,14 +647,26 @@ var PRIMARY_OUTCOMES = [
|
|
|
708
647
|
Outcome.SecretExposure,
|
|
709
648
|
Outcome.ControlAbuse,
|
|
710
649
|
Outcome.SystemCompromise,
|
|
711
|
-
Outcome.ServiceDisruption
|
|
650
|
+
Outcome.ServiceDisruption,
|
|
651
|
+
Outcome.CodeGeneration,
|
|
652
|
+
Outcome.StoryScriptGeneration,
|
|
653
|
+
Outcome.GameGeneration,
|
|
654
|
+
Outcome.WebsiteGeneration,
|
|
655
|
+
Outcome.ClickUpTermsViolation,
|
|
656
|
+
Outcome.TraditionalAiAbuse
|
|
712
657
|
];
|
|
713
658
|
var HARMFUL_OUTCOMES = [
|
|
714
659
|
Outcome.InformationDisclosure,
|
|
715
660
|
Outcome.SecretExposure,
|
|
716
661
|
Outcome.ControlAbuse,
|
|
717
662
|
Outcome.SystemCompromise,
|
|
718
|
-
Outcome.ServiceDisruption
|
|
663
|
+
Outcome.ServiceDisruption,
|
|
664
|
+
Outcome.CodeGeneration,
|
|
665
|
+
Outcome.StoryScriptGeneration,
|
|
666
|
+
Outcome.GameGeneration,
|
|
667
|
+
Outcome.WebsiteGeneration,
|
|
668
|
+
Outcome.ClickUpTermsViolation,
|
|
669
|
+
Outcome.TraditionalAiAbuse
|
|
719
670
|
];
|
|
720
671
|
var OUTCOME_DESCRIPTIONS = {
|
|
721
672
|
[Outcome.Benign]: "No harmful firewall outcome detected.",
|
|
@@ -723,7 +674,13 @@ var OUTCOME_DESCRIPTIONS = {
|
|
|
723
674
|
[Outcome.SecretExposure]: "Exposes credentials, tokens, API keys, cookies, passwords, signing keys, OAuth secrets, session material, or webhook secrets.",
|
|
724
675
|
[Outcome.ControlAbuse]: "Misuses authorized tools or user privileges to send, change, approve, delete, operate, or bypass policy/RBAC without a stronger outcome.",
|
|
725
676
|
[Outcome.SystemCompromise]: "Enables privilege escalation, account takeover, hostile integration or plugin takeover, persistence, lateral movement, attacker webhook registration, or code/plugin execution.",
|
|
726
|
-
[Outcome.ServiceDisruption]: "Causes downtime, lockout, degradation, alert suppression, destructive loops, resource exhaustion, cost spikes, or hidden outage evidence."
|
|
677
|
+
[Outcome.ServiceDisruption]: "Causes downtime, lockout, degradation, alert suppression, destructive loops, resource exhaustion, cost spikes, or hidden outage evidence.",
|
|
678
|
+
[Outcome.CodeGeneration]: "Requests generation or material modification of executable code, scripts, workflows, or configuration.",
|
|
679
|
+
[Outcome.StoryScriptGeneration]: "Requests generation of narrative prose, dialogue, scripts, or story artifacts.",
|
|
680
|
+
[Outcome.GameGeneration]: "Requests generation of a game, quest, level, mechanic, or playable experience.",
|
|
681
|
+
[Outcome.WebsiteGeneration]: "Requests generation of a website, landing page, storefront, or web experience.",
|
|
682
|
+
[Outcome.ClickUpTermsViolation]: "Requests content or actions that violate the configured ClickUp tenant policy.",
|
|
683
|
+
[Outcome.TraditionalAiAbuse]: "Requests unsafe AI assistance outside the concrete security outcome classes."
|
|
727
684
|
};
|
|
728
685
|
var PRIMARY_OUTCOME_SET = new Set(PRIMARY_OUTCOMES);
|
|
729
686
|
var HARMFUL_OUTCOME_SET = new Set(HARMFUL_OUTCOMES);
|
|
@@ -763,14 +720,42 @@ function normalizeHarmfulOutcomeMap(values, fieldName) {
|
|
|
763
720
|
return Object.freeze(out);
|
|
764
721
|
}
|
|
765
722
|
|
|
723
|
+
// src/sanitization.ts
|
|
724
|
+
function isHighSurrogate(code) {
|
|
725
|
+
return code >= 55296 && code <= 56319;
|
|
726
|
+
}
|
|
727
|
+
function isLowSurrogate(code) {
|
|
728
|
+
return code >= 56320 && code <= 57343;
|
|
729
|
+
}
|
|
730
|
+
function sanitizeText(text) {
|
|
731
|
+
let out = "";
|
|
732
|
+
for (let i = 0; i < text.length; i++) {
|
|
733
|
+
const code = text.charCodeAt(i);
|
|
734
|
+
if (isHighSurrogate(code)) {
|
|
735
|
+
if (i + 1 < text.length && isLowSurrogate(text.charCodeAt(i + 1))) {
|
|
736
|
+
out += text[i];
|
|
737
|
+
out += text[i + 1];
|
|
738
|
+
i++;
|
|
739
|
+
}
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
if (!isLowSurrogate(code)) {
|
|
743
|
+
out += text[i];
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
return out;
|
|
747
|
+
}
|
|
748
|
+
|
|
766
749
|
// src/firewall.ts
|
|
767
|
-
var SDK_VERSION = "0.
|
|
750
|
+
var SDK_VERSION = "0.5.1";
|
|
768
751
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
769
|
-
var DEFAULT_CHUNK_CONCURRENCY = 8;
|
|
770
752
|
var DEFAULT_MAX_RETRIES = 5;
|
|
771
753
|
var MAX_BACKOFF_SECONDS = 30;
|
|
772
754
|
var MAX_ERROR_BODY_BYTES = 1 << 16;
|
|
773
755
|
function blockResultFromResponse(data) {
|
|
756
|
+
if (data.prediction !== "BENIGN" && data.prediction !== "MALICIOUS") {
|
|
757
|
+
throw new Error("Firewall: response prediction must be BENIGN or MALICIOUS");
|
|
758
|
+
}
|
|
774
759
|
const result = {
|
|
775
760
|
prediction: data.prediction,
|
|
776
761
|
score: Number(data.score),
|
|
@@ -813,9 +798,7 @@ function withSdkMetadata(metadata, info) {
|
|
|
813
798
|
sdk_language: "typescript",
|
|
814
799
|
sdk_version: SDK_VERSION,
|
|
815
800
|
request_id: info.requestId,
|
|
816
|
-
input_index: info.inputIndex
|
|
817
|
-
chunk_index: info.chunkIndex,
|
|
818
|
-
chunk_count: info.chunkCount
|
|
801
|
+
...info.inputIndex === void 0 ? {} : { input_index: info.inputIndex }
|
|
819
802
|
};
|
|
820
803
|
return payload;
|
|
821
804
|
}
|
|
@@ -856,36 +839,10 @@ async function readCappedErrorBody(response) {
|
|
|
856
839
|
}
|
|
857
840
|
return new TextDecoder().decode(body);
|
|
858
841
|
}
|
|
859
|
-
async function mapWithConcurrency(items, concurrency, task) {
|
|
860
|
-
const results = new Array(items.length);
|
|
861
|
-
let nextIndex = 0;
|
|
862
|
-
let firstError;
|
|
863
|
-
const workerCount = Math.min(concurrency, items.length);
|
|
864
|
-
async function worker() {
|
|
865
|
-
for (; ; ) {
|
|
866
|
-
const index = nextIndex;
|
|
867
|
-
nextIndex += 1;
|
|
868
|
-
if (index >= items.length) {
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
try {
|
|
872
|
-
results[index] = await task(items[index], index);
|
|
873
|
-
} catch (err) {
|
|
874
|
-
firstError ??= err;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
879
|
-
if (firstError !== void 0) {
|
|
880
|
-
throw firstError;
|
|
881
|
-
}
|
|
882
|
-
return results;
|
|
883
|
-
}
|
|
884
842
|
var Firewall = class {
|
|
885
843
|
apiKey;
|
|
886
844
|
apiUrl;
|
|
887
845
|
timeoutMs;
|
|
888
|
-
chunkConcurrency;
|
|
889
846
|
shadowMode;
|
|
890
847
|
headers;
|
|
891
848
|
constructor(options) {
|
|
@@ -901,12 +858,6 @@ var Firewall = class {
|
|
|
901
858
|
if (typeof this.timeoutMs !== "number" || !Number.isFinite(this.timeoutMs) || this.timeoutMs < 0) {
|
|
902
859
|
throw new Error(`Firewall: timeoutMs must be a finite non-negative number, got ${this.timeoutMs}`);
|
|
903
860
|
}
|
|
904
|
-
this.chunkConcurrency = options.chunkConcurrency ?? DEFAULT_CHUNK_CONCURRENCY;
|
|
905
|
-
if (!Number.isInteger(this.chunkConcurrency) || this.chunkConcurrency < 1) {
|
|
906
|
-
throw new Error(
|
|
907
|
-
`Firewall: chunkConcurrency must be an integer >= 1, got ${this.chunkConcurrency}`
|
|
908
|
-
);
|
|
909
|
-
}
|
|
910
861
|
this.shadowMode = options.shadowMode ?? false;
|
|
911
862
|
this.headers = Object.freeze({
|
|
912
863
|
"x-api-key": this.apiKey,
|
|
@@ -914,27 +865,8 @@ var Firewall = class {
|
|
|
914
865
|
});
|
|
915
866
|
}
|
|
916
867
|
async classify(text, options = {}) {
|
|
917
|
-
const chunks = chunkText(text);
|
|
918
868
|
const requestId = options.requestId ?? randomUUID();
|
|
919
|
-
|
|
920
|
-
return this.classifySingleChunk(chunks[0], options, {
|
|
921
|
-
requestId,
|
|
922
|
-
inputIndex: 0,
|
|
923
|
-
chunkIndex: 0,
|
|
924
|
-
chunkCount: 1
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
|
-
const results = await mapWithConcurrency(
|
|
928
|
-
chunks,
|
|
929
|
-
this.chunkConcurrency,
|
|
930
|
-
(chunk, index) => this.classifySingleChunk(chunk, options, {
|
|
931
|
-
requestId,
|
|
932
|
-
inputIndex: 0,
|
|
933
|
-
chunkIndex: index,
|
|
934
|
-
chunkCount: chunks.length
|
|
935
|
-
})
|
|
936
|
-
);
|
|
937
|
-
return results.reduce((best, r) => r.score > best.score ? r : best);
|
|
869
|
+
return this.classifySingle(sanitizeText(text), options, { requestId });
|
|
938
870
|
}
|
|
939
871
|
async classifyBatch(texts, options = {}) {
|
|
940
872
|
if (texts.length === 0) {
|
|
@@ -968,9 +900,7 @@ var Firewall = class {
|
|
|
968
900
|
payload.metadata = texts.map(
|
|
969
901
|
(_, index) => withSdkMetadata(options.metadata?.[index], {
|
|
970
902
|
requestId,
|
|
971
|
-
inputIndex: index
|
|
972
|
-
chunkIndex: 0,
|
|
973
|
-
chunkCount: 1
|
|
903
|
+
inputIndex: index
|
|
974
904
|
})
|
|
975
905
|
);
|
|
976
906
|
const data = await this.postWithRetry(payload);
|
|
@@ -1009,7 +939,7 @@ var Firewall = class {
|
|
|
1009
939
|
}
|
|
1010
940
|
throw new Error("Firewall: exhausted retries (unreachable)");
|
|
1011
941
|
}
|
|
1012
|
-
async
|
|
942
|
+
async classifySingle(text, options, metadataInfo) {
|
|
1013
943
|
const payload = { text };
|
|
1014
944
|
if (options.hook !== void 0) {
|
|
1015
945
|
payload.hook = options.hook;
|
|
@@ -1028,11 +958,6 @@ init_exceptions();
|
|
|
1028
958
|
init_hooks();
|
|
1029
959
|
export {
|
|
1030
960
|
ALL_HOOKS,
|
|
1031
|
-
CHUNK_OVERLAP,
|
|
1032
|
-
CHUNK_OVERLAP_CHARS,
|
|
1033
|
-
CHUNK_WINDOW,
|
|
1034
|
-
CHUNK_WINDOW_CHARS,
|
|
1035
|
-
DEFAULT_CHUNK_CONCURRENCY,
|
|
1036
961
|
DEFAULT_HOOKS,
|
|
1037
962
|
DEFAULT_TIMEOUT_MS,
|
|
1038
963
|
FIREWALL_HOOK_TO_LABEL,
|
|
@@ -1042,15 +967,12 @@ export {
|
|
|
1042
967
|
HARMFUL_OUTCOMES,
|
|
1043
968
|
HookLabel,
|
|
1044
969
|
INPUT_HOOKS,
|
|
1045
|
-
MAX_INPUT_CHARS,
|
|
1046
|
-
MAX_INPUT_TOKENS,
|
|
1047
970
|
OUTCOME_DESCRIPTIONS,
|
|
1048
971
|
OUTPUT_HOOKS,
|
|
1049
972
|
Outcome,
|
|
1050
973
|
PRIMARY_OUTCOMES,
|
|
1051
974
|
PromptBlockedException,
|
|
1052
975
|
SilmarilApiError,
|
|
1053
|
-
chunkText,
|
|
1054
976
|
isHarmfulOutcome,
|
|
1055
977
|
isPrimaryOutcome,
|
|
1056
978
|
normalizeHarmfulOutcome,
|
|
@@ -1058,7 +980,6 @@ export {
|
|
|
1058
980
|
normalizePrimaryOutcome,
|
|
1059
981
|
prependHook,
|
|
1060
982
|
prependToolName,
|
|
1061
|
-
resolveHooks
|
|
1062
|
-
sanitizeText
|
|
983
|
+
resolveHooks
|
|
1063
984
|
};
|
|
1064
985
|
//# sourceMappingURL=index.js.map
|