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,90 @@
1
+ export interface ValidateInput {
2
+ policies: string;
3
+ /** Optional. When omitted, validate runs in syntax-only mode (parse-only, no schema typing). */
4
+ schema?: string;
5
+ /**
6
+ * Optional store name to disambiguate workspace auto-discovery (10d) when
7
+ * multiple stores are loaded. The server.ts handler resolves this against
8
+ * the StoreManager and supplies `schema` before calling handleValidate; the
9
+ * field is carried through so handleValidate can surface ambiguity errors
10
+ * when callers invoke it directly without going through the MCP layer.
11
+ */
12
+ store?: string;
13
+ /**
14
+ * 11c opt-in: explicitly select the validation mode rather than letting
15
+ * schema presence decide it.
16
+ *
17
+ * "auto" (default): schema presence picks the mode. With a schema (inline
18
+ * or auto-discovered from a single loaded store), run syntax_and_schema.
19
+ * Without one, run syntax_only.
20
+ * "syntax_only": always parser-only. Skip workspace auto-discovery and
21
+ * ignore any inline schema. Useful when the user explicitly says "I have
22
+ * no schema" or wants a fast syntax sanity check.
23
+ * "syntax_and_schema": require a schema. If neither an inline schema nor
24
+ * one resolvable from a loaded store is available, return a clear error
25
+ * rather than silently dropping to syntax_only.
26
+ */
27
+ validation_mode?: "auto" | "syntax_only" | "syntax_and_schema";
28
+ }
29
+ export interface ValidateError {
30
+ policy_id: string;
31
+ message: string;
32
+ hint: string | null;
33
+ /** 1-indexed line of the source location, when the WASM error reports one. */
34
+ line?: number;
35
+ /** 1-indexed column of the source location, when the WASM error reports one. */
36
+ column?: number;
37
+ }
38
+ export interface ValidateResult {
39
+ valid: boolean;
40
+ errors: ValidateError[];
41
+ warnings: ValidateError[];
42
+ policy_count: number;
43
+ /**
44
+ * Discriminator that tells the caller what was actually checked.
45
+ * "syntax_only": parser-only run, no schema supplied. Catches parse errors
46
+ * (typos, malformed scopes, bad operators) but not attribute typing or
47
+ * action applicability.
48
+ * "syntax_and_schema": full parse + type-check against a Cedar schema.
49
+ */
50
+ validation_mode: "syntax_only" | "syntax_and_schema";
51
+ /**
52
+ * 10d workspace auto-discovery: populated when an input was sourced from a
53
+ * loaded MCP root rather than supplied inline. Surfaces to the caller which
54
+ * store ended up satisfying the missing field so the action is traceable.
55
+ */
56
+ auto_discovered?: {
57
+ schema_from?: string;
58
+ };
59
+ }
60
+ export declare function handleValidate(input: ValidateInput): Promise<ValidateResult>;
61
+ /**
62
+ * Inputs accepted by the MCP-level validate entry point. Wider than
63
+ * `ValidateInput` because it also accepts the `_ref` shapes the MCP layer
64
+ * resolves before reaching `handleValidate`.
65
+ */
66
+ export interface ValidateMcpInput {
67
+ policies?: string;
68
+ policy_ref?: string;
69
+ schema?: string;
70
+ schema_ref?: string;
71
+ store?: string;
72
+ validation_mode?: "auto" | "syntax_only" | "syntax_and_schema";
73
+ }
74
+ /**
75
+ * 10d workspace auto-discovery wrapper for `cedar_validate`. Resolves the
76
+ * schema from a loaded MCP root when neither `schema` nor `schema_ref` was
77
+ * supplied. Single-store deployments upgrade to syntax_and_schema mode;
78
+ * multi-store deployments require an explicit `store` parameter and return
79
+ * an ambiguity error otherwise.
80
+ */
81
+ export declare function handleValidateMcp(input: ValidateMcpInput, resolveRef: (uri: string) => {
82
+ content: string;
83
+ } | {
84
+ error: string;
85
+ }): Promise<{
86
+ result: ValidateResult;
87
+ } | {
88
+ error: string;
89
+ }>;
90
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,mBAAmB,CAAC;CAChE;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,eAAe,EAAE,aAAa,GAAG,mBAAmB,CAAC;IACrD;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAoMD,wBAAsB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CA+HlF;AAID;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,mBAAmB,CAAC;CAChE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACnE,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA2CzD"}
@@ -0,0 +1,351 @@
1
+ import { validate, checkParsePolicySet, policySetTextToParts } from "@cedar-policy/cedar-wasm/nodejs";
2
+ import { storeManager } from "../resources/store-manager.js";
3
+ /**
4
+ * Common Cedar typo → suggestion table. Used to populate the `hint` field on
5
+ * parse errors of the form "unexpected token `X`" when X is a known misspelling
6
+ * of a Cedar keyword. Keep small and conservative; better to leave hint null
7
+ * than to over-suggest. Levenshtein over the reserved keyword set is the
8
+ * future generalization if this table proves too narrow.
9
+ */
10
+ const TYPO_HINTS = {
11
+ int: "in",
12
+ permint: "permit",
13
+ forbit: "forbid",
14
+ prinipal: "principal",
15
+ prinicpal: "principal",
16
+ prncipal: "principal",
17
+ resorce: "resource",
18
+ resoure: "resource",
19
+ actoin: "action",
20
+ acton: "action",
21
+ unles: "unless",
22
+ wen: "when",
23
+ Like: "like",
24
+ Has: "has",
25
+ Permit: "permit",
26
+ Forbid: "forbid",
27
+ When: "when",
28
+ Unless: "unless",
29
+ };
30
+ function parseSchema(schemaStr) {
31
+ try {
32
+ return JSON.parse(schemaStr);
33
+ }
34
+ catch {
35
+ // Not JSON — treat as Cedar schema text
36
+ return schemaStr;
37
+ }
38
+ }
39
+ function countPolicies(policiesText) {
40
+ const parts = policySetTextToParts(policiesText);
41
+ if (parts.type === "failure")
42
+ return 0;
43
+ return parts.policies.length + parts.policy_templates.length;
44
+ }
45
+ /**
46
+ * Convert a WASM-reported UTF-8 byte offset into the source text into a
47
+ * 1-indexed line + Unicode-code-point column. Walking the JS string as if
48
+ * the offset were a char index drifts whenever the source contains
49
+ * multi-byte UTF-8 chars (em-dashes in comments, non-ASCII identifiers
50
+ * in string literals). This matters in practice for any Cedar policy
51
+ * with non-ASCII content, including comments, before the error site.
52
+ *
53
+ * Implementation: encode the full source to bytes, slice up to the
54
+ * byte offset, decode back to a string, then count Unicode code points
55
+ * (via for-of, which iterates code points rather than UTF-16 code units).
56
+ */
57
+ function offsetToLineCol(source, byteOffset) {
58
+ const enc = new TextEncoder();
59
+ const bytes = enc.encode(source);
60
+ if (byteOffset < 0 || byteOffset > bytes.length) {
61
+ return { line: 1, column: 1 };
62
+ }
63
+ const before = new TextDecoder().decode(bytes.slice(0, byteOffset));
64
+ let line = 1;
65
+ let column = 1;
66
+ for (const ch of before) {
67
+ if (ch === "\n") {
68
+ line++;
69
+ column = 1;
70
+ }
71
+ else {
72
+ column++;
73
+ }
74
+ }
75
+ return { line, column };
76
+ }
77
+ /**
78
+ * Pull the offending token out of a Cedar parse error message, if present.
79
+ * Cedar emits a few distinct error templates depending on where the token
80
+ * appears in the grammar; this matches the ones common typos produce.
81
+ */
82
+ function extractOffendingToken(message) {
83
+ const patterns = [
84
+ /unexpected token `([^`]+)`/, // operator / keyword in expressions
85
+ /invalid variable in the policy scope: (\S+)/, // mis-typed principal / action / resource
86
+ /invalid policy effect: (\S+)/, // mis-typed permit / forbid
87
+ ];
88
+ for (const re of patterns) {
89
+ const m = message.match(re);
90
+ if (m)
91
+ return m[1];
92
+ }
93
+ return null;
94
+ }
95
+ /** Suggest a hint string for a known typo, or null if none applies. */
96
+ function typoHint(message) {
97
+ const token = extractOffendingToken(message);
98
+ if (!token)
99
+ return null;
100
+ const suggestion = TYPO_HINTS[token];
101
+ return suggestion ? `Did you mean '${suggestion}'?` : null;
102
+ }
103
+ /** Best-effort source location: prefer error's own sourceLocations[0]; null if none. */
104
+ function locationFor(err, source) {
105
+ const loc = err.sourceLocations?.[0];
106
+ if (!loc || typeof loc.start !== "number")
107
+ return null;
108
+ return offsetToLineCol(source, loc.start);
109
+ }
110
+ /**
111
+ * Resolve a Cedar schema for cedar_validate from, in order:
112
+ * 1. an inline `schema` string (highest priority; `from` is left undefined),
113
+ * 2. an explicit `store` name (read `schema.cedarschema` / `schema.json` from that loaded store; errors if read fails),
114
+ * 3. the workspace default when exactly one store is loaded (10d auto-discovery; falls to `none` if the store has no schema file),
115
+ * 4. `none` when no store is loaded at all,
116
+ * 5. `error` when multiple stores are loaded and no `store` was passed to disambiguate.
117
+ *
118
+ * Single source of truth for the resolution rules; called from both
119
+ * handleValidate (direct callers, including tests) and handleValidateMcp
120
+ * (after `schema_ref` resolution). Replaces two near-duplicate inline
121
+ * blocks from kickoff-10 (10d) that the kickoff-10 audit flagged for
122
+ * v1.1 cleanup.
123
+ */
124
+ function resolveWorkspaceSchema(inputSchema, storeParam) {
125
+ if (inputSchema !== undefined)
126
+ return { kind: "resolved", schema: inputSchema };
127
+ if (storeParam) {
128
+ try {
129
+ return { kind: "resolved", schema: storeManager.readSchema(storeParam), from: storeParam };
130
+ }
131
+ catch (e) {
132
+ return { kind: "error", error: e instanceof Error ? e.message : String(e) };
133
+ }
134
+ }
135
+ const def = storeManager.getDefaultStore();
136
+ if (def.kind === "single") {
137
+ try {
138
+ return { kind: "resolved", schema: storeManager.readSchema(def.store.name), from: def.store.name };
139
+ }
140
+ catch {
141
+ // Store exists but has no schema file; caller falls through to syntax_only
142
+ // (or errors out in syntax_and_schema mode at the next gate).
143
+ return { kind: "none" };
144
+ }
145
+ }
146
+ if (def.kind === "ambiguous") {
147
+ return { kind: "error", error: `Multiple stores are loaded (${def.names.join(", ")}). Pass store: "<name>" to choose.` };
148
+ }
149
+ return { kind: "none" };
150
+ }
151
+ /** Parser-only validation. Used by mode="syntax_only" and by mode="auto" when no schema is resolvable. */
152
+ function parseOnlyResult(policies) {
153
+ const parseAnswer = checkParsePolicySet({ staticPolicies: policies });
154
+ if (parseAnswer.type === "failure") {
155
+ return {
156
+ valid: false,
157
+ errors: parseAnswer.errors.map((e) => {
158
+ const loc = locationFor(e, policies);
159
+ const hint = typoHint(e.message) ?? e.help ?? null;
160
+ const base = {
161
+ policy_id: "",
162
+ message: e.message,
163
+ hint,
164
+ };
165
+ if (loc) {
166
+ base.line = loc.line;
167
+ base.column = loc.column;
168
+ }
169
+ return base;
170
+ }),
171
+ warnings: [],
172
+ policy_count: countPolicies(policies),
173
+ validation_mode: "syntax_only",
174
+ };
175
+ }
176
+ return {
177
+ valid: true,
178
+ errors: [],
179
+ warnings: [],
180
+ policy_count: countPolicies(policies),
181
+ validation_mode: "syntax_only",
182
+ };
183
+ }
184
+ export async function handleValidate(input) {
185
+ const mode = input.validation_mode ?? "auto";
186
+ // 11c: explicit syntax_only short-circuits every schema path. The caller
187
+ // said "I have no schema" or "I want a parse-only check"; we honor that
188
+ // even when an inline schema is present and even when a workspace store
189
+ // is loaded.
190
+ if (mode === "syntax_only") {
191
+ return parseOnlyResult(input.policies);
192
+ }
193
+ // 10d workspace auto-discovery, single-sourced through resolveWorkspaceSchema.
194
+ // Returns inline schema verbatim, reads from `store` if named, or auto-discovers
195
+ // from the default workspace store. Errors out on read failure or multi-store
196
+ // ambiguity. mode="syntax_and_schema" turns "no schema available" into a hard
197
+ // error in the next gate.
198
+ const resolution = resolveWorkspaceSchema(input.schema, input.store);
199
+ if (resolution.kind === "error") {
200
+ return {
201
+ valid: false,
202
+ errors: [{ policy_id: "", message: resolution.error, hint: null }],
203
+ warnings: [],
204
+ policy_count: countPolicies(input.policies),
205
+ validation_mode: mode === "syntax_and_schema" ? "syntax_and_schema" : "syntax_only",
206
+ };
207
+ }
208
+ const schemaText = resolution.kind === "resolved" ? resolution.schema : undefined;
209
+ const schemaFrom = resolution.kind === "resolved" ? resolution.from : undefined;
210
+ // 11c: explicit syntax_and_schema requires a schema. After both inline and
211
+ // auto-discovery paths, if there is still no schema, the caller asked for a
212
+ // mode we cannot honor. Return a clear error rather than silently dropping
213
+ // to syntax_only (which is exactly the Round 4 Scenario I friction).
214
+ if (mode === "syntax_and_schema" && schemaText === undefined) {
215
+ return {
216
+ valid: false,
217
+ errors: [{
218
+ policy_id: "",
219
+ message: 'validation_mode "syntax_and_schema" requires a schema, but none was provided and none could be auto-discovered. Pass schema, schema_ref, or store, or use validation_mode "auto" / "syntax_only".',
220
+ hint: null,
221
+ }],
222
+ warnings: [],
223
+ policy_count: countPolicies(input.policies),
224
+ validation_mode: "syntax_and_schema",
225
+ };
226
+ }
227
+ // Syntax-only mode: no schema supplied (mode === "auto" with no resolvable
228
+ // schema). Run the parser alone so the caller can sanity-check a snippet
229
+ // without having to construct a schema first. Maps any parse failure to
230
+ // the same ValidateError shape the full-validate path uses, so downstream
231
+ // consumers do not need a separate branch.
232
+ if (schemaText === undefined) {
233
+ return parseOnlyResult(input.policies);
234
+ }
235
+ const schema = parseSchema(schemaText);
236
+ // per spike-report-wasm-api.md §2: type field is WASM call health, not policy validity.
237
+ // Check validationErrors.length for actual validity.
238
+ const answer = validate({
239
+ schema,
240
+ policies: { staticPolicies: input.policies },
241
+ });
242
+ const autoDiscovered = schemaFrom ? { schema_from: schemaFrom } : undefined;
243
+ if (answer.type === "failure") {
244
+ return {
245
+ valid: false,
246
+ errors: answer.errors.map((e) => {
247
+ const loc = locationFor(e, input.policies);
248
+ const hint = typoHint(e.message) ?? e.help ?? null;
249
+ const base = {
250
+ policy_id: "",
251
+ message: e.message,
252
+ hint,
253
+ };
254
+ if (loc) {
255
+ base.line = loc.line;
256
+ base.column = loc.column;
257
+ }
258
+ return base;
259
+ }),
260
+ warnings: [],
261
+ policy_count: countPolicies(input.policies),
262
+ validation_mode: "syntax_and_schema",
263
+ ...(autoDiscovered ? { auto_discovered: autoDiscovered } : {}),
264
+ };
265
+ }
266
+ const errors = answer.validationErrors.map((e) => {
267
+ const loc = locationFor(e.error, input.policies);
268
+ const base = {
269
+ policy_id: e.policyId,
270
+ message: e.error.message,
271
+ hint: typoHint(e.error.message) ?? e.error.help ?? null,
272
+ };
273
+ if (loc) {
274
+ base.line = loc.line;
275
+ base.column = loc.column;
276
+ }
277
+ return base;
278
+ });
279
+ const warnings = answer.validationWarnings.map((e) => {
280
+ const loc = locationFor(e.error, input.policies);
281
+ const base = {
282
+ policy_id: e.policyId,
283
+ message: e.error.message,
284
+ hint: typoHint(e.error.message) ?? e.error.help ?? null,
285
+ };
286
+ if (loc) {
287
+ base.line = loc.line;
288
+ base.column = loc.column;
289
+ }
290
+ return base;
291
+ });
292
+ return {
293
+ valid: errors.length === 0,
294
+ errors,
295
+ warnings,
296
+ policy_count: countPolicies(input.policies),
297
+ validation_mode: "syntax_and_schema",
298
+ ...(autoDiscovered ? { auto_discovered: autoDiscovered } : {}),
299
+ };
300
+ }
301
+ /**
302
+ * 10d workspace auto-discovery wrapper for `cedar_validate`. Resolves the
303
+ * schema from a loaded MCP root when neither `schema` nor `schema_ref` was
304
+ * supplied. Single-store deployments upgrade to syntax_and_schema mode;
305
+ * multi-store deployments require an explicit `store` parameter and return
306
+ * an ambiguity error otherwise.
307
+ */
308
+ export async function handleValidateMcp(input, resolveRef) {
309
+ let policies = input.policies;
310
+ if (!policies && input.policy_ref) {
311
+ const resolved = resolveRef(input.policy_ref);
312
+ if ("error" in resolved)
313
+ return { error: resolved.error };
314
+ policies = resolved.content;
315
+ }
316
+ if (!policies)
317
+ return { error: "Either policies or policy_ref is required" };
318
+ const mode = input.validation_mode ?? "auto";
319
+ // 11c: explicit syntax_only short-circuits all schema work at the wrapper
320
+ // level too. The user said parser-only; don't read schema_ref off disk,
321
+ // don't auto-discover, don't error on a missing schema. Pass straight to
322
+ // handleValidate which knows to run parseOnlyResult.
323
+ if (mode === "syntax_only") {
324
+ const result = await handleValidate({ policies, validation_mode: "syntax_only" });
325
+ return { result };
326
+ }
327
+ let schema = input.schema;
328
+ if (!schema && input.schema_ref) {
329
+ const resolved = resolveRef(input.schema_ref);
330
+ if ("error" in resolved)
331
+ return { error: resolved.error };
332
+ schema = resolved.content;
333
+ }
334
+ // 10d workspace auto-discovery, single-sourced through resolveWorkspaceSchema.
335
+ // schema_ref was resolved above; if a caller used schema_ref the helper short-
336
+ // circuits on the inline-schema check and never touches StoreManager.
337
+ const resolution = resolveWorkspaceSchema(schema, input.store);
338
+ if (resolution.kind === "error")
339
+ return { error: resolution.error };
340
+ let autoSchemaFrom;
341
+ if (resolution.kind === "resolved") {
342
+ schema = resolution.schema;
343
+ autoSchemaFrom = resolution.from;
344
+ }
345
+ const result = await handleValidate({ policies, schema, validation_mode: mode });
346
+ if (autoSchemaFrom) {
347
+ result.auto_discovered = { schema_from: autoSchemaFrom };
348
+ }
349
+ return { result };
350
+ }
351
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Cedar input format detection and normalization.
3
+ *
4
+ * Three AVP SDK variants exist in the wild — all need conversion to Cedar WASM format:
5
+ *
6
+ * Ruby SDK (snake_case): identifier.entity_type / entity_id, string/long/boolean
7
+ * Python/JS SDK (camelCase): identifier.entityType / entityId, string/long/boolean
8
+ * Official API/Console (PascalCase): Identifier.EntityType / EntityId, String/Long/Boolean
9
+ *
10
+ * Cedar WASM format:
11
+ * uid: { type, id }, attrs: { key: rawValue }, parents: [{ type, id }]
12
+ * Entity refs in attrs: { __entity: { type, id } }
13
+ * Extension types: { __extn: { fn, arg } }
14
+ *
15
+ * Detection strategy: case-insensitive key lookup handles all three casing variants
16
+ * in a single code path. One normalizer to rule them all.
17
+ *
18
+ * Cedar CLI format (uid.__entity wrapper): WASM accepts natively — no conversion needed.
19
+ *
20
+ * Attribute value wrapper detection rule:
21
+ * Single-key object whose key (lowercased) is a known AVP type name AND whose value
22
+ * is the matching primitive. Multi-key objects are Cedar Records — not touched.
23
+ *
24
+ * Limitation: a Cedar Record with exactly one field named "string"/"long"/"boolean"
25
+ * would be misidentified. Adding a second field removes the ambiguity.
26
+ *
27
+ * Sources confirmed by SDK docs (2026-05-20):
28
+ * Ruby: entity_type/entity_id/entity_identifier (snake_case)
29
+ * Python/JS: entityType/entityId/entityIdentifier (camelCase)
30
+ * Official API: EntityType/EntityId/EntityIdentifier (PascalCase)
31
+ */
32
+ export type InputFormat = "cedar" | "avp" | "cedar_cli";
33
+ export interface FormatDetectionResult {
34
+ format: InputFormat;
35
+ confidence: "high" | "medium";
36
+ note: string;
37
+ }
38
+ export interface NormalizedRef {
39
+ type: string;
40
+ id: string;
41
+ }
42
+ export interface NormalizedRefError {
43
+ error: string;
44
+ }
45
+ export declare function detectFormat(entities: unknown[], principal: unknown, action: unknown, resource: unknown): FormatDetectionResult;
46
+ export declare function normalizeEntities(entities: unknown[], format: InputFormat): unknown[];
47
+ export declare function normalizePrincipalRef(ref: unknown): NormalizedRef | NormalizedRefError;
48
+ export declare function unwrapAvpAttributes(attrs: Record<string, unknown>): Record<string, unknown>;
49
+ //# sourceMappingURL=format-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-detector.d.ts","sourceRoot":"","sources":["../../src/utils/format-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,KAAK,GAAG,WAAW,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;CACf;AAkBD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,OAAO,GAChB,qBAAqB,CA0CvB;AAID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,EAAE,CAGrF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,kBAAkB,CA0CtF;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB"}