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.
- package/.editorconfig +12 -0
- package/.github/workflows/ci.yml +31 -0
- package/.github/workflows/release.yml +42 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +241 -0
- package/CONTRIBUTING.md +83 -0
- package/LICENSE +182 -0
- package/README.md +1635 -0
- package/SECURITY.md +37 -0
- package/dist/http-server.d.ts +61 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +194 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +270 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/policy-ast.d.ts +49 -0
- package/dist/parser/policy-ast.d.ts.map +1 -0
- package/dist/parser/policy-ast.js +311 -0
- package/dist/parser/policy-ast.js.map +1 -0
- package/dist/prompts/index.d.ts +38 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +172 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/ref-resolver.d.ts +23 -0
- package/dist/resources/ref-resolver.d.ts.map +1 -0
- package/dist/resources/ref-resolver.js +128 -0
- package/dist/resources/ref-resolver.js.map +1 -0
- package/dist/resources/store-manager.d.ts +64 -0
- package/dist/resources/store-manager.d.ts.map +1 -0
- package/dist/resources/store-manager.js +221 -0
- package/dist/resources/store-manager.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +539 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/advise/avp-rules.d.ts +49 -0
- package/dist/tools/advise/avp-rules.d.ts.map +1 -0
- package/dist/tools/advise/avp-rules.js +59 -0
- package/dist/tools/advise/avp-rules.js.map +1 -0
- package/dist/tools/advise/cedar-patterns.d.ts +24 -0
- package/dist/tools/advise/cedar-patterns.d.ts.map +1 -0
- package/dist/tools/advise/cedar-patterns.js +57 -0
- package/dist/tools/advise/cedar-patterns.js.map +1 -0
- package/dist/tools/advise/context-builder.d.ts +28 -0
- package/dist/tools/advise/context-builder.d.ts.map +1 -0
- package/dist/tools/advise/context-builder.js +89 -0
- package/dist/tools/advise/context-builder.js.map +1 -0
- package/dist/tools/advise/gotchas.d.ts +15 -0
- package/dist/tools/advise/gotchas.d.ts.map +1 -0
- package/dist/tools/advise/gotchas.js +83 -0
- package/dist/tools/advise/gotchas.js.map +1 -0
- package/dist/tools/advise.d.ts +96 -0
- package/dist/tools/advise.d.ts.map +1 -0
- package/dist/tools/advise.js +258 -0
- package/dist/tools/advise.js.map +1 -0
- package/dist/tools/authorize-batch.d.ts +35 -0
- package/dist/tools/authorize-batch.d.ts.map +1 -0
- package/dist/tools/authorize-batch.js +262 -0
- package/dist/tools/authorize-batch.js.map +1 -0
- package/dist/tools/authorize.d.ts +115 -0
- package/dist/tools/authorize.d.ts.map +1 -0
- package/dist/tools/authorize.js +373 -0
- package/dist/tools/authorize.js.map +1 -0
- package/dist/tools/check-change.d.ts +19 -0
- package/dist/tools/check-change.d.ts.map +1 -0
- package/dist/tools/check-change.js +91 -0
- package/dist/tools/check-change.js.map +1 -0
- package/dist/tools/diff-schema.d.ts +103 -0
- package/dist/tools/diff-schema.d.ts.map +1 -0
- package/dist/tools/diff-schema.js +379 -0
- package/dist/tools/diff-schema.js.map +1 -0
- package/dist/tools/diff-stores.d.ts +45 -0
- package/dist/tools/diff-stores.d.ts.map +1 -0
- package/dist/tools/diff-stores.js +222 -0
- package/dist/tools/diff-stores.js.map +1 -0
- package/dist/tools/explain.d.ts +80 -0
- package/dist/tools/explain.d.ts.map +1 -0
- package/dist/tools/explain.js +187 -0
- package/dist/tools/explain.js.map +1 -0
- package/dist/tools/format.d.ts +11 -0
- package/dist/tools/format.d.ts.map +1 -0
- package/dist/tools/format.js +20 -0
- package/dist/tools/format.js.map +1 -0
- package/dist/tools/generate-sample.d.ts +28 -0
- package/dist/tools/generate-sample.d.ts.map +1 -0
- package/dist/tools/generate-sample.js +568 -0
- package/dist/tools/generate-sample.js.map +1 -0
- package/dist/tools/link-template.d.ts +17 -0
- package/dist/tools/link-template.d.ts.map +1 -0
- package/dist/tools/link-template.js +78 -0
- package/dist/tools/link-template.js.map +1 -0
- package/dist/tools/list-template-links.d.ts +16 -0
- package/dist/tools/list-template-links.d.ts.map +1 -0
- package/dist/tools/list-template-links.js +22 -0
- package/dist/tools/list-template-links.js.map +1 -0
- package/dist/tools/list-templates.d.ts +16 -0
- package/dist/tools/list-templates.d.ts.map +1 -0
- package/dist/tools/list-templates.js +36 -0
- package/dist/tools/list-templates.js.map +1 -0
- package/dist/tools/translate.d.ts +11 -0
- package/dist/tools/translate.d.ts.map +1 -0
- package/dist/tools/translate.js +53 -0
- package/dist/tools/translate.js.map +1 -0
- package/dist/tools/validate-entities.d.ts +19 -0
- package/dist/tools/validate-entities.d.ts.map +1 -0
- package/dist/tools/validate-entities.js +88 -0
- package/dist/tools/validate-entities.js.map +1 -0
- package/dist/tools/validate-schema.d.ts +22 -0
- package/dist/tools/validate-schema.d.ts.map +1 -0
- package/dist/tools/validate-schema.js +89 -0
- package/dist/tools/validate-schema.js.map +1 -0
- package/dist/tools/validate-template.d.ts +18 -0
- package/dist/tools/validate-template.d.ts.map +1 -0
- package/dist/tools/validate-template.js +59 -0
- package/dist/tools/validate-template.js.map +1 -0
- package/dist/tools/validate.d.ts +90 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +351 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/utils/format-detector.d.ts +49 -0
- package/dist/utils/format-detector.d.ts.map +1 -0
- package/dist/utils/format-detector.js +298 -0
- package/dist/utils/format-detector.js.map +1 -0
- package/examples/README.md +36 -0
- package/examples/abac-multi-tenant/README.md +150 -0
- package/examples/abac-multi-tenant/entities/users-and-docs.json +33 -0
- package/examples/abac-multi-tenant/policies/member-read-internal.cedar +9 -0
- package/examples/abac-multi-tenant/policies/owner-full-access.cedar +9 -0
- package/examples/abac-multi-tenant/policies/premium-share-guard.cedar +9 -0
- package/examples/abac-multi-tenant/policies/private-doc-guard.cedar +13 -0
- package/examples/abac-multi-tenant/run.ts +92 -0
- package/examples/abac-multi-tenant/schema.json +60 -0
- package/examples/api-gateway-path-routing/README.md +154 -0
- package/examples/api-gateway-path-routing/entities/users-and-roles.json +20 -0
- package/examples/api-gateway-path-routing/policies/admin-full-access.cedar +6 -0
- package/examples/api-gateway-path-routing/policies/developer-projects.cedar +14 -0
- package/examples/api-gateway-path-routing/policies/viewer-readonly.cedar +10 -0
- package/examples/api-gateway-path-routing/run.ts +108 -0
- package/examples/api-gateway-path-routing/schema.json +54 -0
- package/examples/rbac-document-management/README.md +167 -0
- package/examples/rbac-document-management/entities/users-and-docs.json +43 -0
- package/examples/rbac-document-management/policies/admin.cedar +6 -0
- package/examples/rbac-document-management/policies/editor.cedar +6 -0
- package/examples/rbac-document-management/policies/top-secret-forbid.cedar +13 -0
- package/examples/rbac-document-management/policies/viewer.cedar +6 -0
- package/examples/rbac-document-management/run.ts +87 -0
- package/examples/rbac-document-management/schema.json +57 -0
- package/package.json +50 -0
- package/src/http-server.ts +239 -0
- package/src/index.ts +294 -0
- package/src/parser/policy-ast.ts +345 -0
- package/src/prompts/README.md +3 -0
- package/src/prompts/index.ts +217 -0
- package/src/resources/ref-resolver.ts +134 -0
- package/src/resources/store-manager.ts +248 -0
- package/src/server.ts +711 -0
- package/src/tools/advise/avp-rules.ts +70 -0
- package/src/tools/advise/cedar-patterns.ts +73 -0
- package/src/tools/advise/context-builder.ts +109 -0
- package/src/tools/advise/gotchas.ts +92 -0
- package/src/tools/advise.ts +366 -0
- package/src/tools/authorize-batch.ts +345 -0
- package/src/tools/authorize.ts +464 -0
- package/src/tools/check-change.ts +119 -0
- package/src/tools/diff-schema.ts +510 -0
- package/src/tools/diff-stores.ts +298 -0
- package/src/tools/explain.ts +278 -0
- package/src/tools/format.ts +33 -0
- package/src/tools/generate-sample.ts +665 -0
- package/src/tools/link-template.ts +109 -0
- package/src/tools/list-template-links.ts +41 -0
- package/src/tools/list-templates.ts +55 -0
- package/src/tools/translate.ts +66 -0
- package/src/tools/validate-entities.ts +125 -0
- package/src/tools/validate-schema.ts +128 -0
- package/src/tools/validate-template.ts +72 -0
- package/src/tools/validate.ts +459 -0
- package/src/utils/format-detector.ts +356 -0
- package/test/fixtures/docmgmt.ts +121 -0
- package/test/fixtures/multitenant.ts +163 -0
- package/test/index.test.ts +96 -0
- package/test/integration/e2e/behavior.test.ts +359 -0
- package/test/integration/e2e/edge-cases.test.ts +365 -0
- package/test/integration/e2e/failure-modes.test.ts +266 -0
- package/test/integration/e2e/protocol.test.ts +252 -0
- package/test/integration/http-smoke.test.ts +588 -0
- package/test/integration/smoke.test.ts +475 -0
- package/test/prompts/prompts.test.ts +173 -0
- package/test/property/properties.test.ts +234 -0
- package/test/resources/ref-resolver.test.ts +186 -0
- package/test/resources/store-manager.test.ts +344 -0
- package/test/setup.test.ts +7 -0
- package/test/tools/advise/avp-rules.test.ts +76 -0
- package/test/tools/advise.test.ts +339 -0
- package/test/tools/authorize-batch.test.ts +459 -0
- package/test/tools/authorize.test.ts +682 -0
- package/test/tools/check-change.test.ts +104 -0
- package/test/tools/cross-fixture.test.ts +170 -0
- package/test/tools/diff-schema.test.ts +355 -0
- package/test/tools/diff-stores.test.ts +291 -0
- package/test/tools/explain.test.ts +221 -0
- package/test/tools/format.test.ts +33 -0
- package/test/tools/generate-sample.test.ts +480 -0
- package/test/tools/link-template.test.ts +90 -0
- package/test/tools/list-templates.test.ts +151 -0
- package/test/tools/translate.test.ts +89 -0
- package/test/tools/validate-entities.test.ts +178 -0
- package/test/tools/validate-schema.test.ts +86 -0
- package/test/tools/validate-template.test.ts +89 -0
- package/test/tools/validate.test.ts +331 -0
- package/test/utils/format-detector.test.ts +518 -0
- package/tsconfig.json +17 -0
- 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"}
|