@silmaril-security/sdk 0.7.5 → 0.7.7

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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.7.7
6
+
7
+ - Preserve optional governance response evidence for the canonical resource,
8
+ identity revision, and open-ended decision reason when supplied by the
9
+ serving runtime.
10
+
11
+ ## 0.7.6
12
+
13
+ - Send typed governance resources in the runtime's top-level `resource` and
14
+ aligned `resources` fields, preserving compatibility attribution metadata.
15
+ - Reject invalid canonical resource references before submitting a request.
16
+ Caller-supplied agent metadata remains attribution, not authenticated identity.
17
+
3
18
  All notable changes to the Silmaril Firewall TypeScript SDK are documented here.
4
19
 
5
20
  ## 0.7.5 - 2026-10-12
package/README.md CHANGED
@@ -34,10 +34,10 @@ This SDK is distributed as an npm package.
34
34
  npm install @silmaril-security/sdk
35
35
  ```
36
36
 
37
- For reproducible installs, pin the current tagged release:
37
+ After publication, pin version 0.7.7 for reproducible installs:
38
38
 
39
39
  ```sh
40
- npm install @silmaril-security/sdk@0.7.5
40
+ npm install @silmaril-security/sdk@0.7.7
41
41
  ```
42
42
 
43
43
  Requires Node 20 or later.
@@ -397,6 +397,13 @@ returns the server action, policy version, and optional rule ID. A malicious
397
397
  prediction or explicit governance block is blocked in Block mode; legacy
398
398
  responses without governance remain valid.
399
399
 
400
+ When supported by the serving runtime, `BlockResult.governance` can also
401
+ include optional decision evidence: the canonical `resource` (`kind`, `id`,
402
+ and `parentId` for MCP tools), `identityRevision`, and `reason`. Older runtimes
403
+ may omit these fields, and reason strings are open-ended so callers should
404
+ preserve unknown values. This response evidence does not establish request
405
+ identity and does not change enforcement behavior.
406
+
400
407
  ## Errors
401
408
 
402
409
  - `SilmarilApiError`: thrown when native `fetch` returns a non-2xx response to
@@ -637,3 +644,15 @@ npm publish --access public
637
644
 
638
645
  This SDK is distributed under the license terms in [LICENSE](LICENSE). It is not
639
646
  permissive open source.
647
+
648
+ ## Governance resource requests
649
+
650
+ Typed governance resources are sent in the classify request's top-level
651
+ `resource` field or aligned nullable `resources` array for batch calls. Resource
652
+ IDs must be non-empty; MCP tools also require their canonical server parent ID.
653
+ The compatibility metadata copy remains attribution only. Caller agent metadata
654
+ does not supply an authenticated principal.
655
+
656
+ This source prepares version 0.7.7. Its registry install command becomes
657
+ available after the authorized main-branch release workflow publishes the package.
658
+ Confirm registry publication before installing this version.
@@ -12,7 +12,7 @@ import * as _langchain_core_utils_types from '@langchain/core/utils/types';
12
12
  import * as langchain from 'langchain';
13
13
  import { CreateAgentParams } from 'langchain';
14
14
  import * as _langchain_core_tools from '@langchain/core/tools';
15
- import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-g3ZLF0xp.cjs';
15
+ import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-CueYday8.cjs';
16
16
 
17
17
  declare const SAFE_TOOL_MESSAGE = "Silmaril Firewall blocked this tool interaction. Choose a different safe action.";
18
18
  declare const SAFE_FINAL_MESSAGE = "Silmaril Firewall stopped this request after repeated unsafe actions.";
@@ -12,7 +12,7 @@ import * as _langchain_core_utils_types from '@langchain/core/utils/types';
12
12
  import * as langchain from 'langchain';
13
13
  import { CreateAgentParams } from 'langchain';
14
14
  import * as _langchain_core_tools from '@langchain/core/tools';
15
- import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-g3ZLF0xp.js';
15
+ import { h as FirewallMode, b as ClassifyEvent, e as Firewall } from '../firewall-CueYday8.js';
16
16
 
17
17
  declare const SAFE_TOOL_MESSAGE = "Silmaril Firewall blocked this tool interaction. Choose a different safe action.";
18
18
  declare const SAFE_FINAL_MESSAGE = "Silmaril Firewall stopped this request after repeated unsafe actions.";
@@ -1,5 +1,5 @@
1
1
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
- import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-g3ZLF0xp.cjs';
2
+ import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-CueYday8.cjs';
3
3
 
4
4
  declare function createLangChainHandler(firewall: Firewall, options?: LangChainAdapterOptions): Promise<BaseCallbackHandler>;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
- import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-g3ZLF0xp.js';
2
+ import { e as Firewall, L as LangChainAdapterOptions } from '../firewall-CueYday8.js';
3
3
 
4
4
  declare function createLangChainHandler(firewall: Firewall, options?: LangChainAdapterOptions): Promise<BaseCallbackHandler>;
5
5
 
@@ -1 +1 @@
1
- export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-g3ZLF0xp.cjs';
1
+ export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-CueYday8.cjs';
@@ -1 +1 @@
1
- export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-g3ZLF0xp.js';
1
+ export { g as FirewallMiddleware, Q as createMiddleware } from '../firewall-CueYday8.js';
@@ -74,11 +74,15 @@ type Prediction = "BENIGN" | "MALICIOUS";
74
74
  type FirewallMode = "shadow" | "warn" | "block";
75
75
  type GovernanceAction = "allow" | "block";
76
76
  type GovernanceResourceKind = "agent" | "tool" | "mcp_server" | "mcp_tool" | "plugin" | "skill" | "extension";
77
- interface GovernanceResource {
78
- readonly kind: GovernanceResourceKind;
79
- readonly id?: string;
80
- readonly parentId?: string;
81
- }
77
+ type GovernanceResource = {
78
+ readonly kind: "mcp_tool";
79
+ readonly id: string;
80
+ readonly parentId: string;
81
+ } | {
82
+ readonly kind: Exclude<GovernanceResourceKind, "mcp_tool">;
83
+ readonly id: string;
84
+ readonly parentId?: never;
85
+ };
82
86
  interface GovernanceContext {
83
87
  readonly agent?: string;
84
88
  readonly resource?: GovernanceResource;
@@ -87,6 +91,9 @@ interface GovernanceDecision {
87
91
  readonly action: GovernanceAction;
88
92
  readonly ruleId?: string;
89
93
  readonly policyVersion: string;
94
+ readonly resource?: GovernanceResource;
95
+ readonly identityRevision?: string;
96
+ readonly reason?: string;
90
97
  }
91
98
  interface BlockResult {
92
99
  readonly prediction: Prediction;
@@ -74,11 +74,15 @@ type Prediction = "BENIGN" | "MALICIOUS";
74
74
  type FirewallMode = "shadow" | "warn" | "block";
75
75
  type GovernanceAction = "allow" | "block";
76
76
  type GovernanceResourceKind = "agent" | "tool" | "mcp_server" | "mcp_tool" | "plugin" | "skill" | "extension";
77
- interface GovernanceResource {
78
- readonly kind: GovernanceResourceKind;
79
- readonly id?: string;
80
- readonly parentId?: string;
81
- }
77
+ type GovernanceResource = {
78
+ readonly kind: "mcp_tool";
79
+ readonly id: string;
80
+ readonly parentId: string;
81
+ } | {
82
+ readonly kind: Exclude<GovernanceResourceKind, "mcp_tool">;
83
+ readonly id: string;
84
+ readonly parentId?: never;
85
+ };
82
86
  interface GovernanceContext {
83
87
  readonly agent?: string;
84
88
  readonly resource?: GovernanceResource;
@@ -87,6 +91,9 @@ interface GovernanceDecision {
87
91
  readonly action: GovernanceAction;
88
92
  readonly ruleId?: string;
89
93
  readonly policyVersion: string;
94
+ readonly resource?: GovernanceResource;
95
+ readonly identityRevision?: string;
96
+ readonly reason?: string;
90
97
  }
91
98
  interface BlockResult {
92
99
  readonly prediction: Prediction;
package/dist/index.cjs CHANGED
@@ -818,7 +818,7 @@ function sanitizeText(text) {
818
818
  }
819
819
 
820
820
  // src/firewall.ts
821
- var SDK_VERSION = "0.7.5";
821
+ var SDK_VERSION = "0.7.7";
822
822
  var DEFAULT_TIMEOUT_MS = 1e4;
823
823
  var DEFAULT_MAX_RETRIES = 5;
824
824
  var MAX_BACKOFF_SECONDS = 30;
@@ -870,7 +870,7 @@ function blockResultFromResponse(data, requestedMode) {
870
870
  result.detectorCounts = detectorCounts;
871
871
  }
872
872
  }
873
- if (data.governance !== void 0) {
873
+ if (data.governance !== void 0 && data.governance !== null) {
874
874
  result.governance = governanceDecisionFromResponse(data.governance);
875
875
  }
876
876
  return Object.freeze(result);
@@ -894,15 +894,75 @@ function withSdkMetadata(metadata, info) {
894
894
  };
895
895
  return payload;
896
896
  }
897
+ var GOVERNANCE_RESOURCE_KINDS = [
898
+ "agent",
899
+ "tool",
900
+ "mcp_server",
901
+ "mcp_tool",
902
+ "plugin",
903
+ "skill",
904
+ "extension"
905
+ ];
906
+ function isGovernanceResourceKind(value) {
907
+ return typeof value === "string" && GOVERNANCE_RESOURCE_KINDS.includes(value);
908
+ }
909
+ function governanceResourceToWire(resource) {
910
+ if (!isGovernanceResourceKind(resource.kind)) {
911
+ throw new Error("Firewall: invalid governance resource kind");
912
+ }
913
+ if (typeof resource.id !== "string" || !resource.id.trim()) {
914
+ throw new Error("Firewall: governance resource id must be a non-empty string");
915
+ }
916
+ if (resource.kind === "mcp_tool") {
917
+ if (typeof resource.parentId !== "string" || !resource.parentId.trim()) {
918
+ throw new Error("Firewall: mcp_tool resource requires a non-empty parentId");
919
+ }
920
+ } else if (resource.parentId !== void 0) {
921
+ throw new Error("Firewall: parentId is valid only for mcp_tool resources");
922
+ }
923
+ return {
924
+ kind: resource.kind,
925
+ id: resource.id,
926
+ ...resource.parentId === void 0 ? {} : { parent_id: resource.parentId }
927
+ };
928
+ }
929
+ function governanceResourceFromResponse(value) {
930
+ if (!isRecord2(value)) {
931
+ throw new Error("Firewall: response governance resource must be an object");
932
+ }
933
+ if (!isGovernanceResourceKind(value.kind)) {
934
+ throw new Error("Firewall: response governance resource has an invalid kind");
935
+ }
936
+ if (typeof value.id !== "string" || !value.id.trim()) {
937
+ throw new Error("Firewall: response governance resource id must be a non-empty string");
938
+ }
939
+ if (value.kind === "mcp_tool") {
940
+ if (typeof value.parent_id !== "string" || !value.parent_id.trim()) {
941
+ throw new Error(
942
+ "Firewall: response governance mcp_tool resource requires a non-empty parent_id"
943
+ );
944
+ }
945
+ return Object.freeze({
946
+ kind: value.kind,
947
+ id: value.id,
948
+ parentId: value.parent_id
949
+ });
950
+ }
951
+ if (value.parent_id !== void 0 && value.parent_id !== null) {
952
+ throw new Error(
953
+ "Firewall: response governance parent_id is valid only for mcp_tool resources"
954
+ );
955
+ }
956
+ return Object.freeze({
957
+ kind: value.kind,
958
+ id: value.id
959
+ });
960
+ }
897
961
  function governanceContextToWire(context) {
898
962
  return {
899
963
  ...context.agent === void 0 ? {} : { agent: context.agent },
900
964
  ...context.resource === void 0 ? {} : {
901
- resource: {
902
- kind: context.resource.kind,
903
- ...context.resource.id === void 0 ? {} : { id: context.resource.id },
904
- ...context.resource.parentId === void 0 ? {} : { parent_id: context.resource.parentId }
905
- }
965
+ resource: governanceResourceToWire(context.resource)
906
966
  }
907
967
  };
908
968
  }
@@ -916,13 +976,25 @@ function governanceDecisionFromResponse(value) {
916
976
  if (typeof value.policy_version !== "string" || value.policy_version.length === 0) {
917
977
  throw new Error("Firewall: response governance policy_version must be a non-empty string");
918
978
  }
919
- if (value.rule_id !== void 0 && typeof value.rule_id !== "string") {
979
+ if (value.rule_id !== void 0 && value.rule_id !== null && typeof value.rule_id !== "string") {
920
980
  throw new Error("Firewall: response governance rule_id must be a string when provided");
921
981
  }
982
+ if (value.identity_revision !== void 0 && value.identity_revision !== null && typeof value.identity_revision !== "string") {
983
+ throw new Error(
984
+ "Firewall: response governance identity_revision must be a string when provided"
985
+ );
986
+ }
987
+ if (value.reason !== void 0 && value.reason !== null && typeof value.reason !== "string") {
988
+ throw new Error("Firewall: response governance reason must be a string when provided");
989
+ }
990
+ const resource = value.resource === void 0 || value.resource === null ? void 0 : governanceResourceFromResponse(value.resource);
922
991
  return Object.freeze({
923
992
  action: value.action,
924
- ...value.rule_id === void 0 ? {} : { ruleId: value.rule_id },
925
- policyVersion: value.policy_version
993
+ ...value.rule_id === void 0 || value.rule_id === null ? {} : { ruleId: value.rule_id },
994
+ policyVersion: value.policy_version,
995
+ ...resource === void 0 ? {} : { resource },
996
+ ...value.identity_revision === void 0 || value.identity_revision === null ? {} : { identityRevision: value.identity_revision },
997
+ ...value.reason === void 0 || value.reason === null ? {} : { reason: value.reason }
926
998
  });
927
999
  }
928
1000
  async function readCappedErrorBody(response) {
@@ -1122,6 +1194,11 @@ var Firewall = class {
1122
1194
  ...options.governance?.[index] === void 0 ? {} : { governance: options.governance[index] }
1123
1195
  })
1124
1196
  );
1197
+ if (options.governance !== void 0) {
1198
+ payload.resources = options.governance.map(
1199
+ (context) => context?.resource === void 0 ? null : governanceResourceToWire(context.resource)
1200
+ );
1201
+ }
1125
1202
  const data = await this.postWithRetry(payload, options.signal);
1126
1203
  if (!Array.isArray(data.predictions)) {
1127
1204
  throw new Error("Firewall: response predictions must be an array");
@@ -1190,6 +1267,9 @@ var Firewall = class {
1190
1267
  if (options.toolName !== void 0) {
1191
1268
  payload.tool_name = options.toolName;
1192
1269
  }
1270
+ if (options.governance?.resource !== void 0) {
1271
+ payload.resource = governanceResourceToWire(options.governance.resource);
1272
+ }
1193
1273
  payload.metadata = withSdkMetadata(options.metadata, {
1194
1274
  ...metadataInfo,
1195
1275
  ...options.governance === void 0 ? {} : { governance: options.governance }