@highflame/policy 2.0.9 → 2.1.0
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/_schemas/guardrails/context.json +435 -0
- package/_schemas/guardrails/schema.cedarschema +225 -0
- package/_schemas/guardrails/templates/defaults/agentic_safety.cedar +94 -0
- package/_schemas/guardrails/templates/defaults/baseline.cedar +24 -0
- package/_schemas/guardrails/templates/defaults/injection.cedar +70 -0
- package/_schemas/guardrails/templates/defaults/pii.cedar +48 -0
- package/_schemas/guardrails/templates/defaults/secrets.cedar +40 -0
- package/_schemas/guardrails/templates/defaults/semantic.cedar +59 -0
- package/_schemas/guardrails/templates/defaults/tool_risk.cedar +58 -0
- package/_schemas/guardrails/templates/defaults/toxicity.cedar +76 -0
- package/_schemas/guardrails/templates/mcp_tool_permissions.cedar +84 -0
- package/_schemas/guardrails/templates/profiles/chat_assistant/privacy.cedar +22 -0
- package/_schemas/guardrails/templates/profiles/chat_assistant/security.cedar +35 -0
- package/_schemas/guardrails/templates/profiles/chat_assistant/trust_safety.cedar +43 -0
- package/_schemas/guardrails/templates/profiles/chat_assistant.cedar +85 -0
- package/_schemas/guardrails/templates/profiles/code_agent/agentic_security.cedar +109 -0
- package/_schemas/guardrails/templates/profiles/code_agent/security.cedar +22 -0
- package/_schemas/guardrails/templates/profiles/code_agent.cedar +125 -0
- package/_schemas/guardrails/templates/profiles/data_pipeline/agentic_security.cedar +38 -0
- package/_schemas/guardrails/templates/profiles/data_pipeline/privacy.cedar +40 -0
- package/_schemas/guardrails/templates/profiles/data_pipeline/security.cedar +49 -0
- package/_schemas/guardrails/templates/profiles/data_pipeline.cedar +111 -0
- package/_schemas/guardrails/templates/templates.json +213 -0
- package/_schemas/overwatch/context.json +54 -54
- package/_schemas/overwatch/schema.cedarschema +77 -68
- package/dist/builder.d.ts +106 -13
- package/dist/builder.js +103 -34
- package/dist/engine.d.ts +20 -2
- package/dist/engine.js +50 -20
- package/dist/entities.gen.d.ts +4 -0
- package/dist/entities.gen.js +4 -0
- package/dist/explain.d.ts +150 -0
- package/dist/explain.js +363 -0
- package/dist/guardrails-context.gen.d.ts +49 -0
- package/dist/guardrails-context.gen.js +50 -0
- package/dist/guardrails-defaults.gen.d.ts +61 -0
- package/dist/guardrails-defaults.gen.js +1278 -0
- package/dist/guardrails-entities.gen.d.ts +11 -0
- package/dist/guardrails-entities.gen.js +37 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/overwatch-defaults.gen.js +122 -2
- package/dist/parser.js +136 -4
- package/dist/schema.gen.d.ts +1 -1
- package/dist/schema.gen.js +6 -0
- package/dist/service-schemas.gen.d.ts +15 -11
- package/dist/service-schemas.gen.js +509 -84
- package/dist/types.d.ts +6 -1
- package/dist/types.js +6 -1
- package/package.json +5 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ServiceEntityMetadata, ActionEntityMetadata } from './entity-metadata-types.gen.js';
|
|
2
|
+
/**
|
|
3
|
+
* Guardrails entity metadata for UI components.
|
|
4
|
+
* Extracted from Cedar schema appliesTo blocks.
|
|
5
|
+
*/
|
|
6
|
+
export declare const GUARDRAILS_ENTITIES: ServiceEntityMetadata;
|
|
7
|
+
/**
|
|
8
|
+
* Per-action entity mapping for Guardrails.
|
|
9
|
+
* Maps action names to their valid principals and resources.
|
|
10
|
+
*/
|
|
11
|
+
export declare const GUARDRAILS_ACTION_ENTITIES: Record<string, ActionEntityMetadata>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Code generated by highflame-policy-codegen. DO NOT EDIT.
|
|
2
|
+
// Source: schemas/guardrails/schema.cedarschema
|
|
3
|
+
/**
|
|
4
|
+
* Guardrails entity metadata for UI components.
|
|
5
|
+
* Extracted from Cedar schema appliesTo blocks.
|
|
6
|
+
*/
|
|
7
|
+
export const GUARDRAILS_ENTITIES = {
|
|
8
|
+
principals: ['Agent', 'User'],
|
|
9
|
+
resources: ['App', 'Session'],
|
|
10
|
+
actions: ['call_tool', 'connect_server', 'process_prompt', 'read_file', 'write_file'],
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Per-action entity mapping for Guardrails.
|
|
14
|
+
* Maps action names to their valid principals and resources.
|
|
15
|
+
*/
|
|
16
|
+
export const GUARDRAILS_ACTION_ENTITIES = {
|
|
17
|
+
'call_tool': {
|
|
18
|
+
principals: ['User', 'Agent'],
|
|
19
|
+
resources: ['Session'],
|
|
20
|
+
},
|
|
21
|
+
'connect_server': {
|
|
22
|
+
principals: ['User', 'Agent'],
|
|
23
|
+
resources: ['Session'],
|
|
24
|
+
},
|
|
25
|
+
'process_prompt': {
|
|
26
|
+
principals: ['User', 'Agent'],
|
|
27
|
+
resources: ['App', 'Session'],
|
|
28
|
+
},
|
|
29
|
+
'read_file': {
|
|
30
|
+
principals: ['User', 'Agent'],
|
|
31
|
+
resources: ['Session'],
|
|
32
|
+
},
|
|
33
|
+
'write_file': {
|
|
34
|
+
principals: ['User', 'Agent'],
|
|
35
|
+
resources: ['Session'],
|
|
36
|
+
},
|
|
37
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -7,12 +7,17 @@ export * from './builder.js';
|
|
|
7
7
|
export * from './parser.js';
|
|
8
8
|
export * from './errors.js';
|
|
9
9
|
export * from './annotations.js';
|
|
10
|
-
export
|
|
10
|
+
export * from './explain.js';
|
|
11
|
+
export { GUARDRAILS_SCHEMA, GUARDRAILS_CONTEXT, OVERWATCH_SCHEMA, OVERWATCH_CONTEXT, PALISADE_SCHEMA, PALISADE_CONTEXT, } from './service-schemas.gen.js';
|
|
11
12
|
export type { ContextAttribute, ActionContext, ServiceContext, } from './service-schemas.gen.js';
|
|
13
|
+
export { GuardrailsContextKey } from './guardrails-context.gen.js';
|
|
12
14
|
export { OverwatchContextKey } from './overwatch-context.gen.js';
|
|
13
15
|
export { PalisadeContextKey } from './palisade-context.gen.js';
|
|
16
|
+
export { GUARDRAILS_ENTITIES, GUARDRAILS_ACTION_ENTITIES, } from './guardrails-entities.gen.js';
|
|
14
17
|
export { OVERWATCH_ENTITIES, OVERWATCH_ACTION_ENTITIES, } from './overwatch-entities.gen.js';
|
|
15
18
|
export { PALISADE_ENTITIES, PALISADE_ACTION_ENTITIES, } from './palisade-entities.gen.js';
|
|
16
19
|
export type { ServiceEntityMetadata, ActionEntityMetadata } from './entity-metadata-types.gen.js';
|
|
20
|
+
export { GUARDRAILS_DEFAULTS, GUARDRAILS_TEMPLATES, GUARDRAILS_CATEGORIES, GUARDRAILS_TEMPLATES_JSON, getGuardrailsDefaultsByCategory, getGuardrailsTemplatesByCategory, getGuardrailsTemplateById, } from './guardrails-defaults.gen.js';
|
|
21
|
+
export type { GuardrailsCategory, GuardrailsCategoryInfo, GuardrailsDefaultPolicy, GuardrailsTemplate, } from './guardrails-defaults.gen.js';
|
|
17
22
|
export { OVERWATCH_DEFAULTS, OVERWATCH_TEMPLATES, OVERWATCH_CATEGORIES, OVERWATCH_TEMPLATES_JSON, getOverwatchDefaultsByCategory, getOverwatchTemplatesByCategory, getOverwatchTemplateById, } from './overwatch-defaults.gen.js';
|
|
18
23
|
export type { OverwatchCategory, OverwatchCategoryInfo, OverwatchDefaultPolicy, OverwatchTemplate, } from './overwatch-defaults.gen.js';
|
package/dist/index.js
CHANGED
|
@@ -13,13 +13,18 @@ export * from './builder.js';
|
|
|
13
13
|
export * from './parser.js';
|
|
14
14
|
export * from './errors.js';
|
|
15
15
|
export * from './annotations.js';
|
|
16
|
+
// Decision explanation
|
|
17
|
+
export * from './explain.js';
|
|
16
18
|
// Service-specific schemas and context (inlined)
|
|
17
|
-
export { OVERWATCH_SCHEMA, OVERWATCH_CONTEXT, PALISADE_SCHEMA, PALISADE_CONTEXT, } from './service-schemas.gen.js';
|
|
19
|
+
export { GUARDRAILS_SCHEMA, GUARDRAILS_CONTEXT, OVERWATCH_SCHEMA, OVERWATCH_CONTEXT, PALISADE_SCHEMA, PALISADE_CONTEXT, } from './service-schemas.gen.js';
|
|
18
20
|
// Service-specific context key enums
|
|
21
|
+
export { GuardrailsContextKey } from './guardrails-context.gen.js';
|
|
19
22
|
export { OverwatchContextKey } from './overwatch-context.gen.js';
|
|
20
23
|
export { PalisadeContextKey } from './palisade-context.gen.js';
|
|
21
24
|
// Service-specific entity metadata (for UI - principals, resources, actions)
|
|
25
|
+
export { GUARDRAILS_ENTITIES, GUARDRAILS_ACTION_ENTITIES, } from './guardrails-entities.gen.js';
|
|
22
26
|
export { OVERWATCH_ENTITIES, OVERWATCH_ACTION_ENTITIES, } from './overwatch-entities.gen.js';
|
|
23
27
|
export { PALISADE_ENTITIES, PALISADE_ACTION_ENTITIES, } from './palisade-entities.gen.js';
|
|
24
28
|
// Service-specific default policies, templates, and categories
|
|
29
|
+
export { GUARDRAILS_DEFAULTS, GUARDRAILS_TEMPLATES, GUARDRAILS_CATEGORIES, GUARDRAILS_TEMPLATES_JSON, getGuardrailsDefaultsByCategory, getGuardrailsTemplatesByCategory, getGuardrailsTemplateById, } from './guardrails-defaults.gen.js';
|
|
25
30
|
export { OVERWATCH_DEFAULTS, OVERWATCH_TEMPLATES, OVERWATCH_CATEGORIES, OVERWATCH_TEMPLATES_JSON, getOverwatchDefaultsByCategory, getOverwatchTemplatesByCategory, getOverwatchTemplateById, } from './overwatch-defaults.gen.js';
|
|
@@ -59,6 +59,7 @@ const OVERWATCH_SECRETS_DEFAULT_CEDAR = `// ====================================
|
|
|
59
59
|
@description("Block prompts when YARA scanners detect API keys, tokens, or credential patterns")
|
|
60
60
|
@severity("critical")
|
|
61
61
|
@tags("secrets,credentials,prompts,nist-sc-28,nist-ia-5")
|
|
62
|
+
@reject_message("Your prompt was blocked because it contains detected secrets such as API keys, tokens, or credentials. Remove all secrets before resubmitting.")
|
|
62
63
|
forbid (
|
|
63
64
|
principal,
|
|
64
65
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -74,6 +75,7 @@ when {
|
|
|
74
75
|
@description("Prevent file reads and tool execution when secrets or credentials are detected in content")
|
|
75
76
|
@severity("high")
|
|
76
77
|
@tags("secrets,file-access,tools,credentials,nist-sc-28")
|
|
78
|
+
@reject_message("This operation was blocked because secrets or credentials were detected in the content. File reads and tool calls are restricted when credential exposure is identified.")
|
|
77
79
|
forbid (
|
|
78
80
|
principal,
|
|
79
81
|
action in [Overwatch::Action::"read_file", Overwatch::Action::"call_tool"],
|
|
@@ -93,6 +95,7 @@ when {
|
|
|
93
95
|
@description("Block access to .env files that commonly contain secrets, API keys, and database credentials")
|
|
94
96
|
@severity("high")
|
|
95
97
|
@tags("secrets,env-files,config,nist-sc-28,mitre-t1552")
|
|
98
|
+
@reject_message("Access to .env files is blocked because they commonly contain secrets, API keys, and database credentials. Use a secrets manager instead of .env files.")
|
|
96
99
|
forbid (
|
|
97
100
|
principal,
|
|
98
101
|
action in [Overwatch::Action::"read_file", Overwatch::Action::"write_file", Overwatch::Action::"call_tool"],
|
|
@@ -113,6 +116,7 @@ when {
|
|
|
113
116
|
@description("Detect and block AWS access key IDs (AKIA prefix) in AI responses to prevent credential exfiltration")
|
|
114
117
|
@severity("critical")
|
|
115
118
|
@tags("secrets,aws,credentials,response-scan,nist-ia-5,mitre-t1552")
|
|
119
|
+
@reject_message("This response was blocked because an AWS access key ID (AKIA prefix) was detected. AWS credentials must never be exposed in AI responses.")
|
|
116
120
|
forbid (
|
|
117
121
|
principal,
|
|
118
122
|
action,
|
|
@@ -129,6 +133,7 @@ when {
|
|
|
129
133
|
@description("Detect and block AWS secret access keys in AI responses")
|
|
130
134
|
@severity("critical")
|
|
131
135
|
@tags("secrets,aws,credentials,response-scan,nist-ia-5")
|
|
136
|
+
@reject_message("This response was blocked because an AWS secret access key was detected. AWS credentials must never be exposed in AI responses.")
|
|
132
137
|
forbid (
|
|
133
138
|
principal,
|
|
134
139
|
action,
|
|
@@ -146,6 +151,7 @@ when {
|
|
|
146
151
|
@description("Detect and block GitHub personal access tokens (ghp_), fine-grained tokens (github_pat_), and app tokens (ghs_)")
|
|
147
152
|
@severity("critical")
|
|
148
153
|
@tags("secrets,github,tokens,response-scan,mitre-t1552")
|
|
154
|
+
@reject_message("This response was blocked because a GitHub token (personal access token, fine-grained token, or app token) was detected. GitHub tokens must never be exposed in AI responses.")
|
|
149
155
|
forbid (
|
|
150
156
|
principal,
|
|
151
157
|
action,
|
|
@@ -164,6 +170,7 @@ when {
|
|
|
164
170
|
@description("Detect and block SSH, RSA, and OpenSSH private keys in AI responses")
|
|
165
171
|
@severity("critical")
|
|
166
172
|
@tags("secrets,ssh,private-keys,response-scan,nist-sc-28,mitre-t1552")
|
|
173
|
+
@reject_message("This response was blocked because a private key (SSH, RSA, or OpenSSH) was detected. Private keys must never be exposed in AI responses.")
|
|
167
174
|
forbid (
|
|
168
175
|
principal,
|
|
169
176
|
action,
|
|
@@ -187,6 +194,7 @@ when {
|
|
|
187
194
|
@description("Block content flagged by YARA rules for credential exposure, API key leaks, JWT tokens, and bearer tokens")
|
|
188
195
|
@severity("critical")
|
|
189
196
|
@tags("secrets,yara,credentials,jwt,bearer,nist-ia-5")
|
|
197
|
+
@reject_message("This content was blocked because YARA scanning detected credential patterns including secret exposure, credential leaks, API keys, JWT tokens, or bearer tokens.")
|
|
190
198
|
forbid (
|
|
191
199
|
principal,
|
|
192
200
|
action,
|
|
@@ -219,6 +227,7 @@ const OVERWATCH_PII_DEFAULT_CEDAR = `// ========================================
|
|
|
219
227
|
@description("Detect and block content containing credit card number patterns (PCI DSS compliance)")
|
|
220
228
|
@severity("critical")
|
|
221
229
|
@tags("pci,credit-card,payment,compliance,pci-dss-3.4")
|
|
230
|
+
@reject_message("Your prompt was blocked because credit card number patterns were detected. Sharing payment card data violates PCI DSS requirements.")
|
|
222
231
|
forbid (
|
|
223
232
|
principal,
|
|
224
233
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -234,6 +243,7 @@ when {
|
|
|
234
243
|
@description("Detect and block content containing SSN patterns (XXX-XX-XXXX format)")
|
|
235
244
|
@severity("critical")
|
|
236
245
|
@tags("ssn,identity,privacy,compliance")
|
|
246
|
+
@reject_message("Your prompt was blocked because Social Security Number patterns (XXX-XX-XXXX) were detected. SSNs are protected personal identifiers that must not be shared.")
|
|
237
247
|
forbid (
|
|
238
248
|
principal,
|
|
239
249
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -249,6 +259,7 @@ when {
|
|
|
249
259
|
@description("Block content when PII-related threat categories are detected by YARA or Javelin scanners")
|
|
250
260
|
@severity("high")
|
|
251
261
|
@tags("pii,privacy,data-protection,gdpr")
|
|
262
|
+
@reject_message("Your prompt was blocked because personally identifiable information was detected by threat scanners. Remove all PII before resubmitting.")
|
|
252
263
|
forbid (
|
|
253
264
|
principal,
|
|
254
265
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -280,6 +291,7 @@ when {
|
|
|
280
291
|
@description("Prevent tool execution when PII patterns are detected in content")
|
|
281
292
|
@severity("high")
|
|
282
293
|
@tags("pii,tools,data-protection")
|
|
294
|
+
@reject_message("Tool execution was blocked because personally identifiable information was detected in the content. PII must be removed before tool calls are permitted.")
|
|
283
295
|
forbid (
|
|
284
296
|
principal,
|
|
285
297
|
action == Overwatch::Action::"call_tool",
|
|
@@ -308,6 +320,7 @@ const OVERWATCH_SEMANTIC_DEFAULT_CEDAR = `// ===================================
|
|
|
308
320
|
@description("Detect and block prompt injection patterns in user input via YARA scanning (OWASP LLM01)")
|
|
309
321
|
@severity("critical")
|
|
310
322
|
@tags("injection,security,llm,owasp-llm01,baseline")
|
|
323
|
+
@reject_message("Your prompt was blocked because prompt injection patterns were detected by YARA scanning. This is a security measure to prevent manipulation of AI agent behavior.")
|
|
311
324
|
forbid (
|
|
312
325
|
principal,
|
|
313
326
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -339,6 +352,7 @@ when {
|
|
|
339
352
|
@description("Detect and block jailbreak and bypass attempts against AI agents (OWASP LLM02)")
|
|
340
353
|
@severity("critical")
|
|
341
354
|
@tags("jailbreak,bypass,security,owasp-llm02,baseline")
|
|
355
|
+
@reject_message("Your prompt was blocked because jailbreak or bypass patterns were detected by YARA scanning. This is a security measure to prevent circumvention of AI safety controls.")
|
|
342
356
|
forbid (
|
|
343
357
|
principal,
|
|
344
358
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -370,6 +384,7 @@ when {
|
|
|
370
384
|
@description("Block prompts when semantic threat scanners detect high severity issues (severity >= 3)")
|
|
371
385
|
@severity("high")
|
|
372
386
|
@tags("semantic,severity,security")
|
|
387
|
+
@reject_message("Your prompt was blocked because semantic threat scanners detected high severity issues in the content. Review your prompt for manipulative or adversarial patterns.")
|
|
373
388
|
forbid (
|
|
374
389
|
principal,
|
|
375
390
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -387,6 +402,7 @@ when {
|
|
|
387
402
|
@description("Block all content when any scanner detects critical severity threats")
|
|
388
403
|
@severity("critical")
|
|
389
404
|
@tags("critical,baseline,security")
|
|
405
|
+
@reject_message("Your prompt was blocked because security scanners detected a critical-severity threat. This content cannot be processed.")
|
|
390
406
|
forbid (
|
|
391
407
|
principal,
|
|
392
408
|
action == Overwatch::Action::"process_prompt",
|
|
@@ -402,6 +418,7 @@ when {
|
|
|
402
418
|
@description("Prevent tool execution when prompt injection patterns are detected in content")
|
|
403
419
|
@severity("critical")
|
|
404
420
|
@tags("injection,tools,security,owasp-llm01")
|
|
421
|
+
@reject_message("Tool execution was blocked because prompt injection patterns were detected in the content by YARA scanning.")
|
|
405
422
|
forbid (
|
|
406
423
|
principal,
|
|
407
424
|
action == Overwatch::Action::"call_tool",
|
|
@@ -435,6 +452,7 @@ const OVERWATCH_TOOLS_DEFAULT_CEDAR = `// ======================================
|
|
|
435
452
|
@description("Block direct shell, bash, and command execution tools to prevent command injection (MITRE T1059)")
|
|
436
453
|
@severity("critical")
|
|
437
454
|
@tags("shell,command-injection,execution,nist-cm-7,mitre-t1059,baseline")
|
|
455
|
+
@reject_message("Tool execution was blocked because direct shell and command execution tools (shell, bash, terminal, system.exec) are restricted to prevent command injection attacks.")
|
|
438
456
|
forbid (
|
|
439
457
|
principal,
|
|
440
458
|
action == Overwatch::Action::"call_tool",
|
|
@@ -456,6 +474,7 @@ when {
|
|
|
456
474
|
@description("Block file deletion and other destructive tool operations to prevent data loss")
|
|
457
475
|
@severity("high")
|
|
458
476
|
@tags("file,delete,destructive,nist-ac-3")
|
|
477
|
+
@reject_message("Tool execution was blocked because destructive file operations (delete, rmdir, unlink) are restricted to prevent data loss.")
|
|
459
478
|
forbid (
|
|
460
479
|
principal,
|
|
461
480
|
action == Overwatch::Action::"call_tool",
|
|
@@ -478,6 +497,7 @@ when {
|
|
|
478
497
|
@description("Prevent access to system directories, credential files, SSH keys, and cloud config (MITRE T1005, T1552.001)")
|
|
479
498
|
@severity("high")
|
|
480
499
|
@tags("file,path,system,security,nist-ac-6,mitre-t1005")
|
|
500
|
+
@reject_message("Access to this path was blocked because it targets a sensitive system directory or credential file (/etc, /proc, /sys, .ssh, .aws, .gnupg, or private key files).")
|
|
481
501
|
forbid (
|
|
482
502
|
principal,
|
|
483
503
|
action in [Overwatch::Action::"read_file", Overwatch::Action::"write_file", Overwatch::Action::"call_tool"],
|
|
@@ -508,6 +528,7 @@ when {
|
|
|
508
528
|
@description("Prevent tool execution when high or critical severity threats are detected in content")
|
|
509
529
|
@severity("high")
|
|
510
530
|
@tags("tools,threats,severity,security")
|
|
531
|
+
@reject_message("Tool execution was blocked because high or critical severity threats were detected in the content by security scanners.")
|
|
511
532
|
forbid (
|
|
512
533
|
principal,
|
|
513
534
|
action == Overwatch::Action::"call_tool",
|
|
@@ -736,8 +757,9 @@ permit (
|
|
|
736
757
|
resource
|
|
737
758
|
)
|
|
738
759
|
when {
|
|
739
|
-
context
|
|
740
|
-
context.mcp_server == "
|
|
760
|
+
context has mcp_server &&
|
|
761
|
+
(context.mcp_server == "filesystem" ||
|
|
762
|
+
context.mcp_server == "playwright")
|
|
741
763
|
};
|
|
742
764
|
|
|
743
765
|
@id("mcp-allowlist-deny")
|
|
@@ -751,6 +773,86 @@ forbid (
|
|
|
751
773
|
resource
|
|
752
774
|
);
|
|
753
775
|
`;
|
|
776
|
+
const OVERWATCH_TOOLS_MCP_TOOL_PERMISSIONS_CEDAR = `// =============================================================================
|
|
777
|
+
// MCP Tool Permissions Template (Overwatch)
|
|
778
|
+
// =============================================================================
|
|
779
|
+
// Per-tool access control for MCP servers in IDE environments.
|
|
780
|
+
// Complements the existing MCP Server Allowlist (connect_server action)
|
|
781
|
+
// with fine-grained per-tool control on call_tool action.
|
|
782
|
+
//
|
|
783
|
+
// Category: tools
|
|
784
|
+
// Namespace: Overwatch
|
|
785
|
+
// =============================================================================
|
|
786
|
+
|
|
787
|
+
// -- GitHub MCP: Read-only access -------------------------------------------
|
|
788
|
+
|
|
789
|
+
@id("mcp-tool-allow-read-github")
|
|
790
|
+
@name("Allow read-only GitHub tools")
|
|
791
|
+
@description("Permit read operations from GitHub MCP server")
|
|
792
|
+
@severity("medium")
|
|
793
|
+
@tags("mcp,github,read-only,least-privilege")
|
|
794
|
+
permit (
|
|
795
|
+
principal,
|
|
796
|
+
action == Overwatch::Action::"call_tool",
|
|
797
|
+
resource
|
|
798
|
+
) when {
|
|
799
|
+
context has mcp_server && context.mcp_server == "github" &&
|
|
800
|
+
context has tool_name &&
|
|
801
|
+
(context.tool_name == "read_issues" ||
|
|
802
|
+
context.tool_name == "get_issue" ||
|
|
803
|
+
context.tool_name == "list_repos" ||
|
|
804
|
+
context.tool_name == "get_pull_request" ||
|
|
805
|
+
context.tool_name == "search_code" ||
|
|
806
|
+
context.tool_name == "get_file_contents")
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
@id("mcp-tool-deny-write-github")
|
|
810
|
+
@name("Deny write GitHub tools")
|
|
811
|
+
@description("Block create/update/delete operations on GitHub MCP server")
|
|
812
|
+
@severity("high")
|
|
813
|
+
@tags("mcp,github,write-block,least-privilege")
|
|
814
|
+
forbid (
|
|
815
|
+
principal,
|
|
816
|
+
action == Overwatch::Action::"call_tool",
|
|
817
|
+
resource
|
|
818
|
+
) when {
|
|
819
|
+
context has mcp_server && context.mcp_server == "github"
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
// -- Organization-wide MCP server exclusions --------------------------------
|
|
823
|
+
|
|
824
|
+
@id("mcp-tool-exclude-server")
|
|
825
|
+
@name("Exclude specific MCP servers")
|
|
826
|
+
@description("Block all tool calls from excluded MCP servers (org-wide exclusion list)")
|
|
827
|
+
@severity("critical")
|
|
828
|
+
@tags("mcp,exclusion,org-wide,block")
|
|
829
|
+
forbid (
|
|
830
|
+
principal,
|
|
831
|
+
action == Overwatch::Action::"call_tool",
|
|
832
|
+
resource
|
|
833
|
+
) when {
|
|
834
|
+
// Add server names to block across the organization.
|
|
835
|
+
// Modify this list to match your exclusion requirements.
|
|
836
|
+
context has mcp_server &&
|
|
837
|
+
(context.mcp_server == "untrusted-server" ||
|
|
838
|
+
context.mcp_server == "deprecated-server")
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
// -- Block unverified MCP servers -------------------------------------------
|
|
842
|
+
|
|
843
|
+
@id("mcp-tool-block-unverified")
|
|
844
|
+
@name("Block tools from unverified MCP servers")
|
|
845
|
+
@description("Deny tool calls from MCP servers not in the verified registry")
|
|
846
|
+
@severity("high")
|
|
847
|
+
@tags("mcp,trust,verification")
|
|
848
|
+
forbid (
|
|
849
|
+
principal,
|
|
850
|
+
action == Overwatch::Action::"call_tool",
|
|
851
|
+
resource
|
|
852
|
+
) when {
|
|
853
|
+
context has mcp_server_verified && context.mcp_server_verified == false
|
|
854
|
+
};
|
|
855
|
+
`;
|
|
754
856
|
const OVERWATCH_ORG_DEFAULT_DENY_CEDAR = `// Default Deny All Template
|
|
755
857
|
// Organization-wide baseline: deny all unless explicitly permitted
|
|
756
858
|
// Category: organization
|
|
@@ -956,6 +1058,15 @@ export const OVERWATCH_TEMPLATES = [
|
|
|
956
1058
|
severity: 'medium',
|
|
957
1059
|
tags: ['mcp', 'allowlist', 'whitelist'],
|
|
958
1060
|
},
|
|
1061
|
+
{
|
|
1062
|
+
id: 'tools-mcp-tool-permissions',
|
|
1063
|
+
name: 'MCP Tool Permissions',
|
|
1064
|
+
description: 'Per-tool access control for MCP servers — allow specific tools while denying others, exclude servers org-wide, block unverified sources',
|
|
1065
|
+
category: 'tools',
|
|
1066
|
+
cedarText: OVERWATCH_TOOLS_MCP_TOOL_PERMISSIONS_CEDAR,
|
|
1067
|
+
severity: 'high',
|
|
1068
|
+
tags: ['mcp', 'tools', 'least-privilege', 'per-server', 'exclusion'],
|
|
1069
|
+
},
|
|
959
1070
|
{
|
|
960
1071
|
id: 'org-default-deny',
|
|
961
1072
|
name: 'Default Deny All',
|
|
@@ -1120,6 +1231,15 @@ export const OVERWATCH_TEMPLATES_JSON = `{
|
|
|
1120
1231
|
"severity": "medium",
|
|
1121
1232
|
"tags": ["mcp", "allowlist", "whitelist"]
|
|
1122
1233
|
},
|
|
1234
|
+
{
|
|
1235
|
+
"id": "tools-mcp-tool-permissions",
|
|
1236
|
+
"name": "MCP Tool Permissions",
|
|
1237
|
+
"description": "Per-tool access control for MCP servers — allow specific tools while denying others, exclude servers org-wide, block unverified sources",
|
|
1238
|
+
"category": "tools",
|
|
1239
|
+
"file": "mcp_tool_permissions.cedar",
|
|
1240
|
+
"severity": "high",
|
|
1241
|
+
"tags": ["mcp", "tools", "least-privilege", "per-server", "exclusion"]
|
|
1242
|
+
},
|
|
1123
1243
|
{
|
|
1124
1244
|
"id": "org-default-deny",
|
|
1125
1245
|
"name": "Default Deny All",
|
package/dist/parser.js
CHANGED
|
@@ -134,11 +134,14 @@ function cedarJsonToRule(policy, policyId, index, originalText) {
|
|
|
134
134
|
order: index,
|
|
135
135
|
};
|
|
136
136
|
// Map conditions
|
|
137
|
-
const { conditions, rawCondition } = mapConditions(policy.conditions, originalText);
|
|
137
|
+
const { conditions, rawCondition, conditionExpression } = mapConditions(policy.conditions, originalText);
|
|
138
138
|
rule.conditions = conditions;
|
|
139
139
|
if (rawCondition) {
|
|
140
140
|
rule.rawCondition = rawCondition;
|
|
141
141
|
}
|
|
142
|
+
if (conditionExpression) {
|
|
143
|
+
rule.conditionExpression = conditionExpression;
|
|
144
|
+
}
|
|
142
145
|
return { rule };
|
|
143
146
|
}
|
|
144
147
|
catch (e) {
|
|
@@ -227,7 +230,7 @@ function mapScopeToEntity(scope, field) {
|
|
|
227
230
|
if (scope.op === "in") {
|
|
228
231
|
if ("entity" in scope) {
|
|
229
232
|
const entity = normalizeEntityRef(scope.entity);
|
|
230
|
-
return { type: entity.type, id: entity.id };
|
|
233
|
+
return { type: entity.type, id: entity.id, operator: 'in' };
|
|
231
234
|
}
|
|
232
235
|
if ("slot" in scope) {
|
|
233
236
|
throw ParserError.scopeSlotNotSupported("in", field);
|
|
@@ -279,17 +282,20 @@ function mapActionScope(scope) {
|
|
|
279
282
|
throw ParserError.actionUnsupportedOp(scope.op);
|
|
280
283
|
}
|
|
281
284
|
/**
|
|
282
|
-
* Map Cedar conditions to PolicyCondition array.
|
|
283
|
-
* When conditions can't be mapped to
|
|
285
|
+
* Map Cedar conditions to PolicyCondition array + recursive ConditionExpression.
|
|
286
|
+
* When conditions can't be mapped to the flat format, extract the raw Cedar
|
|
284
287
|
* condition text from the engine-serialized policy text (not JSON AST).
|
|
285
288
|
*/
|
|
286
289
|
function mapConditions(conditions, originalText) {
|
|
287
290
|
const result = [];
|
|
288
291
|
let hasUnmapped = false;
|
|
292
|
+
// Collect condition expressions from all when clauses
|
|
293
|
+
const expressions = [];
|
|
289
294
|
for (const cond of conditions) {
|
|
290
295
|
if (cond.kind !== "when") {
|
|
291
296
|
continue;
|
|
292
297
|
}
|
|
298
|
+
// Flat mapping (backward compat)
|
|
293
299
|
const parsed = mapConditionBody(cond.body);
|
|
294
300
|
if (parsed.condition) {
|
|
295
301
|
result.push(parsed.condition);
|
|
@@ -297,15 +303,26 @@ function mapConditions(conditions, originalText) {
|
|
|
297
303
|
else if (parsed.raw) {
|
|
298
304
|
hasUnmapped = true;
|
|
299
305
|
}
|
|
306
|
+
// Recursive mapping (new)
|
|
307
|
+
expressions.push(mapConditionBodyToExpression(cond.body, originalText));
|
|
300
308
|
}
|
|
301
309
|
// Extract readable Cedar condition text instead of storing JSON AST
|
|
302
310
|
let rawCondition;
|
|
303
311
|
if (hasUnmapped && originalText) {
|
|
304
312
|
rawCondition = extractWhenClause(originalText);
|
|
305
313
|
}
|
|
314
|
+
// Build the final condition expression
|
|
315
|
+
let conditionExpression;
|
|
316
|
+
if (expressions.length === 1) {
|
|
317
|
+
conditionExpression = expressions[0];
|
|
318
|
+
}
|
|
319
|
+
else if (expressions.length > 1) {
|
|
320
|
+
conditionExpression = { kind: 'and', children: expressions };
|
|
321
|
+
}
|
|
306
322
|
return {
|
|
307
323
|
conditions: result,
|
|
308
324
|
rawCondition: rawCondition || undefined,
|
|
325
|
+
conditionExpression,
|
|
309
326
|
};
|
|
310
327
|
}
|
|
311
328
|
/**
|
|
@@ -365,6 +382,121 @@ function mapConditionBody(body) {
|
|
|
365
382
|
// Can't map - return as raw JSON
|
|
366
383
|
return { raw: JSON.stringify(body) };
|
|
367
384
|
}
|
|
385
|
+
// ---------------------------------------------------------------------------
|
|
386
|
+
// Recursive condition expression walker
|
|
387
|
+
// ---------------------------------------------------------------------------
|
|
388
|
+
/**
|
|
389
|
+
* Recursively walk the Cedar JSON AST to build a ConditionExpression tree.
|
|
390
|
+
* Flattens binary && / || chains into n-ary and/or nodes.
|
|
391
|
+
*/
|
|
392
|
+
function mapConditionBodyToExpression(expr, originalText) {
|
|
393
|
+
// Logical AND — flatten binary chain
|
|
394
|
+
if (expr["&&"]) {
|
|
395
|
+
const children = flattenBinaryChain("&&", expr);
|
|
396
|
+
return { kind: 'and', children };
|
|
397
|
+
}
|
|
398
|
+
// Logical OR — flatten binary chain
|
|
399
|
+
if (expr["||"]) {
|
|
400
|
+
const children = flattenBinaryChain("||", expr);
|
|
401
|
+
return { kind: 'or', children };
|
|
402
|
+
}
|
|
403
|
+
// Negation
|
|
404
|
+
if (expr["!"]) {
|
|
405
|
+
const child = mapConditionBodyToExpression(expr["!"].arg, originalText);
|
|
406
|
+
return { kind: 'not', child };
|
|
407
|
+
}
|
|
408
|
+
// Has (existence check): { has: { left: { Var: "context" }, attr: "field" } }
|
|
409
|
+
if (expr.has) {
|
|
410
|
+
const field = extractHasField(expr.has);
|
|
411
|
+
if (field) {
|
|
412
|
+
return { kind: 'has', field };
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Leaf: comparison operators
|
|
416
|
+
for (const op of ["==", "!=", "<", "<=", ">", ">="]) {
|
|
417
|
+
const comparison = expr[op];
|
|
418
|
+
if (comparison) {
|
|
419
|
+
const mapped = mapComparisonToExpression(op, comparison);
|
|
420
|
+
if (mapped)
|
|
421
|
+
return mapped;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// Leaf: contains
|
|
425
|
+
if (expr.contains) {
|
|
426
|
+
const mapped = mapContainsToExpression(expr.contains);
|
|
427
|
+
if (mapped)
|
|
428
|
+
return mapped;
|
|
429
|
+
}
|
|
430
|
+
// Leaf: like
|
|
431
|
+
if (expr.like) {
|
|
432
|
+
const mapped = mapLikeToExpression(expr.like);
|
|
433
|
+
if (mapped)
|
|
434
|
+
return mapped;
|
|
435
|
+
}
|
|
436
|
+
// Fallback — extract readable text if possible
|
|
437
|
+
const text = originalText ? extractWhenClause(originalText) : JSON.stringify(expr);
|
|
438
|
+
return { kind: 'raw', text };
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Flatten a binary chain of && or || into a flat array of expressions.
|
|
442
|
+
* (A && B) && C becomes [A, B, C] instead of nested binary pairs.
|
|
443
|
+
*/
|
|
444
|
+
function flattenBinaryChain(op, expr) {
|
|
445
|
+
const node = expr[op];
|
|
446
|
+
if (!node)
|
|
447
|
+
return [mapConditionBodyToExpression(expr)];
|
|
448
|
+
return [
|
|
449
|
+
...flattenBinaryChain(op, node.left),
|
|
450
|
+
...flattenBinaryChain(op, node.right),
|
|
451
|
+
];
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Extract field name from a "has" expression.
|
|
455
|
+
* Pattern: { left: { Var: "context" }, attr: "field_name" }
|
|
456
|
+
*/
|
|
457
|
+
function extractHasField(has) {
|
|
458
|
+
if (has.left.Var === "context") {
|
|
459
|
+
return has.attr;
|
|
460
|
+
}
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
function mapComparisonToExpression(op, args) {
|
|
464
|
+
const field = extractContextField(args.left);
|
|
465
|
+
if (!field)
|
|
466
|
+
return null;
|
|
467
|
+
const value = extractLiteralValue(args.right);
|
|
468
|
+
if (value === undefined)
|
|
469
|
+
return null;
|
|
470
|
+
const operator = mapOperator(op);
|
|
471
|
+
if (!operator)
|
|
472
|
+
return null;
|
|
473
|
+
return { kind: 'comparison', field, operator, value };
|
|
474
|
+
}
|
|
475
|
+
function mapContainsToExpression(args) {
|
|
476
|
+
const field = extractContextField(args.left);
|
|
477
|
+
if (!field)
|
|
478
|
+
return null;
|
|
479
|
+
const value = extractLiteralValue(args.right);
|
|
480
|
+
if (value === undefined || typeof value === 'object')
|
|
481
|
+
return null;
|
|
482
|
+
return { kind: 'contains', field, value: value };
|
|
483
|
+
}
|
|
484
|
+
function mapLikeToExpression(args) {
|
|
485
|
+
const field = extractContextField(args.left);
|
|
486
|
+
if (!field)
|
|
487
|
+
return null;
|
|
488
|
+
const patternStr = args.pattern.map(p => {
|
|
489
|
+
if (p === "Wildcard")
|
|
490
|
+
return "*";
|
|
491
|
+
if (typeof p === "object" && "Literal" in p)
|
|
492
|
+
return p.Literal.replace(/\*/g, "\\*");
|
|
493
|
+
return "";
|
|
494
|
+
}).join("");
|
|
495
|
+
return { kind: 'like', field, pattern: patternStr };
|
|
496
|
+
}
|
|
497
|
+
// ---------------------------------------------------------------------------
|
|
498
|
+
// Flat condition mapping (backward compat)
|
|
499
|
+
// ---------------------------------------------------------------------------
|
|
368
500
|
function mapComparison(op, args) {
|
|
369
501
|
const field = extractContextField(args.left);
|
|
370
502
|
if (!field)
|
package/dist/schema.gen.d.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Embedded Cedar schema for policy validation.
|
|
3
3
|
* This is the Highflame Cedar schema used across all services.
|
|
4
4
|
*/
|
|
5
|
-
export declare const CEDAR_SCHEMA = "// Highflame Cedar Schema - Entity and Action Definitions\n// =======================================================\n// This file defines all entity types and actions used across Highflame services.\n// Used for code generation (EntityType and ActionType constants).\n//\n// For policy validation, use service-specific schemas:\n// - schemas/overwatch/schema.cedarschema (Guardian IDE security)\n// - schemas/palisade/schema.cedarschema (ML supply chain security)\n\nnamespace Highflame {\n\n// =============================================================================\n// ENTITIES\n// =============================================================================\n\nentity User {\n user_type: String,\n};\n\nentity Agent {\n agent_type: String,\n};\n\nentity Scanner {\n scanner_type: String,\n};\n\nentity Service {\n service_type: String,\n};\n\nentity Resource {};\n\nentity LlmPrompt {\n prompt_type: String,\n};\n\nentity ResponseData {};\n\nentity Tool {\n tool_name: String,\n};\n\nentity FilePath {\n path: String,\n};\n\nentity HttpEndpoint {\n hostname: String,\n};\n\nentity Server {\n server_name: String,\n};\n\nentity Artifact {\n artifact_format: String,\n};\n\nentity Repository {\n repo_url: String,\n};\n\nentity Package {\n package_name: String,\n};\n\nentity GitBranch {\n branch_name: String,\n};\n\nentity Model {\n model_name: String,\n};\n\nentity ExternalAPI {\n api_name: String,\n};\n\nentity Memory {\n memory_type: String,\n};\n\n// =============================================================================\n// ACTIONS\n// =============================================================================\n\naction process_prompt;\naction process_response;\naction invoke_model;\naction filter_content;\naction call_tool;\naction connect_server;\naction access_server_resource;\naction skip_guardrails;\naction read_file;\naction write_file;\naction delete_file;\naction http_request;\naction call_external_api;\naction execute_code;\naction run_tests;\naction run_build;\naction git_operation;\naction git_clone;\naction git_commit;\naction git_push;\naction git_pull;\naction git_merge;\naction git_checkout;\naction git_reset;\naction git_rebase;\naction delegate_task;\naction spawn_subprocess;\naction access_memory;\naction scan_target;\naction scan_package;\naction scan_artifact;\naction validate_integrity;\naction validate_provenance;\naction quarantine_artifact;\naction load_model;\naction deploy_model;\naction transfer_data;\naction export_data;\n}\n";
|
|
5
|
+
export declare const CEDAR_SCHEMA = "// Highflame Cedar Schema - Entity and Action Definitions\n// =======================================================\n// This file defines all entity types and actions used across Highflame services.\n// Used for code generation (EntityType and ActionType constants).\n//\n// For policy validation, use service-specific schemas:\n// - schemas/overwatch/schema.cedarschema (Guardian IDE security)\n// - schemas/palisade/schema.cedarschema (ML supply chain security)\n\nnamespace Highflame {\n\n// =============================================================================\n// ENTITIES\n// =============================================================================\n\n// Multi-tenant hierarchy (used by services for ReBAC policy scoping)\nentity Account {};\nentity Project {};\nentity App {};\nentity Session {};\n\nentity User {\n user_type: String,\n};\n\nentity Agent {\n agent_type: String,\n};\n\nentity Scanner {\n scanner_type: String,\n};\n\nentity Service {\n service_type: String,\n};\n\nentity Resource {};\n\nentity LlmPrompt {\n prompt_type: String,\n};\n\nentity ResponseData {};\n\nentity Tool {\n tool_name: String,\n};\n\nentity FilePath {\n path: String,\n};\n\nentity HttpEndpoint {\n hostname: String,\n};\n\nentity Server {\n server_name: String,\n};\n\nentity Artifact {\n artifact_format: String,\n};\n\nentity Repository {\n repo_url: String,\n};\n\nentity Package {\n package_name: String,\n};\n\nentity GitBranch {\n branch_name: String,\n};\n\nentity Model {\n model_name: String,\n};\n\nentity ExternalAPI {\n api_name: String,\n};\n\nentity Memory {\n memory_type: String,\n};\n\n// =============================================================================\n// ACTIONS\n// =============================================================================\n\naction process_prompt;\naction process_response;\naction invoke_model;\naction filter_content;\naction call_tool;\naction connect_server;\naction access_server_resource;\naction skip_guardrails;\naction read_file;\naction write_file;\naction delete_file;\naction http_request;\naction call_external_api;\naction execute_code;\naction run_tests;\naction run_build;\naction git_operation;\naction git_clone;\naction git_commit;\naction git_push;\naction git_pull;\naction git_merge;\naction git_checkout;\naction git_reset;\naction git_rebase;\naction delegate_task;\naction spawn_subprocess;\naction access_memory;\naction scan_target;\naction scan_package;\naction scan_artifact;\naction validate_integrity;\naction validate_provenance;\naction quarantine_artifact;\naction load_model;\naction deploy_model;\naction transfer_data;\naction export_data;\n}\n";
|
package/dist/schema.gen.js
CHANGED
|
@@ -19,6 +19,12 @@ namespace Highflame {
|
|
|
19
19
|
// ENTITIES
|
|
20
20
|
// =============================================================================
|
|
21
21
|
|
|
22
|
+
// Multi-tenant hierarchy (used by services for ReBAC policy scoping)
|
|
23
|
+
entity Account {};
|
|
24
|
+
entity Project {};
|
|
25
|
+
entity App {};
|
|
26
|
+
entity Session {};
|
|
27
|
+
|
|
22
28
|
entity User {
|
|
23
29
|
user_type: String,
|
|
24
30
|
};
|