protect-mcp 0.5.0 → 0.5.2

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/dist/index.js CHANGED
@@ -35041,18 +35041,21 @@ __export(index_exports, {
35041
35041
  createSandboxServer: () => createSandboxServer,
35042
35042
  destroySandbox: () => destroySandbox,
35043
35043
  ed25519ToDIDKey: () => ed25519ToDIDKey,
35044
+ evaluateCedar: () => evaluateCedar,
35044
35045
  evaluateTier: () => evaluateTier,
35045
35046
  exportC2PAManifestJSON: () => exportC2PAManifestJSON,
35046
35047
  exportJSONL: () => exportJSONL,
35047
35048
  formatReportMarkdown: () => formatReportMarkdown,
35048
35049
  formatSimulation: () => formatSimulation,
35049
35050
  generateC2PACommand: () => generateC2PACommand,
35051
+ generateCedarSchema: () => generateCedarSchema,
35050
35052
  generateDatasetCard: () => generateDatasetCard,
35051
35053
  generateHFMetadata: () => generateHFMetadata,
35052
35054
  generateHookSettings: () => generateHookSettings,
35053
35055
  generateReport: () => generateReport,
35054
35056
  generateSafetyTranscript: () => generateSafetyTranscript,
35055
35057
  generateSampleCedarPolicy: () => generateSampleCedarPolicy,
35058
+ generateSchemaStub: () => generateSchemaStub,
35056
35059
  generateVerifyReceiptSkill: () => generateVerifyReceiptSkill,
35057
35060
  getSignerInfo: () => getSignerInfo,
35058
35061
  getToolPolicy: () => getToolPolicy,
@@ -35060,11 +35063,13 @@ __export(index_exports, {
35060
35063
  hashResponseBody: () => hashResponseBody,
35061
35064
  initSigning: () => initSigning,
35062
35065
  isAgentId: () => isAgentId,
35066
+ isCedarAvailable: () => isCedarAvailable,
35063
35067
  isDisclosureMode: () => isDisclosureMode,
35064
35068
  isEvidenceType: () => isEvidenceType,
35065
35069
  isManifestStatus: () => isManifestStatus,
35066
35070
  isSigningEnabled: () => isSigningEnabled,
35067
35071
  listCredentialLabels: () => listCredentialLabels,
35072
+ loadCedarPolicies: () => loadCedarPolicies,
35068
35073
  loadPolicy: () => loadPolicy,
35069
35074
  manifestToVC: () => manifestToVC,
35070
35075
  meetsMinTier: () => meetsMinTier,
@@ -35731,7 +35736,7 @@ function buildEntities(req) {
35731
35736
  }
35732
35737
  ];
35733
35738
  }
35734
- async function evaluateCedar(policySet, req) {
35739
+ async function evaluateCedar(policySet, req, schema) {
35735
35740
  const available = await ensureCedarWasm();
35736
35741
  if (!available) {
35737
35742
  return {
@@ -35742,16 +35747,21 @@ async function evaluateCedar(policySet, req) {
35742
35747
  }
35743
35748
  try {
35744
35749
  const agentId = req.agentId || req.tier;
35750
+ const context = {
35751
+ tier: req.tier,
35752
+ ...req.context || {}
35753
+ };
35754
+ if (req.toolInput && Object.keys(req.toolInput).length > 0) {
35755
+ context.input = req.toolInput;
35756
+ }
35745
35757
  const authRequest = {
35746
35758
  principal: { type: "Agent", id: agentId },
35747
35759
  action: { type: "Action", id: "MCP::Tool::call" },
35748
35760
  resource: { type: "Tool", id: req.tool },
35749
- context: {
35750
- tier: req.tier,
35751
- ...req.context || {}
35752
- }
35761
+ context
35753
35762
  };
35754
35763
  const entities = buildEntities(req);
35764
+ const cedarSchema = schema?.schemaJson ?? null;
35755
35765
  let result;
35756
35766
  if (typeof cedarWasm.isAuthorized === "function") {
35757
35767
  result = cedarWasm.isAuthorized({
@@ -35761,8 +35771,7 @@ async function evaluateCedar(policySet, req) {
35761
35771
  action: authRequest.action,
35762
35772
  resource: authRequest.resource,
35763
35773
  context: authRequest.context,
35764
- schema: null
35765
- // No schema enforcement — Cedar still evaluates correctly
35774
+ schema: cedarSchema
35766
35775
  });
35767
35776
  } else if (typeof cedarWasm.checkAuthorization === "function") {
35768
35777
  result = cedarWasm.checkAuthorization(
@@ -35780,7 +35789,7 @@ async function evaluateCedar(policySet, req) {
35780
35789
  action: authRequest.action,
35781
35790
  resource: authRequest.resource,
35782
35791
  context: authRequest.context,
35783
- schema: null
35792
+ schema: cedarSchema
35784
35793
  });
35785
35794
  } else {
35786
35795
  return {
@@ -38381,6 +38390,273 @@ If swarm data exists, show the agent topology (coordinator \u2192 workers).
38381
38390
  `;
38382
38391
  }
38383
38392
 
38393
+ // src/cedar-schema.ts
38394
+ function jsonSchemaToCedarType(schema, namespace, path) {
38395
+ if (schema.enum) {
38396
+ return "String";
38397
+ }
38398
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
38399
+ switch (type) {
38400
+ case "string":
38401
+ if (schema.format === "date-time") return "String";
38402
+ if (schema.format === "uri") return "String";
38403
+ return "String";
38404
+ case "integer":
38405
+ case "number":
38406
+ return "Long";
38407
+ case "boolean":
38408
+ return "Bool";
38409
+ case "array":
38410
+ if (schema.items) {
38411
+ const itemType = jsonSchemaToCedarType(schema.items, namespace, path + "_item");
38412
+ return `Set<${itemType}>`;
38413
+ }
38414
+ return "Set<String>";
38415
+ // Default to Set<String> for untyped arrays
38416
+ case "object":
38417
+ if (schema.properties && Object.keys(schema.properties).length > 0) {
38418
+ const fields = Object.entries(schema.properties).map(([key, prop]) => {
38419
+ const cedarType = jsonSchemaToCedarType(prop, namespace, path + "_" + sanitizeIdentifier(key));
38420
+ const isRequired = schema.required?.includes(key) ?? false;
38421
+ return ` "${sanitizeIdentifier(key)}": ${cedarType}${isRequired ? "" : "?"}`;
38422
+ });
38423
+ return `{
38424
+ ${fields.join(",\n")}
38425
+ }`;
38426
+ }
38427
+ return "Record";
38428
+ // Empty objects
38429
+ default:
38430
+ return "String";
38431
+ }
38432
+ }
38433
+ function sanitizeIdentifier(name) {
38434
+ return name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^(\d)/, "_$1");
38435
+ }
38436
+ function cedarActionId(toolName) {
38437
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(toolName)) {
38438
+ return toolName;
38439
+ }
38440
+ return toolName;
38441
+ }
38442
+ function generateCedarSchema(tools, config = {}) {
38443
+ const ns = config.namespace || "ScopeBlind";
38444
+ const includeTier = config.includeTier !== false;
38445
+ const includeTimestamp = config.includeTimestamp !== false;
38446
+ const includeAgentId = config.includeAgentId !== false;
38447
+ const agentAttrs = [];
38448
+ if (includeTier) agentAttrs.push(' "tier": String');
38449
+ if (includeAgentId) agentAttrs.push(' "agent_id": String?');
38450
+ const sessionFields = [];
38451
+ if (includeTimestamp) sessionFields.push(' "timestamp": String?');
38452
+ sessionFields.push(' "hook_event": String?');
38453
+ const actionDeclarations = [];
38454
+ const inputTypeDeclarations = [];
38455
+ for (const tool of tools) {
38456
+ const actionName = cedarActionId(tool.name);
38457
+ const inputTypeName = `${sanitizeIdentifier(tool.name)}_Input`;
38458
+ if (tool.inputSchema?.properties && Object.keys(tool.inputSchema.properties).length > 0) {
38459
+ const fields = Object.entries(tool.inputSchema.properties).map(([key, prop]) => {
38460
+ const cedarType = jsonSchemaToCedarType(prop, ns, sanitizeIdentifier(tool.name) + "_" + sanitizeIdentifier(key));
38461
+ const isRequired = tool.inputSchema?.required?.includes(key) ?? false;
38462
+ return ` "${sanitizeIdentifier(key)}": ${cedarType}${isRequired ? "" : "?"}`;
38463
+ });
38464
+ inputTypeDeclarations.push(
38465
+ ` // Input type for tool: ${tool.name}` + (tool.description ? `
38466
+ // ${tool.description}` : "") + `
38467
+ type ${inputTypeName} = {
38468
+ ${fields.join(",\n")}
38469
+ };`
38470
+ );
38471
+ actionDeclarations.push(
38472
+ ` action "${actionName}" in [Action::"MCP::Tool::call"] appliesTo {
38473
+ principal: [Agent],
38474
+ resource: [Tool],
38475
+ context: {
38476
+ "input": ${inputTypeName},
38477
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
38478
+ }
38479
+ };`
38480
+ );
38481
+ } else {
38482
+ actionDeclarations.push(
38483
+ ` action "${actionName}" in [Action::"MCP::Tool::call"] appliesTo {
38484
+ principal: [Agent],
38485
+ resource: [Tool],
38486
+ context: {
38487
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
38488
+ }
38489
+ };`
38490
+ );
38491
+ }
38492
+ }
38493
+ actionDeclarations.push(
38494
+ ` // Blanket action for policies matching any tool call
38495
+ action "MCP::Tool::call" appliesTo {
38496
+ principal: [Agent],
38497
+ resource: [Tool],
38498
+ context: {
38499
+ "tier": String${includeTimestamp ? ',\n "timestamp": String?' : ""}${includeAgentId ? ',\n "agent_id": String?' : ""}
38500
+ }
38501
+ };`
38502
+ );
38503
+ const schemaText = [
38504
+ `// Cedar schema for MCP tool governance`,
38505
+ `// Generated by protect-mcp from ${tools.length} tool description(s)`,
38506
+ `// Compatible with cedar-policy/cedar-for-agents`,
38507
+ ``,
38508
+ `namespace ${ns} {`,
38509
+ ``,
38510
+ ` // \u2500\u2500 Entity types \u2500\u2500`,
38511
+ ``,
38512
+ ` entity Agent${agentAttrs.length > 0 ? ` = {
38513
+ ${agentAttrs.join(",\n")}
38514
+ }` : ""};`,
38515
+ ``,
38516
+ ` entity Tool;`,
38517
+ ``,
38518
+ ...inputTypeDeclarations.length > 0 ? [` // \u2500\u2500 Tool input types \u2500\u2500`, ``, ...inputTypeDeclarations, ``] : [],
38519
+ ` // \u2500\u2500 Actions \u2500\u2500`,
38520
+ ``,
38521
+ ...actionDeclarations,
38522
+ ``,
38523
+ `}`,
38524
+ ``
38525
+ ].join("\n");
38526
+ const schemaJson = buildSchemaJson(tools, ns, config);
38527
+ return {
38528
+ schemaText,
38529
+ schemaJson,
38530
+ toolCount: tools.length,
38531
+ tools: tools.map((t) => t.name)
38532
+ };
38533
+ }
38534
+ function buildSchemaJson(tools, namespace, config) {
38535
+ const entityTypes = {
38536
+ Agent: {
38537
+ shape: {
38538
+ type: "Record",
38539
+ attributes: {
38540
+ ...config.includeTier !== false ? { tier: { type: "String", required: false } } : {},
38541
+ ...config.includeAgentId !== false ? { agent_id: { type: "String", required: false } } : {}
38542
+ }
38543
+ },
38544
+ memberOfTypes: []
38545
+ },
38546
+ Tool: {
38547
+ shape: { type: "Record", attributes: {} },
38548
+ memberOfTypes: []
38549
+ }
38550
+ };
38551
+ const actions = {};
38552
+ for (const tool of tools) {
38553
+ const contextAttrs = {
38554
+ tier: { type: "String", required: false }
38555
+ };
38556
+ if (config.includeTimestamp !== false) {
38557
+ contextAttrs["timestamp"] = { type: "String", required: false };
38558
+ }
38559
+ if (config.includeAgentId !== false) {
38560
+ contextAttrs["agent_id"] = { type: "String", required: false };
38561
+ }
38562
+ if (tool.inputSchema?.properties) {
38563
+ const inputAttrs = {};
38564
+ for (const [key, prop] of Object.entries(tool.inputSchema.properties)) {
38565
+ inputAttrs[sanitizeIdentifier(key)] = {
38566
+ type: jsonSchemaToSchemaJsonType(prop),
38567
+ required: tool.inputSchema.required?.includes(key) ?? false
38568
+ };
38569
+ }
38570
+ contextAttrs["input"] = {
38571
+ type: "Record",
38572
+ attributes: inputAttrs,
38573
+ required: false
38574
+ };
38575
+ }
38576
+ actions[tool.name] = {
38577
+ appliesTo: {
38578
+ principalTypes: ["Agent"],
38579
+ resourceTypes: ["Tool"],
38580
+ context: { type: "Record", attributes: contextAttrs }
38581
+ },
38582
+ memberOf: [{ id: "MCP::Tool::call" }]
38583
+ };
38584
+ }
38585
+ const blanketContext = {
38586
+ tier: { type: "String", required: false }
38587
+ };
38588
+ if (config.includeTimestamp !== false) {
38589
+ blanketContext["timestamp"] = { type: "String", required: false };
38590
+ }
38591
+ if (config.includeAgentId !== false) {
38592
+ blanketContext["agent_id"] = { type: "String", required: false };
38593
+ }
38594
+ actions["MCP::Tool::call"] = {
38595
+ appliesTo: {
38596
+ principalTypes: ["Agent"],
38597
+ resourceTypes: ["Tool"],
38598
+ context: { type: "Record", attributes: blanketContext }
38599
+ }
38600
+ };
38601
+ return {
38602
+ [namespace]: {
38603
+ entityTypes,
38604
+ actions
38605
+ }
38606
+ };
38607
+ }
38608
+ function jsonSchemaToSchemaJsonType(schema) {
38609
+ if (schema.enum) return "String";
38610
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
38611
+ switch (type) {
38612
+ case "string":
38613
+ return "String";
38614
+ case "integer":
38615
+ case "number":
38616
+ return "Long";
38617
+ case "boolean":
38618
+ return "EntityOrCommon";
38619
+ // Cedar JSON schema uses this for Bool
38620
+ case "array":
38621
+ return "Set";
38622
+ default:
38623
+ return "String";
38624
+ }
38625
+ }
38626
+ function generateSchemaStub(namespace = "ScopeBlind") {
38627
+ return [
38628
+ `// Cedar schema stub for protect-mcp`,
38629
+ `// This defines the principal and resource entity types.`,
38630
+ `// Tool-specific actions are auto-generated from MCP tools/list.`,
38631
+ `//`,
38632
+ `// Compatible with cedar-policy/cedar-for-agents @mcp_principal/@mcp_resource annotations.`,
38633
+ `// See: https://github.com/cedar-policy/cedar-for-agents`,
38634
+ ``,
38635
+ `namespace ${namespace} {`,
38636
+ ``,
38637
+ ` // @mcp_principal`,
38638
+ ` entity Agent = {`,
38639
+ ` "tier": String,`,
38640
+ ` "agent_id": String?`,
38641
+ ` };`,
38642
+ ``,
38643
+ ` // @mcp_resource`,
38644
+ ` entity Tool;`,
38645
+ ``,
38646
+ ` // @mcp_action`,
38647
+ ` action "MCP::Tool::call" appliesTo {`,
38648
+ ` principal: [Agent],`,
38649
+ ` resource: [Tool],`,
38650
+ ` context: {`,
38651
+ ` "tier": String`,
38652
+ ` }`,
38653
+ ` };`,
38654
+ ``,
38655
+ `}`,
38656
+ ``
38657
+ ].join("\n");
38658
+ }
38659
+
38384
38660
  // src/rekor-anchor.ts
38385
38661
  var import_node_crypto5 = require("crypto");
38386
38662
  var REKOR_API = "https://rekor.sigstore.dev/api/v1";
@@ -39807,18 +40083,21 @@ function createSandboxServer() {
39807
40083
  createSandboxServer,
39808
40084
  destroySandbox,
39809
40085
  ed25519ToDIDKey,
40086
+ evaluateCedar,
39810
40087
  evaluateTier,
39811
40088
  exportC2PAManifestJSON,
39812
40089
  exportJSONL,
39813
40090
  formatReportMarkdown,
39814
40091
  formatSimulation,
39815
40092
  generateC2PACommand,
40093
+ generateCedarSchema,
39816
40094
  generateDatasetCard,
39817
40095
  generateHFMetadata,
39818
40096
  generateHookSettings,
39819
40097
  generateReport,
39820
40098
  generateSafetyTranscript,
39821
40099
  generateSampleCedarPolicy,
40100
+ generateSchemaStub,
39822
40101
  generateVerifyReceiptSkill,
39823
40102
  getSignerInfo,
39824
40103
  getToolPolicy,
@@ -39826,11 +40105,13 @@ function createSandboxServer() {
39826
40105
  hashResponseBody,
39827
40106
  initSigning,
39828
40107
  isAgentId,
40108
+ isCedarAvailable,
39829
40109
  isDisclosureMode,
39830
40110
  isEvidenceType,
39831
40111
  isManifestStatus,
39832
40112
  isSigningEnabled,
39833
40113
  listCredentialLabels,
40114
+ loadCedarPolicies,
39834
40115
  loadPolicy,
39835
40116
  manifestToVC,
39836
40117
  meetsMinTier,