@highflame/policy 2.2.41 → 2.2.43

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.
Files changed (32) hide show
  1. package/_schemas/agent_ops/context.json +0 -42
  2. package/_schemas/agent_ops/schema.cedarschema +44 -6
  3. package/_schemas/ai_gateway/context.json +300 -0
  4. package/_schemas/ai_gateway/schema.cedarschema +107 -3
  5. package/_schemas/guardrails/context.json +0 -36
  6. package/_schemas/guardrails/detectors.json +0 -1
  7. package/_schemas/guardrails/schema.cedarschema +43 -5
  8. package/_schemas/guardrails/templates/dual_attribution.cedar +110 -0
  9. package/_schemas/guardrails/templates/multi_turn_trajectory.cedar +116 -0
  10. package/_schemas/guardrails/templates/profiles/output_protection/credentials.cedar +35 -0
  11. package/_schemas/guardrails/templates/profiles/output_protection/data_leakage.cedar +63 -0
  12. package/_schemas/guardrails/templates/profiles/output_protection/harmful_content.cedar +58 -0
  13. package/_schemas/guardrails/templates/profiles/output_protection/injection_carried_back.cedar +39 -0
  14. package/_schemas/guardrails/templates/session_risk_accumulation.cedar +103 -0
  15. package/_schemas/guardrails/templates/templates.json +157 -11
  16. package/_schemas/overwatch/context.json +65 -0
  17. package/_schemas/overwatch/detectors.json +47 -0
  18. package/_schemas/overwatch/schema.cedarschema +90 -0
  19. package/dist/agent_ops-context.gen.d.ts +1 -2
  20. package/dist/agent_ops-context.gen.js +0 -2
  21. package/dist/ai_gateway-entities.gen.js +5 -1
  22. package/dist/guardrails-context.gen.d.ts +1 -2
  23. package/dist/guardrails-context.gen.js +0 -2
  24. package/dist/guardrails-defaults.gen.js +751 -11
  25. package/dist/overwatch-context.gen.d.ts +3 -1
  26. package/dist/overwatch-context.gen.js +4 -0
  27. package/dist/overwatch-detectors.gen.js +16 -0
  28. package/dist/parser.d.ts +2 -1
  29. package/dist/parser.js +124 -37
  30. package/dist/service-schemas.gen.d.ts +4 -4
  31. package/dist/service-schemas.gen.js +354 -32
  32. package/package.json +1 -1
@@ -140,6 +140,44 @@ namespace AgentOps {
140
140
  // Context Types (Action-Specific)
141
141
  // =========================================================================
142
142
 
143
+ /// The ZeroID NHI principal block (ADR 0009 / CAP-IDN-011).
144
+ ///
145
+ /// A record, not a string: Shield projects the whole identity block under
146
+ /// \`context.principal\`, so policies read members off it —
147
+ ///
148
+ /// permit ... when { context has principal &&
149
+ /// context.principal.trust_level == "first_party" };
150
+ /// forbid ... unless { context has principal &&
151
+ /// context.principal has act_sub };
152
+ ///
153
+ /// Declared once and shared by every action context so a new member cannot
154
+ /// land on one action and go missing on another.
155
+ ///
156
+ /// \`act\` (RFC 8693 delegation) is flattened to \`act_sub\` / \`act_iss\`
157
+ /// because Cedar records are flat key/value at each level; the full
158
+ /// delegation tree is reconstructable audit-side by joining on \`mission_id\`.
159
+ ///
160
+ /// Every member is optional except \`delegation_depth\`: the projector omits
161
+ /// a field whose value is empty, but always emits the depth because zero is
162
+ /// the meaningful base case for a direct (non-delegated) token. The record
163
+ /// itself is optional — it is absent, not empty, when the request carries no
164
+ /// NHI claims (RS256 human tokens, internal-service callers), so
165
+ /// \`context has principal\` is false rather than true-but-empty.
166
+ type PrincipalContext = {
167
+ "identity_type"?: String, // "human" | "agent" | "service" | "mcp_server"
168
+ "sub_type"?: String, // Identity subtype (e.g. "coding_agent")
169
+ "trust_level"?: String, // "first_party" | "verified" | "unverified"
170
+ "framework"?: String, // Agent framework (e.g. "langchain")
171
+ "publisher"?: String, // Agent publisher
172
+ "capabilities"?: Set<String>, // Capabilities granted to the identity
173
+ "scopes"?: Set<String>, // OAuth scopes carried by the token
174
+ "delegation_depth": Long, // Delegation hops; 0 for a direct token
175
+ "act_sub"?: String, // RFC 8693 actor — the accountable human
176
+ "act_iss"?: String, // Issuer of the actor claim
177
+ "mission_id"?: String, // Correlates one delegation tree
178
+ "grant_type"?: String, // How the token was obtained (e.g. "api_key")
179
+ };
180
+
143
181
  /// Context for the process_response action.
144
182
  ///
145
183
  /// An alias, not a copy: prompts and responses are inspected by the same
@@ -154,7 +192,7 @@ namespace AgentOps {
154
192
  "role"?: String,
155
193
  "privilege_scope"?: Set<String>,
156
194
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service" | "mcp_server"
157
- "principal"?: String, // Stable principal identifier (e.g. ZeroID / WIMSE URI or user id)
195
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
158
196
  // Core metadata (required)
159
197
  "request_id": String,
160
198
  "timestamp": Long,
@@ -349,7 +387,7 @@ namespace AgentOps {
349
387
  "role"?: String,
350
388
  "privilege_scope"?: Set<String>,
351
389
  "identity_type"?: String,
352
- "principal"?: String,
390
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
353
391
  // Core metadata (required)
354
392
  "request_id": String,
355
393
  "timestamp": Long,
@@ -560,7 +598,7 @@ namespace AgentOps {
560
598
  "role"?: String,
561
599
  "privilege_scope"?: Set<String>,
562
600
  "identity_type"?: String,
563
- "principal"?: String,
601
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
564
602
  // Core metadata (required)
565
603
  "request_id": String,
566
604
  "timestamp": Long,
@@ -668,7 +706,7 @@ namespace AgentOps {
668
706
  "role"?: String,
669
707
  "privilege_scope"?: Set<String>,
670
708
  "identity_type"?: String,
671
- "principal"?: String,
709
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
672
710
  // Core metadata (required)
673
711
  "request_id": String,
674
712
  "timestamp": Long,
@@ -780,7 +818,7 @@ namespace AgentOps {
780
818
  "role"?: String,
781
819
  "privilege_scope"?: Set<String>,
782
820
  "identity_type"?: String,
783
- "principal"?: String,
821
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
784
822
  // Core metadata (required)
785
823
  "request_id": String,
786
824
  "timestamp": Long,
@@ -913,7 +951,7 @@ namespace AgentOps {
913
951
  "role"?: String,
914
952
  "privilege_scope"?: Set<String>,
915
953
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service" | "mcp_server"
916
- "principal"?: String, // Stable principal identifier (ZeroID / WIMSE URI or user id)
954
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
917
955
  "agent_trust_level"?: String, // "untrusted" | "low" | "verified" | "trusted"
918
956
 
919
957
  // Core metadata (required)
@@ -1025,7 +1063,7 @@ entity FilePath in [Project];
1025
1063
  // ACTIONS
1026
1064
  // =============================================================================
1027
1065
 
1028
- // Call an MCP tool
1066
+ // Call an MCP tool (tools/call). Enumeration is the \`list\` action.
1029
1067
  // Threat focus: command injection, tool poisoning, rug pull, secrets, PII
1030
1068
  action call_tool appliesTo {
1031
1069
  principal: [User, MCP_Client],
@@ -1225,6 +1263,108 @@ action connect_server appliesTo {
1225
1263
  },
1226
1264
  };
1227
1265
 
1266
+ // Enumerate a server's tools, prompts, or resources
1267
+ // (tools/list, prompts/list, resources/list)
1268
+ //
1269
+ // Threat focus: tool poisoning and rug pull in the DESCRIPTIONS returned by
1270
+ // enumeration — the text a host feeds the model when it assembles the
1271
+ // session's tool schema, and the vector a rug-pull exploits between scans.
1272
+ //
1273
+ // Distinct from the actions it enumerates, and deliberately NOT default-locked
1274
+ // (highflame-shield#515 / INV-AUTHZ-003). Listing is host plumbing: the model
1275
+ // never decides to enumerate, the host does it to build the session. Folding
1276
+ // it into call_tool / process_prompt / read_file made enumeration inherit
1277
+ // their lock, and because a list names no tool, no conditioned grant
1278
+ // (\`context has tool_name && ...\`) can ever match it — so an agent holding a
1279
+ // correct grant for every tool it uses was still denied the enumeration step,
1280
+ // and without tools/list it cannot call anything at all. The only grant that
1281
+ // could match was an unconditioned one, which would have lifted the lock for
1282
+ // every call as well. There is no way to express "may list, may not call"
1283
+ // while a list and a call are the same action. See highflame-firehog#589.
1284
+ //
1285
+ // Authorization over WHAT may be enumerated is expressed through the list
1286
+ // CONTENTS (the grant-derived list filter), not by denying the request.
1287
+ action list appliesTo {
1288
+ principal: [User, MCP_Client],
1289
+ resource: [Server],
1290
+ context: {
1291
+ // Identity (AARM R6 / CAP-IDN-011) — projected from the principal's token; optional.
1292
+ role?: String,
1293
+ privilege_scope?: Set<String>,
1294
+
1295
+ // --- Content ---
1296
+ // The enumerated item's description. Optional: a tool may declare none,
1297
+ // and a policy must still evaluate when it does not.
1298
+ content?: String,
1299
+ mcp_server?: String,
1300
+
1301
+ // --- Enumerated item identity ---
1302
+ // The list is scanned one item at a time, so the item being evaluated
1303
+ // rides here while the resource stays the server being enumerated.
1304
+ tool_name?: String,
1305
+ tool_risk_score?: Long,
1306
+ tool_category?: String, // "safe", "sensitive", "dangerous"
1307
+ tool_is_sensitive?: Bool,
1308
+ tool_is_builtin?: Bool,
1309
+ tool_operation_classes?: Set<String>,
1310
+
1311
+ // --- Threat Detection ---
1312
+ threat_count?: Long,
1313
+ highest_severity?: String,
1314
+ threat_categories?: Set<String>,
1315
+ detected_threats?: Set<String>,
1316
+ max_threat_severity?: Long,
1317
+
1318
+ // --- Agent Security (0-100) — the reason this action scans at all ---
1319
+ tool_poisoning_score?: Long, // Hidden instructions in a tool description
1320
+ tool_poisoning_detected?: Bool,
1321
+ rug_pull_score?: Long, // Description drift after trust establishment
1322
+ rug_pull_detected?: Bool,
1323
+ indirect_injection_score?: Long,
1324
+
1325
+ // --- ML Detector Confidence Scores (0-100) ---
1326
+ injection_score?: Long,
1327
+ jailbreak_score?: Long,
1328
+
1329
+ // --- Secrets ---
1330
+ secrets_detected?: Bool,
1331
+ secret_types?: Set<String>,
1332
+ secret_count?: Long,
1333
+
1334
+ // --- PII Detection ---
1335
+ pii_detected?: Bool,
1336
+ pii_types?: Set<String>,
1337
+ pii_count?: Long,
1338
+ pii_score?: Long,
1339
+
1340
+ // --- MCP Trust & Config Risk ---
1341
+ mcp_server_verified?: Bool,
1342
+ mcp_config_risk?: Bool,
1343
+ mcp_risk_score?: Long,
1344
+
1345
+ // --- Session-Aware Threat Aggregation ---
1346
+ session_threat_turns?: Long,
1347
+ session_cumulative_risk_score?: Long,
1348
+ session_injection_detected?: Bool,
1349
+ session_command_injection?: Bool,
1350
+ session_pii_detected?: Bool,
1351
+ session_pii_types?: Set<String>,
1352
+ session_secrets_detected?: Bool,
1353
+ session_secret_types?: Set<String>,
1354
+ session_max_injection_score?: Long,
1355
+ session_max_jailbreak_score?: Long,
1356
+ session_max_command_injection_score?: Long,
1357
+ session_max_pii_score?: Long,
1358
+ session_max_secret_score?: Long,
1359
+
1360
+ // Rate Limiting — gateway-metered, Shield-decided (ADR 0014)
1361
+ rpm_remaining_pct?: Long,
1362
+ rpm_exceeded?: Bool,
1363
+ tpm_remaining_pct?: Long,
1364
+ tpm_exceeded?: Bool,
1365
+ },
1366
+ };
1367
+
1228
1368
  // Shared content-inspection context.
1229
1369
  //
1230
1370
  // Prompts and responses are inspected by the same detector pipeline and so
@@ -1312,7 +1452,8 @@ type ContentInspectionContext = {
1312
1452
  tpm_exceeded?: Bool,
1313
1453
  };
1314
1454
 
1315
- // Process a prompt (MCP prompts/get or LLM chat completions)
1455
+ // Process a prompt (MCP prompts/get or LLM chat completions).
1456
+ // Enumeration (prompts/list) is the \`list\` action.
1316
1457
  // Threat focus: injection, jailbreak, secrets, PII, content safety
1317
1458
  action process_prompt appliesTo {
1318
1459
  principal: [User, MCP_Client],
@@ -1335,7 +1476,8 @@ action process_response appliesTo {
1335
1476
  context: ContentInspectionContext,
1336
1477
  };
1337
1478
 
1338
- // Read an MCP resource (resources/read, resources/list)
1479
+ // Read an MCP resource (resources/read). Enumeration (resources/list)
1480
+ // is the \`list\` action.
1339
1481
  // Threat focus: secrets exposure, PII exposure, sensitive paths
1340
1482
  action read_file appliesTo {
1341
1483
  principal: [User, MCP_Client],
@@ -1583,6 +1725,44 @@ namespace Guardrails {
1583
1725
  // Context Types (Action-Specific)
1584
1726
  // =========================================================================
1585
1727
 
1728
+ /// The ZeroID NHI principal block (ADR 0009 / CAP-IDN-011).
1729
+ ///
1730
+ /// A record, not a string: Shield projects the whole identity block under
1731
+ /// \`context.principal\`, so policies read members off it —
1732
+ ///
1733
+ /// permit ... when { context has principal &&
1734
+ /// context.principal.trust_level == "first_party" };
1735
+ /// forbid ... unless { context has principal &&
1736
+ /// context.principal has act_sub };
1737
+ ///
1738
+ /// Declared once and shared by every action context so a new member cannot
1739
+ /// land on one action and go missing on another.
1740
+ ///
1741
+ /// \`act\` (RFC 8693 delegation) is flattened to \`act_sub\` / \`act_iss\`
1742
+ /// because Cedar records are flat key/value at each level; the full
1743
+ /// delegation tree is reconstructable audit-side by joining on \`mission_id\`.
1744
+ ///
1745
+ /// Every member is optional except \`delegation_depth\`: the projector omits
1746
+ /// a field whose value is empty, but always emits the depth because zero is
1747
+ /// the meaningful base case for a direct (non-delegated) token. The record
1748
+ /// itself is optional — it is absent, not empty, when the request carries no
1749
+ /// NHI claims (RS256 human tokens, internal-service callers), so
1750
+ /// \`context has principal\` is false rather than true-but-empty.
1751
+ type PrincipalContext = {
1752
+ "identity_type"?: String, // "human" | "agent" | "service"
1753
+ "sub_type"?: String, // Identity subtype (e.g. "coding_agent")
1754
+ "trust_level"?: String, // "first_party" | "verified" | "unverified"
1755
+ "framework"?: String, // Agent framework (e.g. "langchain")
1756
+ "publisher"?: String, // Agent publisher
1757
+ "capabilities"?: Set<String>, // Capabilities granted to the identity
1758
+ "scopes"?: Set<String>, // OAuth scopes carried by the token
1759
+ "delegation_depth": Long, // Delegation hops; 0 for a direct token
1760
+ "act_sub"?: String, // RFC 8693 actor — the accountable human
1761
+ "act_iss"?: String, // Issuer of the actor claim
1762
+ "mission_id"?: String, // Correlates one delegation tree
1763
+ "grant_type"?: String, // How the token was obtained (e.g. "api_key")
1764
+ };
1765
+
1586
1766
  /// Context for the process_response action.
1587
1767
  ///
1588
1768
  /// An alias, not a copy: prompts and responses are inspected by the same
@@ -1599,7 +1779,7 @@ namespace Guardrails {
1599
1779
  "role"?: String,
1600
1780
  "privilege_scope"?: Set<String>,
1601
1781
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service"
1602
- "principal"?: String, // Stable principal identifier (e.g. ZeroID / WIMSE URI or user id)
1782
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
1603
1783
  // Core metadata (required)
1604
1784
  "request_id": String,
1605
1785
  "timestamp": Long,
@@ -1751,7 +1931,7 @@ namespace Guardrails {
1751
1931
  "role"?: String,
1752
1932
  "privilege_scope"?: Set<String>,
1753
1933
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service"
1754
- "principal"?: String, // Stable principal identifier (e.g. ZeroID / WIMSE URI or user id)
1934
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
1755
1935
  // Core metadata (required)
1756
1936
  "request_id": String,
1757
1937
  "timestamp": Long,
@@ -1947,7 +2127,7 @@ namespace Guardrails {
1947
2127
  "role"?: String,
1948
2128
  "privilege_scope"?: Set<String>,
1949
2129
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service"
1950
- "principal"?: String, // Stable principal identifier (e.g. ZeroID / WIMSE URI or user id)
2130
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
1951
2131
  // Core metadata (required)
1952
2132
  "request_id": String,
1953
2133
  "timestamp": Long,
@@ -2020,7 +2200,7 @@ namespace Guardrails {
2020
2200
  "role"?: String,
2021
2201
  "privilege_scope"?: Set<String>,
2022
2202
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service"
2023
- "principal"?: String, // Stable principal identifier (e.g. ZeroID / WIMSE URI or user id)
2203
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
2024
2204
  // Core metadata (required)
2025
2205
  "request_id": String,
2026
2206
  "timestamp": Long,
@@ -2097,7 +2277,7 @@ namespace Guardrails {
2097
2277
  "role"?: String,
2098
2278
  "privilege_scope"?: Set<String>,
2099
2279
  "identity_type"?: String, // Principal identity class: "human" | "agent" | "service"
2100
- "principal"?: String, // Stable principal identifier (e.g. ZeroID / WIMSE URI or user id)
2280
+ "principal"?: PrincipalContext, // ZeroID NHI identity block; absent when the token carries no NHI claims
2101
2281
  // Core metadata (required)
2102
2282
  "request_id": String,
2103
2283
  "timestamp": Long,
@@ -2327,6 +2507,24 @@ action process_prompt appliesTo {
2327
2507
  // --- Legacy ---
2328
2508
  prompt_text?: String, // Same as content (backward compatibility)
2329
2509
  response_content?: String, // Response content (if available)
2510
+ // --- Session Token Budget --- (OWASP LLM10; CAP-ENF-009, cerberus#147)
2511
+ // Fed by the cumulative session total the Overwatch daemon reports on the
2512
+ // prompt and before-tool events.
2513
+ //
2514
+ // BOTH are optional, so BOTH need a \`has\` guard — a bare
2515
+ // \`context.budget_remaining_pct < 10\` fails cedar validation with
2516
+ // "unable to guarantee safety of access to optional attribute".
2517
+ // Write: \`context has budget_remaining_pct && context.budget_remaining_pct < 10\`.
2518
+ //
2519
+ // The guard is a validation requirement, NOT a safety property. Whenever a
2520
+ // session loads, budget_checker emits both keys — including
2521
+ // budget_exceeded: false and budget_remaining_pct: 100 when no budget rule
2522
+ // is configured for the scope. So a grant conditioned on
2523
+ // \`!context.budget_exceeded\` fires on unbudgeted sessions, and a low
2524
+ // percentage is evidence of spend only when a budget rule exists. Absence
2525
+ // means the detector did not run at all (no session).
2526
+ budget_remaining_pct?: Long, // Remaining session token budget (0-100)
2527
+ budget_exceeded?: Bool, // Session token budget exceeded
2330
2528
  },
2331
2529
  };
2332
2530
 
@@ -2446,6 +2644,24 @@ action call_tool appliesTo {
2446
2644
 
2447
2645
  // --- Legacy ---
2448
2646
  response_content?: String,
2647
+ // --- Session Token Budget --- (OWASP LLM10; CAP-ENF-009, cerberus#147)
2648
+ // Fed by the cumulative session total the Overwatch daemon reports on the
2649
+ // prompt and before-tool events.
2650
+ //
2651
+ // BOTH are optional, so BOTH need a \`has\` guard — a bare
2652
+ // \`context.budget_remaining_pct < 10\` fails cedar validation with
2653
+ // "unable to guarantee safety of access to optional attribute".
2654
+ // Write: \`context has budget_remaining_pct && context.budget_remaining_pct < 10\`.
2655
+ //
2656
+ // The guard is a validation requirement, NOT a safety property. Whenever a
2657
+ // session loads, budget_checker emits both keys — including
2658
+ // budget_exceeded: false and budget_remaining_pct: 100 when no budget rule
2659
+ // is configured for the scope. So a grant conditioned on
2660
+ // \`!context.budget_exceeded\` fires on unbudgeted sessions, and a low
2661
+ // percentage is evidence of spend only when a budget rule exists. Absence
2662
+ // means the detector did not run at all (no session).
2663
+ budget_remaining_pct?: Long, // Remaining session token budget (0-100)
2664
+ budget_exceeded?: Bool, // Session token budget exceeded
2449
2665
  },
2450
2666
  };
2451
2667
 
@@ -2568,6 +2784,24 @@ action connect_server appliesTo {
2568
2784
  session_max_pii_score?: Long,
2569
2785
  session_max_secret_score?: Long,
2570
2786
  session_cumulative_risk_score?: Long,
2787
+ // --- Session Token Budget --- (OWASP LLM10; CAP-ENF-009, cerberus#147)
2788
+ // Fed by the cumulative session total the Overwatch daemon reports on the
2789
+ // prompt and before-tool events.
2790
+ //
2791
+ // BOTH are optional, so BOTH need a \`has\` guard — a bare
2792
+ // \`context.budget_remaining_pct < 10\` fails cedar validation with
2793
+ // "unable to guarantee safety of access to optional attribute".
2794
+ // Write: \`context has budget_remaining_pct && context.budget_remaining_pct < 10\`.
2795
+ //
2796
+ // The guard is a validation requirement, NOT a safety property. Whenever a
2797
+ // session loads, budget_checker emits both keys — including
2798
+ // budget_exceeded: false and budget_remaining_pct: 100 when no budget rule
2799
+ // is configured for the scope. So a grant conditioned on
2800
+ // \`!context.budget_exceeded\` fires on unbudgeted sessions, and a low
2801
+ // percentage is evidence of spend only when a budget rule exists. Absence
2802
+ // means the detector did not run at all (no session).
2803
+ budget_remaining_pct?: Long, // Remaining session token budget (0-100)
2804
+ budget_exceeded?: Bool, // Session token budget exceeded
2571
2805
  },
2572
2806
  };
2573
2807
 
@@ -2622,6 +2856,24 @@ action read_file appliesTo {
2622
2856
 
2623
2857
  // --- Agent Security ---
2624
2858
  indirect_injection_score?: Long, // Indirect injection via file content
2859
+ // --- Session Token Budget --- (OWASP LLM10; CAP-ENF-009, cerberus#147)
2860
+ // Fed by the cumulative session total the Overwatch daemon reports on the
2861
+ // prompt and before-tool events.
2862
+ //
2863
+ // BOTH are optional, so BOTH need a \`has\` guard — a bare
2864
+ // \`context.budget_remaining_pct < 10\` fails cedar validation with
2865
+ // "unable to guarantee safety of access to optional attribute".
2866
+ // Write: \`context has budget_remaining_pct && context.budget_remaining_pct < 10\`.
2867
+ //
2868
+ // The guard is a validation requirement, NOT a safety property. Whenever a
2869
+ // session loads, budget_checker emits both keys — including
2870
+ // budget_exceeded: false and budget_remaining_pct: 100 when no budget rule
2871
+ // is configured for the scope. So a grant conditioned on
2872
+ // \`!context.budget_exceeded\` fires on unbudgeted sessions, and a low
2873
+ // percentage is evidence of spend only when a budget rule exists. Absence
2874
+ // means the detector did not run at all (no session).
2875
+ budget_remaining_pct?: Long, // Remaining session token budget (0-100)
2876
+ budget_exceeded?: Bool, // Session token budget exceeded
2625
2877
  },
2626
2878
  };
2627
2879
 
@@ -2676,6 +2928,24 @@ action write_file appliesTo {
2676
2928
 
2677
2929
  // --- Agent Security ---
2678
2930
  indirect_injection_score?: Long, // Indirect injection via file content
2931
+ // --- Session Token Budget --- (OWASP LLM10; CAP-ENF-009, cerberus#147)
2932
+ // Fed by the cumulative session total the Overwatch daemon reports on the
2933
+ // prompt and before-tool events.
2934
+ //
2935
+ // BOTH are optional, so BOTH need a \`has\` guard — a bare
2936
+ // \`context.budget_remaining_pct < 10\` fails cedar validation with
2937
+ // "unable to guarantee safety of access to optional attribute".
2938
+ // Write: \`context has budget_remaining_pct && context.budget_remaining_pct < 10\`.
2939
+ //
2940
+ // The guard is a validation requirement, NOT a safety property. Whenever a
2941
+ // session loads, budget_checker emits both keys — including
2942
+ // budget_exceeded: false and budget_remaining_pct: 100 when no budget rule
2943
+ // is configured for the scope. So a grant conditioned on
2944
+ // \`!context.budget_exceeded\` fires on unbudgeted sessions, and a low
2945
+ // percentage is evidence of spend only when a budget rule exists. Absence
2946
+ // means the detector did not run at all (no session).
2947
+ budget_remaining_pct?: Long, // Remaining session token budget (0-100)
2948
+ budget_exceeded?: Bool, // Session token budget exceeded
2679
2949
  },
2680
2950
  };
2681
2951
 
@@ -3276,7 +3546,6 @@ export const AGENT_OPS_CONTEXT = {
3276
3546
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011)" },
3277
3547
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011)" },
3278
3548
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3279
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id)" },
3280
3549
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request, useful for audit trails and debugging" },
3281
3550
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds when the request was processed" },
3282
3551
  { "key": "direction", "type": "string", "required": true, "description": "Content flow direction: \'input\' for user prompts, \'output\' for AI responses" },
@@ -3407,7 +3676,6 @@ export const AGENT_OPS_CONTEXT = {
3407
3676
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011)" },
3408
3677
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011)" },
3409
3678
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3410
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id)" },
3411
3679
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request, useful for audit trails and debugging" },
3412
3680
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds when the request was processed" },
3413
3681
  { "key": "direction", "type": "string", "required": true, "description": "Content flow direction: \'input\' for user prompts, \'output\' for AI responses" },
@@ -3538,7 +3806,6 @@ export const AGENT_OPS_CONTEXT = {
3538
3806
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token" },
3539
3807
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller" },
3540
3808
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3541
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier" },
3542
3809
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
3543
3810
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
3544
3811
  { "key": "source", "type": "string", "required": false, "description": "Traffic origin: \'ide\' | \'cli\' | \'api\' | \'browser\'" },
@@ -3666,7 +3933,6 @@ export const AGENT_OPS_CONTEXT = {
3666
3933
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token" },
3667
3934
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller" },
3668
3935
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3669
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier" },
3670
3936
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
3671
3937
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
3672
3938
  { "key": "source", "type": "string", "required": false, "description": "Traffic origin: \'ide\' | \'cli\' | \'api\' | \'browser\'" },
@@ -3733,7 +3999,6 @@ export const AGENT_OPS_CONTEXT = {
3733
3999
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token" },
3734
4000
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller" },
3735
4001
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3736
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier" },
3737
4002
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
3738
4003
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
3739
4004
  { "key": "source", "type": "string", "required": false, "description": "Traffic origin: \'ide\' | \'cli\' | \'api\' | \'browser\'" },
@@ -3802,7 +4067,6 @@ export const AGENT_OPS_CONTEXT = {
3802
4067
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token" },
3803
4068
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller" },
3804
4069
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3805
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier" },
3806
4070
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
3807
4071
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
3808
4072
  { "key": "source", "type": "string", "required": false, "description": "Traffic origin: \'ide\' | \'cli\' | \'api\' | \'browser\'" },
@@ -3875,7 +4139,6 @@ export const AGENT_OPS_CONTEXT = {
3875
4139
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token" },
3876
4140
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller" },
3877
4141
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class: \'human\', \'agent\', \'service\', or \'mcp_server\'" },
3878
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier (ZeroID / WIMSE URI or user id)" },
3879
4142
  { "key": "agent_trust_level", "type": "string", "required": false, "description": "Agent trust tier: \'untrusted\' | \'low\' | \'verified\' | \'trusted\'" },
3880
4143
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
3881
4144
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
@@ -4035,6 +4298,61 @@ export const AI_GATEWAY_CONTEXT = {
4035
4298
  { "key": "package_check_status", "type": "string", "required": false, "description": "Set to \'degraded\' when the osv.dev lookup failed (fail-open)" }
4036
4299
  ]
4037
4300
  },
4301
+ {
4302
+ "name": "list",
4303
+ "description": "Enumerate a server\'s tools, prompts, or resources — threat focus: tool poisoning and rug pull in the returned descriptions",
4304
+ "context_attributes": [
4305
+ { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011)." },
4306
+ { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011)." },
4307
+ { "key": "content", "type": "string", "required": false, "description": "The enumerated item\'s description — the text scanned for poisoning. Absent when the item declares none." },
4308
+ { "key": "mcp_server", "type": "string", "required": false, "description": "MCP server being enumerated" },
4309
+ { "key": "tool_name", "type": "string", "required": false, "description": "Name of the enumerated item being evaluated" },
4310
+ { "key": "tool_risk_score", "type": "number", "required": false, "description": "Tool risk score" },
4311
+ { "key": "tool_category", "type": "string", "required": false, "description": "\"safe\", \"sensitive\", \"dangerous\"" },
4312
+ { "key": "tool_is_sensitive", "type": "boolean", "required": false, "description": "Tool is sensitive" },
4313
+ { "key": "tool_is_builtin", "type": "boolean", "required": false, "description": "Tool is builtin" },
4314
+ { "key": "tool_operation_classes", "type": "array", "required": false, "description": "Tool operation classes" },
4315
+ { "key": "threat_count", "type": "number", "required": false, "description": "Total threats detected" },
4316
+ { "key": "highest_severity", "type": "string", "required": false, "description": "Highest threat severity" },
4317
+ { "key": "threat_categories", "type": "array", "required": false, "description": "Threat category names" },
4318
+ { "key": "detected_threats", "type": "array", "required": false, "description": "Detection rule names that matched" },
4319
+ { "key": "max_threat_severity", "type": "number", "required": false, "description": "Numeric severity (0=none, 4=critical)" },
4320
+ { "key": "tool_poisoning_score", "type": "number", "required": false, "description": "Hidden instructions in a tool description" },
4321
+ { "key": "tool_poisoning_detected", "type": "boolean", "required": false, "description": "Hidden instructions found in the description" },
4322
+ { "key": "rug_pull_score", "type": "number", "required": false, "description": "Description drift after trust establishment" },
4323
+ { "key": "rug_pull_detected", "type": "boolean", "required": false, "description": "Description drifted after trust was established" },
4324
+ { "key": "indirect_injection_score", "type": "number", "required": false, "description": "Indirect injection score" },
4325
+ { "key": "injection_score", "type": "number", "required": false, "description": "Prompt injection classifier confidence (0-100)" },
4326
+ { "key": "jailbreak_score", "type": "number", "required": false, "description": "Jailbreak classifier confidence (0-100)" },
4327
+ { "key": "secrets_detected", "type": "boolean", "required": false, "description": "Whether secrets were detected in the description" },
4328
+ { "key": "secret_types", "type": "array", "required": false, "description": "Secret types detected" },
4329
+ { "key": "secret_count", "type": "number", "required": false, "description": "Number of secrets detected" },
4330
+ { "key": "pii_detected", "type": "boolean", "required": false, "description": "Whether PII was detected" },
4331
+ { "key": "pii_types", "type": "array", "required": false, "description": "PII types detected" },
4332
+ { "key": "pii_count", "type": "number", "required": false, "description": "Number of PII entities" },
4333
+ { "key": "pii_score", "type": "number", "required": false, "description": "PII confidence (0-100)" },
4334
+ { "key": "mcp_server_verified", "type": "boolean", "required": false, "description": "Whether the server is from a verified registry" },
4335
+ { "key": "mcp_config_risk", "type": "boolean", "required": false, "description": "Server config flagged risky" },
4336
+ { "key": "mcp_risk_score", "type": "number", "required": false, "description": "Server risk score (0-100)" },
4337
+ { "key": "session_threat_turns", "type": "number", "required": false, "description": "Session-aggregated threat turns across prior turns" },
4338
+ { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Session-aggregated cumulative risk score across prior turns" },
4339
+ { "key": "session_injection_detected", "type": "boolean", "required": false, "description": "Session-aggregated injection detected across prior turns" },
4340
+ { "key": "session_command_injection", "type": "boolean", "required": false, "description": "Session-aggregated command injection across prior turns" },
4341
+ { "key": "session_pii_detected", "type": "boolean", "required": false, "description": "Session-aggregated pii detected across prior turns" },
4342
+ { "key": "session_pii_types", "type": "array", "required": false, "description": "Session-aggregated pii types across prior turns" },
4343
+ { "key": "session_secrets_detected", "type": "boolean", "required": false, "description": "Session-aggregated secrets detected across prior turns" },
4344
+ { "key": "session_secret_types", "type": "array", "required": false, "description": "Session-aggregated secret types across prior turns" },
4345
+ { "key": "session_max_injection_score", "type": "number", "required": false, "description": "Session-aggregated max injection score across prior turns" },
4346
+ { "key": "session_max_jailbreak_score", "type": "number", "required": false, "description": "Session-aggregated max jailbreak score across prior turns" },
4347
+ { "key": "session_max_command_injection_score", "type": "number", "required": false, "description": "Session-aggregated max command injection score across prior turns" },
4348
+ { "key": "session_max_pii_score", "type": "number", "required": false, "description": "Session-aggregated max pii score across prior turns" },
4349
+ { "key": "session_max_secret_score", "type": "number", "required": false, "description": "Session-aggregated max secret score across prior turns" },
4350
+ { "key": "rpm_remaining_pct", "type": "number", "required": false, "description": "Requests-per-minute headroom remaining" },
4351
+ { "key": "rpm_exceeded", "type": "boolean", "required": false, "description": "RPM limit exceeded" },
4352
+ { "key": "tpm_remaining_pct", "type": "number", "required": false, "description": "Tokens-per-minute headroom remaining" },
4353
+ { "key": "tpm_exceeded", "type": "boolean", "required": false, "description": "TPM limit exceeded" }
4354
+ ]
4355
+ },
4038
4356
  {
4039
4357
  "name": "process_prompt",
4040
4358
  "description": "Process a prompt (MCP or LLM chat completion) — threat focus: injection, jailbreak, secrets, PII, content safety",
@@ -4232,7 +4550,6 @@ export const GUARDRAILS_CONTEXT = {
4232
4550
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011), e.g. finance_lead. Absent when the token carries no role claim." },
4233
4551
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011), e.g. transfer:approve. Absent when the token carries no claim." },
4234
4552
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', or \'service\'. Use to apply identity-class-specific policies" },
4235
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id). Absent when the token carries no principal claim" },
4236
4553
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request, useful for audit trails and debugging" },
4237
4554
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds when the request was processed" },
4238
4555
  { "key": "direction", "type": "string", "required": true, "description": "Content flow direction: \'input\' for user prompts, \'output\' for AI responses. Use this to apply different policies to inputs vs outputs (e.g., block PII only in outputs)" },
@@ -4343,7 +4660,6 @@ export const GUARDRAILS_CONTEXT = {
4343
4660
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011), e.g. finance_lead. Absent when the token carries no role claim." },
4344
4661
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011), e.g. transfer:approve. Absent when the token carries no claim." },
4345
4662
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', or \'service\'. Use to apply identity-class-specific policies" },
4346
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id). Absent when the token carries no principal claim" },
4347
4663
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request, useful for audit trails and debugging" },
4348
4664
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds when the request was processed" },
4349
4665
  { "key": "direction", "type": "string", "required": true, "description": "Content flow direction: \'input\' for user prompts, \'output\' for AI responses. Use this to apply different policies to inputs vs outputs (e.g., block PII only in outputs)" },
@@ -4454,7 +4770,6 @@ export const GUARDRAILS_CONTEXT = {
4454
4770
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011), e.g. finance_lead. Absent when the token carries no role claim." },
4455
4771
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011), e.g. transfer:approve. Absent when the token carries no claim." },
4456
4772
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', or \'service\'. Use to apply identity-class-specific policies" },
4457
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id). Absent when the token carries no principal claim" },
4458
4773
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
4459
4774
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
4460
4775
  { "key": "tool_name", "type": "string", "required": false, "description": "Name of the tool being called (e.g., \'shell\', \'write_file\', \'http_post\'). Use this to block specific dangerous tools" },
@@ -4576,7 +4891,6 @@ export const GUARDRAILS_CONTEXT = {
4576
4891
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011), e.g. finance_lead. Absent when the token carries no role claim." },
4577
4892
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011), e.g. transfer:approve. Absent when the token carries no claim." },
4578
4893
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', or \'service\'. Use to apply identity-class-specific policies" },
4579
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id). Absent when the token carries no principal claim" },
4580
4894
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
4581
4895
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
4582
4896
  { "key": "path", "type": "string", "required": false, "description": "File path being read. Use for path-based access control policies (e.g., block .env files, system directories, credential directories)" },
@@ -4621,7 +4935,6 @@ export const GUARDRAILS_CONTEXT = {
4621
4935
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011), e.g. finance_lead. Absent when the token carries no role claim." },
4622
4936
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011), e.g. transfer:approve. Absent when the token carries no claim." },
4623
4937
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', or \'service\'. Use to apply identity-class-specific policies" },
4624
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id). Absent when the token carries no principal claim" },
4625
4938
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
4626
4939
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
4627
4940
  { "key": "path", "type": "string", "required": false, "description": "File path being written. Use for path-based blocking policies (e.g., block writes to .env files, credential directories)" },
@@ -4668,7 +4981,6 @@ export const GUARDRAILS_CONTEXT = {
4668
4981
  { "key": "role", "type": "string", "required": false, "description": "Caller\'s RBAC role projected from the principal\'s token (AARM R6 / CAP-IDN-011), e.g. finance_lead. Absent when the token carries no role claim." },
4669
4982
  { "key": "privilege_scope", "type": "array", "required": false, "description": "Privilege-scope strings granted to the caller, projected from the token (AARM R6 / CAP-IDN-011), e.g. transfer:approve. Absent when the token carries no claim." },
4670
4983
  { "key": "identity_type", "type": "string", "required": false, "description": "Principal identity class projected from the token: \'human\', \'agent\', or \'service\'. Use to apply identity-class-specific policies" },
4671
- { "key": "principal", "type": "string", "required": false, "description": "Stable principal identifier projected from the token (e.g. a ZeroID / WIMSE URI or user id). Absent when the token carries no principal claim" },
4672
4984
  { "key": "request_id", "type": "string", "required": true, "description": "Unique identifier for this request" },
4673
4985
  { "key": "timestamp", "type": "number", "required": true, "description": "Unix timestamp in milliseconds" },
4674
4986
  { "key": "mcp_server", "type": "string", "required": false, "description": "Name of the MCP server being connected to (e.g., \'github\', \'filesystem\', \'slack\'). Use this to allow or block specific MCP servers" },
@@ -4774,7 +5086,9 @@ export const OVERWATCH_CONTEXT = {
4774
5086
  { "key": "session_max_command_injection_score", "type": "number", "required": false, "description": "Highest command injection score seen in any turn of the session (0-100)" },
4775
5087
  { "key": "session_max_pii_score", "type": "number", "required": false, "description": "Highest PII risk score seen in any turn of the session (0-100)" },
4776
5088
  { "key": "session_max_secret_score", "type": "number", "required": false, "description": "Highest secret detection score seen in any turn of the session (0-100)" },
4777
- { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" }
5089
+ { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" },
5090
+ { "key": "budget_remaining_pct", "type": "number", "required": false, "description": "Remaining session token budget as a percentage (0-100). Optional, so a policy must guard it: `context has budget_remaining_pct && context.budget_remaining_pct < 10` — a bare comparison fails Cedar validation. Runtime default-fills it to 100 whenever the detector runs, so a high value is not evidence that a budget rule exists." },
5091
+ { "key": "budget_exceeded", "type": "boolean", "required": false, "description": "Whether the session token budget has been exceeded. Optional, so a policy must guard it with `context has budget_exceeded`. The guard is a validation requirement, not a fail-closed property: the detector emits false whenever a session loads, including when no budget rule is configured, so a grant conditioned on `!context.budget_exceeded` will fire on unbudgeted sessions." }
4778
5092
  ]
4779
5093
  },
4780
5094
  {
@@ -4864,7 +5178,9 @@ export const OVERWATCH_CONTEXT = {
4864
5178
  { "key": "session_max_command_injection_score", "type": "number", "required": false, "description": "Highest command injection score seen in any turn of the session (0-100)" },
4865
5179
  { "key": "session_max_pii_score", "type": "number", "required": false, "description": "Highest PII risk score seen in any turn of the session (0-100)" },
4866
5180
  { "key": "session_max_secret_score", "type": "number", "required": false, "description": "Highest secret detection score seen in any turn of the session (0-100)" },
4867
- { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" }
5181
+ { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" },
5182
+ { "key": "budget_remaining_pct", "type": "number", "required": false, "description": "Remaining session token budget as a percentage (0-100). Optional, so a policy must guard it: `context has budget_remaining_pct && context.budget_remaining_pct < 10` — a bare comparison fails Cedar validation. Runtime default-fills it to 100 whenever the detector runs, so a high value is not evidence that a budget rule exists." },
5183
+ { "key": "budget_exceeded", "type": "boolean", "required": false, "description": "Whether the session token budget has been exceeded. Optional, so a policy must guard it with `context has budget_exceeded`. The guard is a validation requirement, not a fail-closed property: the detector emits false whenever a session loads, including when no budget rule is configured, so a grant conditioned on `!context.budget_exceeded` will fire on unbudgeted sessions." }
4868
5184
  ]
4869
5185
  },
4870
5186
  {
@@ -4945,7 +5261,9 @@ export const OVERWATCH_CONTEXT = {
4945
5261
  { "key": "session_max_command_injection_score", "type": "number", "required": false, "description": "Highest command injection score seen in any turn of the session (0-100)" },
4946
5262
  { "key": "session_max_pii_score", "type": "number", "required": false, "description": "Highest PII risk score seen in any turn of the session (0-100)" },
4947
5263
  { "key": "session_max_secret_score", "type": "number", "required": false, "description": "Highest secret detection score seen in any turn of the session (0-100)" },
4948
- { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" }
5264
+ { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" },
5265
+ { "key": "budget_remaining_pct", "type": "number", "required": false, "description": "Remaining session token budget as a percentage (0-100). Optional, so a policy must guard it: `context has budget_remaining_pct && context.budget_remaining_pct < 10` — a bare comparison fails Cedar validation. Runtime default-fills it to 100 whenever the detector runs, so a high value is not evidence that a budget rule exists." },
5266
+ { "key": "budget_exceeded", "type": "boolean", "required": false, "description": "Whether the session token budget has been exceeded. Optional, so a policy must guard it with `context has budget_exceeded`. The guard is a validation requirement, not a fail-closed property: the detector emits false whenever a session loads, including when no budget rule is configured, so a grant conditioned on `!context.budget_exceeded` will fire on unbudgeted sessions." }
4949
5267
  ]
4950
5268
  },
4951
5269
  {
@@ -4984,7 +5302,9 @@ export const OVERWATCH_CONTEXT = {
4984
5302
  { "key": "session_max_command_injection_score", "type": "number", "required": false, "description": "Highest command injection score seen in any turn of the session (0-100)" },
4985
5303
  { "key": "session_max_pii_score", "type": "number", "required": false, "description": "Highest PII risk score seen in any turn of the session (0-100)" },
4986
5304
  { "key": "session_max_secret_score", "type": "number", "required": false, "description": "Highest secret detection score seen in any turn of the session (0-100)" },
4987
- { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" }
5305
+ { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" },
5306
+ { "key": "budget_remaining_pct", "type": "number", "required": false, "description": "Remaining session token budget as a percentage (0-100). Optional, so a policy must guard it: `context has budget_remaining_pct && context.budget_remaining_pct < 10` — a bare comparison fails Cedar validation. Runtime default-fills it to 100 whenever the detector runs, so a high value is not evidence that a budget rule exists." },
5307
+ { "key": "budget_exceeded", "type": "boolean", "required": false, "description": "Whether the session token budget has been exceeded. Optional, so a policy must guard it with `context has budget_exceeded`. The guard is a validation requirement, not a fail-closed property: the detector emits false whenever a session loads, including when no budget rule is configured, so a grant conditioned on `!context.budget_exceeded` will fire on unbudgeted sessions." }
4988
5308
  ]
4989
5309
  },
4990
5310
  {
@@ -5024,7 +5344,9 @@ export const OVERWATCH_CONTEXT = {
5024
5344
  { "key": "session_max_command_injection_score", "type": "number", "required": false, "description": "Highest command injection score seen in any turn of the session (0-100)" },
5025
5345
  { "key": "session_max_pii_score", "type": "number", "required": false, "description": "Highest PII risk score seen in any turn of the session (0-100)" },
5026
5346
  { "key": "session_max_secret_score", "type": "number", "required": false, "description": "Highest secret detection score seen in any turn of the session (0-100)" },
5027
- { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" }
5347
+ { "key": "session_cumulative_risk_score", "type": "number", "required": false, "description": "Sum of per-turn risk scores across the session. Catches death-by-a-thousand-cuts where no single turn is high but cumulative risk is significant" },
5348
+ { "key": "budget_remaining_pct", "type": "number", "required": false, "description": "Remaining session token budget as a percentage (0-100). Optional, so a policy must guard it: `context has budget_remaining_pct && context.budget_remaining_pct < 10` — a bare comparison fails Cedar validation. Runtime default-fills it to 100 whenever the detector runs, so a high value is not evidence that a budget rule exists." },
5349
+ { "key": "budget_exceeded", "type": "boolean", "required": false, "description": "Whether the session token budget has been exceeded. Optional, so a policy must guard it with `context has budget_exceeded`. The guard is a validation requirement, not a fail-closed property: the detector emits false whenever a session loads, including when no budget rule is configured, so a grant conditioned on `!context.budget_exceeded` will fire on unbudgeted sessions." }
5028
5350
  ]
5029
5351
  }
5030
5352
  ]