cedar-mcp-server 1.0.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.
Files changed (215) hide show
  1. package/.editorconfig +12 -0
  2. package/.github/workflows/ci.yml +31 -0
  3. package/.github/workflows/release.yml +42 -0
  4. package/.nvmrc +1 -0
  5. package/CHANGELOG.md +241 -0
  6. package/CONTRIBUTING.md +83 -0
  7. package/LICENSE +182 -0
  8. package/README.md +1635 -0
  9. package/SECURITY.md +37 -0
  10. package/dist/http-server.d.ts +61 -0
  11. package/dist/http-server.d.ts.map +1 -0
  12. package/dist/http-server.js +194 -0
  13. package/dist/http-server.js.map +1 -0
  14. package/dist/index.d.ts +32 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +270 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/parser/policy-ast.d.ts +49 -0
  19. package/dist/parser/policy-ast.d.ts.map +1 -0
  20. package/dist/parser/policy-ast.js +311 -0
  21. package/dist/parser/policy-ast.js.map +1 -0
  22. package/dist/prompts/index.d.ts +38 -0
  23. package/dist/prompts/index.d.ts.map +1 -0
  24. package/dist/prompts/index.js +172 -0
  25. package/dist/prompts/index.js.map +1 -0
  26. package/dist/resources/ref-resolver.d.ts +23 -0
  27. package/dist/resources/ref-resolver.d.ts.map +1 -0
  28. package/dist/resources/ref-resolver.js +128 -0
  29. package/dist/resources/ref-resolver.js.map +1 -0
  30. package/dist/resources/store-manager.d.ts +64 -0
  31. package/dist/resources/store-manager.d.ts.map +1 -0
  32. package/dist/resources/store-manager.js +221 -0
  33. package/dist/resources/store-manager.js.map +1 -0
  34. package/dist/server.d.ts +18 -0
  35. package/dist/server.d.ts.map +1 -0
  36. package/dist/server.js +539 -0
  37. package/dist/server.js.map +1 -0
  38. package/dist/tools/advise/avp-rules.d.ts +49 -0
  39. package/dist/tools/advise/avp-rules.d.ts.map +1 -0
  40. package/dist/tools/advise/avp-rules.js +59 -0
  41. package/dist/tools/advise/avp-rules.js.map +1 -0
  42. package/dist/tools/advise/cedar-patterns.d.ts +24 -0
  43. package/dist/tools/advise/cedar-patterns.d.ts.map +1 -0
  44. package/dist/tools/advise/cedar-patterns.js +57 -0
  45. package/dist/tools/advise/cedar-patterns.js.map +1 -0
  46. package/dist/tools/advise/context-builder.d.ts +28 -0
  47. package/dist/tools/advise/context-builder.d.ts.map +1 -0
  48. package/dist/tools/advise/context-builder.js +89 -0
  49. package/dist/tools/advise/context-builder.js.map +1 -0
  50. package/dist/tools/advise/gotchas.d.ts +15 -0
  51. package/dist/tools/advise/gotchas.d.ts.map +1 -0
  52. package/dist/tools/advise/gotchas.js +83 -0
  53. package/dist/tools/advise/gotchas.js.map +1 -0
  54. package/dist/tools/advise.d.ts +96 -0
  55. package/dist/tools/advise.d.ts.map +1 -0
  56. package/dist/tools/advise.js +258 -0
  57. package/dist/tools/advise.js.map +1 -0
  58. package/dist/tools/authorize-batch.d.ts +35 -0
  59. package/dist/tools/authorize-batch.d.ts.map +1 -0
  60. package/dist/tools/authorize-batch.js +262 -0
  61. package/dist/tools/authorize-batch.js.map +1 -0
  62. package/dist/tools/authorize.d.ts +115 -0
  63. package/dist/tools/authorize.d.ts.map +1 -0
  64. package/dist/tools/authorize.js +373 -0
  65. package/dist/tools/authorize.js.map +1 -0
  66. package/dist/tools/check-change.d.ts +19 -0
  67. package/dist/tools/check-change.d.ts.map +1 -0
  68. package/dist/tools/check-change.js +91 -0
  69. package/dist/tools/check-change.js.map +1 -0
  70. package/dist/tools/diff-schema.d.ts +103 -0
  71. package/dist/tools/diff-schema.d.ts.map +1 -0
  72. package/dist/tools/diff-schema.js +379 -0
  73. package/dist/tools/diff-schema.js.map +1 -0
  74. package/dist/tools/diff-stores.d.ts +45 -0
  75. package/dist/tools/diff-stores.d.ts.map +1 -0
  76. package/dist/tools/diff-stores.js +222 -0
  77. package/dist/tools/diff-stores.js.map +1 -0
  78. package/dist/tools/explain.d.ts +80 -0
  79. package/dist/tools/explain.d.ts.map +1 -0
  80. package/dist/tools/explain.js +187 -0
  81. package/dist/tools/explain.js.map +1 -0
  82. package/dist/tools/format.d.ts +11 -0
  83. package/dist/tools/format.d.ts.map +1 -0
  84. package/dist/tools/format.js +20 -0
  85. package/dist/tools/format.js.map +1 -0
  86. package/dist/tools/generate-sample.d.ts +28 -0
  87. package/dist/tools/generate-sample.d.ts.map +1 -0
  88. package/dist/tools/generate-sample.js +568 -0
  89. package/dist/tools/generate-sample.js.map +1 -0
  90. package/dist/tools/link-template.d.ts +17 -0
  91. package/dist/tools/link-template.d.ts.map +1 -0
  92. package/dist/tools/link-template.js +78 -0
  93. package/dist/tools/link-template.js.map +1 -0
  94. package/dist/tools/list-template-links.d.ts +16 -0
  95. package/dist/tools/list-template-links.d.ts.map +1 -0
  96. package/dist/tools/list-template-links.js +22 -0
  97. package/dist/tools/list-template-links.js.map +1 -0
  98. package/dist/tools/list-templates.d.ts +16 -0
  99. package/dist/tools/list-templates.d.ts.map +1 -0
  100. package/dist/tools/list-templates.js +36 -0
  101. package/dist/tools/list-templates.js.map +1 -0
  102. package/dist/tools/translate.d.ts +11 -0
  103. package/dist/tools/translate.d.ts.map +1 -0
  104. package/dist/tools/translate.js +53 -0
  105. package/dist/tools/translate.js.map +1 -0
  106. package/dist/tools/validate-entities.d.ts +19 -0
  107. package/dist/tools/validate-entities.d.ts.map +1 -0
  108. package/dist/tools/validate-entities.js +88 -0
  109. package/dist/tools/validate-entities.js.map +1 -0
  110. package/dist/tools/validate-schema.d.ts +22 -0
  111. package/dist/tools/validate-schema.d.ts.map +1 -0
  112. package/dist/tools/validate-schema.js +89 -0
  113. package/dist/tools/validate-schema.js.map +1 -0
  114. package/dist/tools/validate-template.d.ts +18 -0
  115. package/dist/tools/validate-template.d.ts.map +1 -0
  116. package/dist/tools/validate-template.js +59 -0
  117. package/dist/tools/validate-template.js.map +1 -0
  118. package/dist/tools/validate.d.ts +90 -0
  119. package/dist/tools/validate.d.ts.map +1 -0
  120. package/dist/tools/validate.js +351 -0
  121. package/dist/tools/validate.js.map +1 -0
  122. package/dist/utils/format-detector.d.ts +49 -0
  123. package/dist/utils/format-detector.d.ts.map +1 -0
  124. package/dist/utils/format-detector.js +298 -0
  125. package/dist/utils/format-detector.js.map +1 -0
  126. package/examples/README.md +36 -0
  127. package/examples/abac-multi-tenant/README.md +150 -0
  128. package/examples/abac-multi-tenant/entities/users-and-docs.json +33 -0
  129. package/examples/abac-multi-tenant/policies/member-read-internal.cedar +9 -0
  130. package/examples/abac-multi-tenant/policies/owner-full-access.cedar +9 -0
  131. package/examples/abac-multi-tenant/policies/premium-share-guard.cedar +9 -0
  132. package/examples/abac-multi-tenant/policies/private-doc-guard.cedar +13 -0
  133. package/examples/abac-multi-tenant/run.ts +92 -0
  134. package/examples/abac-multi-tenant/schema.json +60 -0
  135. package/examples/api-gateway-path-routing/README.md +154 -0
  136. package/examples/api-gateway-path-routing/entities/users-and-roles.json +20 -0
  137. package/examples/api-gateway-path-routing/policies/admin-full-access.cedar +6 -0
  138. package/examples/api-gateway-path-routing/policies/developer-projects.cedar +14 -0
  139. package/examples/api-gateway-path-routing/policies/viewer-readonly.cedar +10 -0
  140. package/examples/api-gateway-path-routing/run.ts +108 -0
  141. package/examples/api-gateway-path-routing/schema.json +54 -0
  142. package/examples/rbac-document-management/README.md +167 -0
  143. package/examples/rbac-document-management/entities/users-and-docs.json +43 -0
  144. package/examples/rbac-document-management/policies/admin.cedar +6 -0
  145. package/examples/rbac-document-management/policies/editor.cedar +6 -0
  146. package/examples/rbac-document-management/policies/top-secret-forbid.cedar +13 -0
  147. package/examples/rbac-document-management/policies/viewer.cedar +6 -0
  148. package/examples/rbac-document-management/run.ts +87 -0
  149. package/examples/rbac-document-management/schema.json +57 -0
  150. package/package.json +50 -0
  151. package/src/http-server.ts +239 -0
  152. package/src/index.ts +294 -0
  153. package/src/parser/policy-ast.ts +345 -0
  154. package/src/prompts/README.md +3 -0
  155. package/src/prompts/index.ts +217 -0
  156. package/src/resources/ref-resolver.ts +134 -0
  157. package/src/resources/store-manager.ts +248 -0
  158. package/src/server.ts +711 -0
  159. package/src/tools/advise/avp-rules.ts +70 -0
  160. package/src/tools/advise/cedar-patterns.ts +73 -0
  161. package/src/tools/advise/context-builder.ts +109 -0
  162. package/src/tools/advise/gotchas.ts +92 -0
  163. package/src/tools/advise.ts +366 -0
  164. package/src/tools/authorize-batch.ts +345 -0
  165. package/src/tools/authorize.ts +464 -0
  166. package/src/tools/check-change.ts +119 -0
  167. package/src/tools/diff-schema.ts +510 -0
  168. package/src/tools/diff-stores.ts +298 -0
  169. package/src/tools/explain.ts +278 -0
  170. package/src/tools/format.ts +33 -0
  171. package/src/tools/generate-sample.ts +665 -0
  172. package/src/tools/link-template.ts +109 -0
  173. package/src/tools/list-template-links.ts +41 -0
  174. package/src/tools/list-templates.ts +55 -0
  175. package/src/tools/translate.ts +66 -0
  176. package/src/tools/validate-entities.ts +125 -0
  177. package/src/tools/validate-schema.ts +128 -0
  178. package/src/tools/validate-template.ts +72 -0
  179. package/src/tools/validate.ts +459 -0
  180. package/src/utils/format-detector.ts +356 -0
  181. package/test/fixtures/docmgmt.ts +121 -0
  182. package/test/fixtures/multitenant.ts +163 -0
  183. package/test/index.test.ts +96 -0
  184. package/test/integration/e2e/behavior.test.ts +359 -0
  185. package/test/integration/e2e/edge-cases.test.ts +365 -0
  186. package/test/integration/e2e/failure-modes.test.ts +266 -0
  187. package/test/integration/e2e/protocol.test.ts +252 -0
  188. package/test/integration/http-smoke.test.ts +588 -0
  189. package/test/integration/smoke.test.ts +475 -0
  190. package/test/prompts/prompts.test.ts +173 -0
  191. package/test/property/properties.test.ts +234 -0
  192. package/test/resources/ref-resolver.test.ts +186 -0
  193. package/test/resources/store-manager.test.ts +344 -0
  194. package/test/setup.test.ts +7 -0
  195. package/test/tools/advise/avp-rules.test.ts +76 -0
  196. package/test/tools/advise.test.ts +339 -0
  197. package/test/tools/authorize-batch.test.ts +459 -0
  198. package/test/tools/authorize.test.ts +682 -0
  199. package/test/tools/check-change.test.ts +104 -0
  200. package/test/tools/cross-fixture.test.ts +170 -0
  201. package/test/tools/diff-schema.test.ts +355 -0
  202. package/test/tools/diff-stores.test.ts +291 -0
  203. package/test/tools/explain.test.ts +221 -0
  204. package/test/tools/format.test.ts +33 -0
  205. package/test/tools/generate-sample.test.ts +480 -0
  206. package/test/tools/link-template.test.ts +90 -0
  207. package/test/tools/list-templates.test.ts +151 -0
  208. package/test/tools/translate.test.ts +89 -0
  209. package/test/tools/validate-entities.test.ts +178 -0
  210. package/test/tools/validate-schema.test.ts +86 -0
  211. package/test/tools/validate-template.test.ts +89 -0
  212. package/test/tools/validate.test.ts +331 -0
  213. package/test/utils/format-detector.test.ts +518 -0
  214. package/tsconfig.json +17 -0
  215. package/vitest.config.ts +13 -0
@@ -0,0 +1,115 @@
1
+ import type { Policy, PolicyId } from "@cedar-policy/cedar-wasm/nodejs";
2
+ export interface AuthorizeInput {
3
+ /** Concatenated Cedar policy text. Mutually exclusive with policiesMap. */
4
+ policies?: string;
5
+ /**
6
+ * Map of policy id -> policy text. Each key becomes the WASM policy_id and
7
+ * surfaces in determining_policies (overridden by an `@id` annotation when
8
+ * present). Use this when the caller knows the source filename per policy.
9
+ */
10
+ policiesMap?: Record<string, string>;
11
+ principal: string | Record<string, unknown>;
12
+ action: string | Record<string, unknown>;
13
+ resource: string | Record<string, unknown>;
14
+ entities: string;
15
+ schema?: string;
16
+ context?: string;
17
+ /**
18
+ * Optional store name to disambiguate workspace auto-discovery (10d) at the
19
+ * MCP layer. handleAuthorize itself does not consult the StoreManager; the
20
+ * server.ts handler resolves this and supplies inputs before calling in.
21
+ */
22
+ store?: string;
23
+ }
24
+ export type AuthorizeDecisionReason = "permit_policy_fired" | "forbid_policy_fired" | "default_deny_no_permit_matched" | "evaluation_error";
25
+ export interface AuthorizeResult {
26
+ decision: "Allow" | "Deny";
27
+ determining_policies: string[];
28
+ errors: string[];
29
+ decision_reason?: AuthorizeDecisionReason;
30
+ format_detected?: string;
31
+ format_note?: string;
32
+ error?: string;
33
+ /**
34
+ * 10d workspace auto-discovery: populated by the server.ts MCP handler when
35
+ * one or more inputs were resolved from a loaded MCP root rather than from
36
+ * inline params. Each subfield names the store that satisfied the missing
37
+ * input. Surfaces so the caller can trace which store the decision used.
38
+ */
39
+ auto_discovered?: {
40
+ policies_from?: string;
41
+ schema_from?: string;
42
+ entities_from?: string;
43
+ };
44
+ }
45
+ /**
46
+ * Build a Record<policyId, Policy> from caller input.
47
+ *
48
+ * Resolution order for each policy's id:
49
+ * 1. The @id("name") annotation on the policy (highest priority)
50
+ * 2. The caller-provided basename (key in policiesMap)
51
+ * 3. positional "policy<index>" fallback
52
+ *
53
+ * For a flat policies string, we split it via policySetTextToParts so each
54
+ * policy gets its own id rather than collapsing into a single anonymous blob.
55
+ *
56
+ * Exported so cedar_authorize_batch can apply the same H1 resolution and
57
+ * surface the same stable IDs as the single-request handler (kickoff-14 14a).
58
+ */
59
+ export declare function buildStaticPolicies(input: Pick<AuthorizeInput, "policies" | "policiesMap">): {
60
+ record: Record<PolicyId, Policy>;
61
+ } | {
62
+ error: string;
63
+ };
64
+ export declare function handleAuthorize(input: AuthorizeInput): Promise<AuthorizeResult>;
65
+ /**
66
+ * Inputs accepted by the MCP-level authorize entry point. Wider than
67
+ * `AuthorizeInput` because it also accepts the `_ref` shapes the MCP layer
68
+ * resolves before reaching `handleAuthorize`. Kept distinct so the WASM-level
69
+ * handler does not need to know about MCP plumbing.
70
+ */
71
+ export interface AuthorizeMcpInput {
72
+ policies?: string;
73
+ policy_ref?: string;
74
+ policiesMap?: Record<string, string>;
75
+ principal: string | Record<string, unknown>;
76
+ action: string | Record<string, unknown>;
77
+ resource: string | Record<string, unknown>;
78
+ entities?: string;
79
+ entities_ref?: string;
80
+ schema?: string;
81
+ schema_ref?: string;
82
+ context?: string;
83
+ store?: string;
84
+ }
85
+ /**
86
+ * 10d workspace auto-discovery wrapper for `cedar_authorize`.
87
+ *
88
+ * Resolves missing policies / schema / entities from the loaded MCP roots,
89
+ * then delegates to `handleAuthorize`. A single store backs all three so a
90
+ * call never mixes policies from one workspace with entities from another.
91
+ *
92
+ * Multi-store deployments with no explicit `store` parameter surface an
93
+ * ambiguity error in the `{ error }` envelope. None-loaded falls through to
94
+ * the "policies / entities required" errors that the MCP layer already used.
95
+ *
96
+ * Returns either:
97
+ * - `{ result }` -- the AuthorizeResult, with `auto_discovered` set when any
98
+ * input was sourced from the workspace.
99
+ * - `{ error }` -- a string error suitable for the standard `{ error: ... }`
100
+ * MCP envelope.
101
+ *
102
+ * The server.ts handler wraps this and serializes the result back to MCP.
103
+ * Tests can call it directly after setting up the `storeManager` singleton
104
+ * with `loadFromRoots([...])`.
105
+ */
106
+ export declare function handleAuthorizeMcp(input: AuthorizeMcpInput, resolveRef: (uri: string) => {
107
+ content: string;
108
+ } | {
109
+ error: string;
110
+ }): Promise<{
111
+ result: AuthorizeResult;
112
+ } | {
113
+ error: string;
114
+ }>;
115
+ //# sourceMappingURL=authorize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/tools/authorize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,373 @@
1
+ import { isAuthorized, policySetTextToParts, policyToJson } from "@cedar-policy/cedar-wasm/nodejs";
2
+ import { detectFormat, normalizeEntities, normalizePrincipalRef, } from "../utils/format-detector.js";
3
+ import { storeManager } from "../resources/store-manager.js";
4
+ const DENY_RESULT = (error, detection) => ({
5
+ decision: "Deny",
6
+ determining_policies: [],
7
+ errors: [],
8
+ ...(detection ? { format_detected: detection.format, format_note: detection.note } : {}),
9
+ error,
10
+ });
11
+ /**
12
+ * Extract the @id annotation from a single Cedar policy text, if present.
13
+ * Returns undefined when the policy fails to parse OR when no @id is set.
14
+ */
15
+ function readIdAnnotation(policyText) {
16
+ const parsed = policyToJson(policyText);
17
+ if (parsed.type !== "success")
18
+ return undefined;
19
+ const id = parsed.json.annotations?.id;
20
+ return typeof id === "string" && id.length > 0 ? id : undefined;
21
+ }
22
+ /**
23
+ * Build a Record<policyId, Policy> from caller input.
24
+ *
25
+ * Resolution order for each policy's id:
26
+ * 1. The @id("name") annotation on the policy (highest priority)
27
+ * 2. The caller-provided basename (key in policiesMap)
28
+ * 3. positional "policy<index>" fallback
29
+ *
30
+ * For a flat policies string, we split it via policySetTextToParts so each
31
+ * policy gets its own id rather than collapsing into a single anonymous blob.
32
+ *
33
+ * Exported so cedar_authorize_batch can apply the same H1 resolution and
34
+ * surface the same stable IDs as the single-request handler (kickoff-14 14a).
35
+ */
36
+ export function buildStaticPolicies(input) {
37
+ const record = {};
38
+ const usedIds = new Set();
39
+ const assignId = (preferredId, fallbackBase) => {
40
+ let id = preferredId;
41
+ if (usedIds.has(id)) {
42
+ // Disambiguate duplicates so the WASM call does not collide.
43
+ let suffix = 2;
44
+ while (usedIds.has(`${fallbackBase}-${suffix}`))
45
+ suffix++;
46
+ id = `${fallbackBase}-${suffix}`;
47
+ }
48
+ usedIds.add(id);
49
+ return id;
50
+ };
51
+ if (input.policiesMap) {
52
+ for (const [basename, text] of Object.entries(input.policiesMap)) {
53
+ const annotation = readIdAnnotation(text);
54
+ const preferred = annotation ?? basename;
55
+ const id = assignId(preferred, basename);
56
+ record[id] = text;
57
+ }
58
+ return { record };
59
+ }
60
+ const text = input.policies ?? "";
61
+ const parts = policySetTextToParts(text);
62
+ if (parts.type === "failure") {
63
+ // Fall through with a single positional entry; downstream isAuthorized
64
+ // will surface the parse error in the standard errors[] channel.
65
+ record["policy0"] = text;
66
+ return { record };
67
+ }
68
+ parts.policies.forEach((policyText, idx) => {
69
+ const annotation = readIdAnnotation(policyText);
70
+ const fallback = `policy${idx}`;
71
+ const preferred = annotation ?? fallback;
72
+ const id = assignId(preferred, fallback);
73
+ record[id] = policyText;
74
+ });
75
+ return { record };
76
+ }
77
+ /**
78
+ * Classify the authorization outcome into one of four reason codes.
79
+ * See AuthorizeDecisionReason for the contract.
80
+ */
81
+ function classifyDecisionReason(decision, determining, errors, staticPolicies) {
82
+ if (errors.length > 0)
83
+ return "evaluation_error";
84
+ if (decision === "Allow")
85
+ return "permit_policy_fired";
86
+ // Deny path.
87
+ if (determining.length === 0)
88
+ return "default_deny_no_permit_matched";
89
+ // At least one determining policy fired on a Deny -> a forbid policy.
90
+ // Verify defensively by checking the policy's effect; if any determining
91
+ // entry parses as forbid, classify as forbid_policy_fired.
92
+ for (const id of determining) {
93
+ const text = staticPolicies[id];
94
+ if (typeof text !== "string")
95
+ continue;
96
+ const parsed = policyToJson(text);
97
+ if (parsed.type === "success" && parsed.json.effect === "forbid") {
98
+ return "forbid_policy_fired";
99
+ }
100
+ }
101
+ // Fallback: a determining policy exists on Deny but is not a parseable forbid.
102
+ return "forbid_policy_fired";
103
+ }
104
+ export async function handleAuthorize(input) {
105
+ // Parse entities first so we can run format detection.
106
+ // Also unwrap the AVP SDK entity_list/entityList envelope:
107
+ // Ruby SDK: { entity_list: [...] }
108
+ // Python/JS: { entityList: [...] }
109
+ // Official API: { entityList: [...] }
110
+ // Users sometimes copy the full SDK entities parameter value rather than just the array.
111
+ let rawEntities;
112
+ try {
113
+ const parsed = JSON.parse(input.entities);
114
+ if (Array.isArray(parsed)) {
115
+ rawEntities = parsed;
116
+ }
117
+ else if (typeof parsed === "object" && parsed !== null) {
118
+ const obj = parsed;
119
+ const list = obj["entity_list"] ?? obj["entityList"] ?? obj["EntityList"];
120
+ if (Array.isArray(list)) {
121
+ rawEntities = list;
122
+ }
123
+ else {
124
+ throw new Error("not an array");
125
+ }
126
+ }
127
+ else {
128
+ throw new Error("not an array");
129
+ }
130
+ }
131
+ catch {
132
+ return DENY_RESULT("entities must be a valid JSON array or an AVP entity_list object");
133
+ }
134
+ // Detect format across all inputs together
135
+ const detection = detectFormat(rawEntities, input.principal, input.action, input.resource);
136
+ // Normalize entities and principal/action/resource to WASM format
137
+ const normalizedEntities = normalizeEntities(rawEntities, detection.format);
138
+ const principalRef = normalizePrincipalRef(input.principal);
139
+ if ("error" in principalRef)
140
+ return DENY_RESULT(principalRef.error, detection);
141
+ const actionRef = normalizePrincipalRef(input.action);
142
+ if ("error" in actionRef)
143
+ return DENY_RESULT(actionRef.error, detection);
144
+ const resourceRef = normalizePrincipalRef(input.resource);
145
+ if ("error" in resourceRef)
146
+ return DENY_RESULT(resourceRef.error, detection);
147
+ if (!input.policies && !input.policiesMap) {
148
+ return DENY_RESULT("policies or policiesMap is required", detection);
149
+ }
150
+ const built = buildStaticPolicies(input);
151
+ if ("error" in built)
152
+ return DENY_RESULT(built.error, detection);
153
+ const staticPolicies = built.record;
154
+ let schema;
155
+ if (input.schema) {
156
+ try {
157
+ schema = JSON.parse(input.schema);
158
+ }
159
+ catch {
160
+ schema = input.schema;
161
+ }
162
+ }
163
+ let context = {};
164
+ if (input.context) {
165
+ try {
166
+ context = JSON.parse(input.context);
167
+ }
168
+ catch {
169
+ return DENY_RESULT("context must be a valid JSON object", detection);
170
+ }
171
+ }
172
+ const call = {
173
+ principal: principalRef,
174
+ action: actionRef,
175
+ resource: resourceRef,
176
+ context,
177
+ policies: { staticPolicies },
178
+ entities: normalizedEntities,
179
+ ...(schema ? { schema, validateRequest: true } : {}),
180
+ };
181
+ // per spike-report-wasm-api.md §1: type field is "success"|"failure" for WASM health,
182
+ // decision is "allow"|"deny" for the authorization result
183
+ const answer = isAuthorized(call);
184
+ if (answer.type === "failure") {
185
+ const errorMessages = answer.errors.map((e) => e.message);
186
+ return {
187
+ decision: "Deny",
188
+ determining_policies: [],
189
+ errors: errorMessages,
190
+ decision_reason: "evaluation_error",
191
+ format_detected: detection.format,
192
+ format_note: detection.note,
193
+ };
194
+ }
195
+ const { decision, diagnostics } = answer.response;
196
+ const normalizedDecision = decision === "allow" ? "Allow" : "Deny";
197
+ const determining = diagnostics.reason;
198
+ const errorMessages = diagnostics.errors.map((e) => e.error.message);
199
+ return {
200
+ decision: normalizedDecision,
201
+ determining_policies: determining,
202
+ errors: errorMessages,
203
+ decision_reason: classifyDecisionReason(normalizedDecision, determining, errorMessages, staticPolicies),
204
+ format_detected: detection.format,
205
+ format_note: detection.note,
206
+ };
207
+ }
208
+ /**
209
+ * 10d workspace auto-discovery wrapper for `cedar_authorize`.
210
+ *
211
+ * Resolves missing policies / schema / entities from the loaded MCP roots,
212
+ * then delegates to `handleAuthorize`. A single store backs all three so a
213
+ * call never mixes policies from one workspace with entities from another.
214
+ *
215
+ * Multi-store deployments with no explicit `store` parameter surface an
216
+ * ambiguity error in the `{ error }` envelope. None-loaded falls through to
217
+ * the "policies / entities required" errors that the MCP layer already used.
218
+ *
219
+ * Returns either:
220
+ * - `{ result }` -- the AuthorizeResult, with `auto_discovered` set when any
221
+ * input was sourced from the workspace.
222
+ * - `{ error }` -- a string error suitable for the standard `{ error: ... }`
223
+ * MCP envelope.
224
+ *
225
+ * The server.ts handler wraps this and serializes the result back to MCP.
226
+ * Tests can call it directly after setting up the `storeManager` singleton
227
+ * with `loadFromRoots([...])`.
228
+ */
229
+ export async function handleAuthorizeMcp(input, resolveRef) {
230
+ const needsAuto = (!input.policies && !input.policy_ref && !input.policiesMap) ||
231
+ (!input.schema && !input.schema_ref) ||
232
+ (!input.entities && !input.entities_ref);
233
+ let autoStore;
234
+ if (needsAuto) {
235
+ if (input.store) {
236
+ if (!storeManager.getStore(input.store)) {
237
+ const available = storeManager.listStoreNames().join(", ") || "none";
238
+ return { error: `Store not found: "${input.store}". Available stores: ${available}.` };
239
+ }
240
+ autoStore = input.store;
241
+ }
242
+ else {
243
+ const def = storeManager.getDefaultStore();
244
+ if (def.kind === "single")
245
+ autoStore = def.store.name;
246
+ else if (def.kind === "ambiguous") {
247
+ return { error: `Multiple stores are loaded (${def.names.join(", ")}). Pass store: "<name>" to choose.` };
248
+ }
249
+ // def.kind === "none": leave autoStore undefined and let the
250
+ // "Either X or X_ref is required" branches below fire.
251
+ }
252
+ }
253
+ // Resolve policy_ref / policies. The cedar://policies/{store} loop pattern
254
+ // keeps each policy's basename as its determining-policies id rather than
255
+ // collapsing the set into a single blob.
256
+ let policies = input.policies;
257
+ let policiesMap = input.policiesMap;
258
+ let policiesFrom;
259
+ if (!policies && !policiesMap && input.policy_ref) {
260
+ const storeMatch = input.policy_ref.match(/^cedar:\/\/policies\/([^/]+)$/);
261
+ const singleMatch = input.policy_ref.match(/^cedar:\/\/policies\/([^/]+)\/([^/]+)$/);
262
+ if (storeMatch) {
263
+ const storeName = storeMatch[1];
264
+ try {
265
+ const ids = storeManager.listPolicies(storeName);
266
+ policiesMap = {};
267
+ for (const id of ids)
268
+ policiesMap[id] = storeManager.readPolicy(storeName, id);
269
+ }
270
+ catch (e) {
271
+ return { error: e instanceof Error ? e.message : String(e) };
272
+ }
273
+ }
274
+ else if (singleMatch) {
275
+ const storeName = singleMatch[1];
276
+ const policyId = singleMatch[2];
277
+ try {
278
+ policiesMap = { [policyId]: storeManager.readPolicy(storeName, policyId) };
279
+ }
280
+ catch (e) {
281
+ return { error: e instanceof Error ? e.message : String(e) };
282
+ }
283
+ }
284
+ else {
285
+ const resolved = resolveRef(input.policy_ref);
286
+ if ("error" in resolved)
287
+ return { error: resolved.error };
288
+ policies = resolved.content;
289
+ }
290
+ }
291
+ if (!policies && !policiesMap && autoStore) {
292
+ try {
293
+ const ids = storeManager.listPolicies(autoStore);
294
+ policiesMap = {};
295
+ for (const id of ids)
296
+ policiesMap[id] = storeManager.readPolicy(autoStore, id);
297
+ policiesFrom = autoStore;
298
+ }
299
+ catch (e) {
300
+ return { error: e instanceof Error ? e.message : String(e) };
301
+ }
302
+ }
303
+ if (!policies && !policiesMap)
304
+ return { error: "Either policies or policy_ref is required" };
305
+ let schema = input.schema;
306
+ let schemaFrom;
307
+ if (!schema && input.schema_ref) {
308
+ const resolved = resolveRef(input.schema_ref);
309
+ if ("error" in resolved)
310
+ return { error: resolved.error };
311
+ schema = resolved.content;
312
+ }
313
+ if (!schema && autoStore) {
314
+ try {
315
+ schema = storeManager.readSchema(autoStore);
316
+ schemaFrom = autoStore;
317
+ }
318
+ catch {
319
+ // Store has no schema file; schema stays undefined (it is optional).
320
+ }
321
+ }
322
+ let entities = input.entities;
323
+ let entitiesFrom;
324
+ if (!entities && input.entities_ref) {
325
+ const resolved = resolveRef(input.entities_ref);
326
+ if ("error" in resolved)
327
+ return { error: resolved.error };
328
+ entities = resolved.content;
329
+ }
330
+ if (!entities && autoStore) {
331
+ // Only claim entities_from if the store actually has an entities/
332
+ // subdirectory with files. readAllEntities returns "[]" when the
333
+ // directory is missing, which would otherwise have us lie in
334
+ // auto_discovered.entities_from about the source of zero entities.
335
+ try {
336
+ const entityFiles = storeManager.listEntities(autoStore);
337
+ if (entityFiles.length > 0) {
338
+ entities = storeManager.readAllEntities(autoStore);
339
+ entitiesFrom = autoStore;
340
+ }
341
+ else {
342
+ entities = "[]";
343
+ }
344
+ }
345
+ catch (e) {
346
+ return { error: e instanceof Error ? e.message : String(e) };
347
+ }
348
+ }
349
+ if (!entities)
350
+ return { error: "Either entities or entities_ref is required" };
351
+ const result = await handleAuthorize({
352
+ policies,
353
+ policiesMap,
354
+ principal: input.principal,
355
+ action: input.action,
356
+ resource: input.resource,
357
+ entities,
358
+ schema,
359
+ context: input.context,
360
+ });
361
+ const autoDiscovered = {};
362
+ if (policiesFrom)
363
+ autoDiscovered.policies_from = policiesFrom;
364
+ if (schemaFrom)
365
+ autoDiscovered.schema_from = schemaFrom;
366
+ if (entitiesFrom)
367
+ autoDiscovered.entities_from = entitiesFrom;
368
+ if (Object.keys(autoDiscovered).length > 0) {
369
+ result.auto_discovered = autoDiscovered;
370
+ }
371
+ return { result };
372
+ }
373
+ //# sourceMappingURL=authorize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/tools/authorize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface CheckChangeInput {
2
+ old_policy: string;
3
+ new_policy: string;
4
+ }
5
+ export interface PolicyChange {
6
+ field: "effect" | "principal" | "resource" | "action" | "conditions";
7
+ old_value?: string;
8
+ new_value?: string;
9
+ in_place_allowed: boolean;
10
+ reason: string;
11
+ }
12
+ export interface CheckChangeResult {
13
+ can_update_in_place: boolean;
14
+ changes: PolicyChange[];
15
+ recommendation: string;
16
+ error?: string;
17
+ }
18
+ export declare function handleCheckChange(input: CheckChangeInput): Promise<CheckChangeResult>;
19
+ //# sourceMappingURL=check-change.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-change.d.ts","sourceRoot":"","sources":["../../src/tools/check-change.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,CAAC;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2CD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAsD3F"}
@@ -0,0 +1,91 @@
1
+ import { policyToJson } from "@cedar-policy/cedar-wasm/nodejs";
2
+ const IN_PLACE_RULES = {
3
+ effect: {
4
+ allowed: false,
5
+ reason: "Changing effect (permit ↔ forbid) requires deleting and recreating the policy.",
6
+ },
7
+ principal: {
8
+ allowed: false,
9
+ reason: "Changing the principal clause requires deleting and recreating the policy.",
10
+ },
11
+ resource: {
12
+ allowed: false,
13
+ reason: "Changing the resource clause requires deleting and recreating the policy.",
14
+ },
15
+ action: {
16
+ allowed: true,
17
+ reason: "Action clause changes can be applied in-place.",
18
+ },
19
+ conditions: {
20
+ allowed: true,
21
+ reason: "Condition clause (when/unless) changes can be applied in-place.",
22
+ },
23
+ };
24
+ function parsePolicy(text) {
25
+ const result = policyToJson(text);
26
+ if (result.type === "failure") {
27
+ throw new Error(result.errors.map((e) => e.message).join("; "));
28
+ }
29
+ return result.json;
30
+ }
31
+ function stringify(v) {
32
+ return JSON.stringify(v);
33
+ }
34
+ const EMPTY_RESULT = {
35
+ can_update_in_place: false,
36
+ changes: [],
37
+ recommendation: "",
38
+ };
39
+ export async function handleCheckChange(input) {
40
+ let oldJson;
41
+ let newJson;
42
+ try {
43
+ oldJson = parsePolicy(input.old_policy);
44
+ }
45
+ catch (e) {
46
+ return { ...EMPTY_RESULT, error: `Failed to parse old_policy: ${e instanceof Error ? e.message : String(e)}` };
47
+ }
48
+ try {
49
+ newJson = parsePolicy(input.new_policy);
50
+ }
51
+ catch (e) {
52
+ return { ...EMPTY_RESULT, error: `Failed to parse new_policy: ${e instanceof Error ? e.message : String(e)}` };
53
+ }
54
+ const changes = [];
55
+ // Compare each field. Effect is a string; others are structured objects.
56
+ const fields = [
57
+ "effect",
58
+ "principal",
59
+ "resource",
60
+ "action",
61
+ "conditions",
62
+ ];
63
+ for (const field of fields) {
64
+ const oldVal = field === "effect" ? oldJson.effect : oldJson[field];
65
+ const newVal = field === "effect" ? newJson.effect : newJson[field];
66
+ if (stringify(oldVal) !== stringify(newVal)) {
67
+ const rule = IN_PLACE_RULES[field];
68
+ changes.push({
69
+ field: field,
70
+ old_value: stringify(oldVal),
71
+ new_value: stringify(newVal),
72
+ in_place_allowed: rule.allowed,
73
+ reason: rule.reason,
74
+ });
75
+ }
76
+ }
77
+ const can_update_in_place = changes.every((c) => c.in_place_allowed);
78
+ let recommendation;
79
+ if (changes.length === 0) {
80
+ recommendation = "No changes detected.";
81
+ }
82
+ else if (can_update_in_place) {
83
+ recommendation = "All changes can be applied as an in-place policy update.";
84
+ }
85
+ else {
86
+ const blocking = changes.filter((c) => !c.in_place_allowed).map((c) => c.field);
87
+ recommendation = `Delete the existing policy and create a new one. The following fields cannot be changed in-place: ${blocking.join(", ")}.`;
88
+ }
89
+ return { can_update_in_place, changes, recommendation };
90
+ }
91
+ //# sourceMappingURL=check-change.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-change.js","sourceRoot":"","sources":["../../src/tools/check-change.ts"],"names":[],"mappings":"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"}