@intentius/chant-lexicon-cedar 0.44.8
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/README.md +190 -0
- package/dist/avp/ambient.d.ts +54 -0
- package/dist/avp/ambient.d.ts.map +1 -0
- package/dist/avp/client.d.ts +127 -0
- package/dist/avp/client.d.ts.map +1 -0
- package/dist/avp/describe-resources.d.ts +42 -0
- package/dist/avp/describe-resources.d.ts.map +1 -0
- package/dist/avp/embed.d.ts +120 -0
- package/dist/avp/embed.d.ts.map +1 -0
- package/dist/avp/live-export.d.ts +94 -0
- package/dist/avp/live-export.d.ts.map +1 -0
- package/dist/avp/ownership.d.ts +97 -0
- package/dist/avp/ownership.d.ts.map +1 -0
- package/dist/avp/statement.d.ts +22 -0
- package/dist/avp/statement.d.ts.map +1 -0
- package/dist/avp/store.d.ts +82 -0
- package/dist/avp/store.d.ts.map +1 -0
- package/dist/avp/testdata/mock-transport.d.ts +55 -0
- package/dist/avp/testdata/mock-transport.d.ts.map +1 -0
- package/dist/codegen/docs-cli.d.ts +3 -0
- package/dist/codegen/docs-cli.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts +26 -0
- package/dist/codegen/docs.d.ts.map +1 -0
- package/dist/codegen/emit.d.ts +85 -0
- package/dist/codegen/emit.d.ts.map +1 -0
- package/dist/codegen/generate-cli.d.ts +3 -0
- package/dist/codegen/generate-cli.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +37 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/naming.d.ts +48 -0
- package/dist/codegen/naming.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +10 -0
- package/dist/codegen/package.d.ts.map +1 -0
- package/dist/composites/deny-by-default-set.d.ts +58 -0
- package/dist/composites/deny-by-default-set.d.ts.map +1 -0
- package/dist/composites/index.d.ts +12 -0
- package/dist/composites/index.d.ts.map +1 -0
- package/dist/composites/owner-can-manage.d.ts +48 -0
- package/dist/composites/owner-can-manage.d.ts.map +1 -0
- package/dist/config.d.ts +102 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/coverage.d.ts +59 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/detect.d.ts +18 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/generated/index.d.ts +251 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/runtime.d.ts +2 -0
- package/dist/generated/runtime.d.ts.map +1 -0
- package/dist/import/adapter.d.ts +21 -0
- package/dist/import/adapter.d.ts.map +1 -0
- package/dist/import/clause-text.d.ts +38 -0
- package/dist/import/clause-text.d.ts.map +1 -0
- package/dist/import/generator.d.ts +53 -0
- package/dist/import/generator.d.ts.map +1 -0
- package/dist/import/parser.d.ts +57 -0
- package/dist/import/parser.d.ts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/init-templates.d.ts +32 -0
- package/dist/init-templates.d.ts.map +1 -0
- package/dist/integrity.json +22 -0
- package/dist/lint/audit-catalog.d.ts +29 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -0
- package/dist/lint/post-synth/cedar-helpers.d.ts +97 -0
- package/dist/lint/post-synth/cedar-helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/cedc010.d.ts +17 -0
- package/dist/lint/post-synth/cedc010.d.ts.map +1 -0
- package/dist/lint/post-synth/cedc011.d.ts +17 -0
- package/dist/lint/post-synth/cedc011.d.ts.map +1 -0
- package/dist/lint/post-synth/cedc012.d.ts +21 -0
- package/dist/lint/post-synth/cedc012.d.ts.map +1 -0
- package/dist/lint/post-synth/cedc013.d.ts +20 -0
- package/dist/lint/post-synth/cedc013.d.ts.map +1 -0
- package/dist/lint/post-synth/cedc014.d.ts +19 -0
- package/dist/lint/post-synth/cedc014.d.ts.map +1 -0
- package/dist/lint/post-synth/cede010.d.ts +34 -0
- package/dist/lint/post-synth/cede010.d.ts.map +1 -0
- package/dist/lint/post-synth/cede011.d.ts +22 -0
- package/dist/lint/post-synth/cede011.d.ts.map +1 -0
- package/dist/lint/post-synth/ceds010.d.ts +24 -0
- package/dist/lint/post-synth/ceds010.d.ts.map +1 -0
- package/dist/lint/post-synth/ceds011.d.ts +19 -0
- package/dist/lint/post-synth/ceds011.d.ts.map +1 -0
- package/dist/lint/post-synth/ceds012.d.ts +17 -0
- package/dist/lint/post-synth/ceds012.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts +3 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -0
- package/dist/lint/post-synth/wasm-helpers.d.ts +108 -0
- package/dist/lint/post-synth/wasm-helpers.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +10 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/policy-shape.d.ts +31 -0
- package/dist/lint/rules/policy-shape.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts +24 -0
- package/dist/lsp/completions.d.ts.map +1 -0
- package/dist/lsp/hover.d.ts +11 -0
- package/dist/lsp/hover.d.ts.map +1 -0
- package/dist/lsp/registry.d.ts +45 -0
- package/dist/lsp/registry.d.ts.map +1 -0
- package/dist/manifest.json +8 -0
- package/dist/mcp/index.d.ts +34 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/policy-coverage.d.ts +81 -0
- package/dist/mcp/policy-coverage.d.ts.map +1 -0
- package/dist/meta.json +699 -0
- package/dist/okf/index.md +37 -0
- package/dist/okf/rules/CEDC001.md +11 -0
- package/dist/okf/rules/CEDC010.md +11 -0
- package/dist/okf/rules/CEDC011.md +15 -0
- package/dist/okf/rules/CEDC012.md +11 -0
- package/dist/okf/rules/CEDC013.md +15 -0
- package/dist/okf/rules/CEDC014.md +15 -0
- package/dist/okf/rules/CEDE010.md +15 -0
- package/dist/okf/rules/CEDE011.md +15 -0
- package/dist/okf/rules/CEDS010.md +15 -0
- package/dist/okf/rules/CEDS011.md +11 -0
- package/dist/okf/rules/CEDS012.md +15 -0
- package/dist/okf/types/AdminAction.md +14 -0
- package/dist/okf/types/Application.md +14 -0
- package/dist/okf/types/ApproveAction.md +13 -0
- package/dist/okf/types/CommentAction.md +14 -0
- package/dist/okf/types/CreateAction.md +14 -0
- package/dist/okf/types/DeleteAction.md +14 -0
- package/dist/okf/types/Document.md +18 -0
- package/dist/okf/types/Folder.md +15 -0
- package/dist/okf/types/Group.md +14 -0
- package/dist/okf/types/ListAction.md +14 -0
- package/dist/okf/types/Policy.md +29 -0
- package/dist/okf/types/ReadAction.md +14 -0
- package/dist/okf/types/ServiceAccount.md +15 -0
- package/dist/okf/types/ShareAction.md +14 -0
- package/dist/okf/types/Team.md +14 -0
- package/dist/okf/types/User.md +18 -0
- package/dist/okf/types/WriteAction.md +14 -0
- package/dist/package-cli.d.ts +3 -0
- package/dist/package-cli.d.ts.map +1 -0
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/rules/cedar-helpers.ts +209 -0
- package/dist/rules/cedc010.ts +80 -0
- package/dist/rules/cedc011.ts +47 -0
- package/dist/rules/cedc012.ts +64 -0
- package/dist/rules/cedc013.ts +68 -0
- package/dist/rules/cedc014.ts +73 -0
- package/dist/rules/cede010.ts +89 -0
- package/dist/rules/cede011.ts +58 -0
- package/dist/rules/ceds010.ts +57 -0
- package/dist/rules/ceds011.ts +42 -0
- package/dist/rules/ceds012.ts +50 -0
- package/dist/rules/policy-shape.ts +148 -0
- package/dist/rules/wasm-helpers.ts +315 -0
- package/dist/serializer.d.ts +138 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/spec/fetch.d.ts +71 -0
- package/dist/spec/fetch.d.ts.map +1 -0
- package/dist/spec/parse.d.ts +113 -0
- package/dist/spec/parse.d.ts.map +1 -0
- package/dist/spec/pin.d.ts +116 -0
- package/dist/spec/pin.d.ts.map +1 -0
- package/dist/spec/pinned-names.json +18 -0
- package/dist/spec/wasm.d.ts +143 -0
- package/dist/spec/wasm.d.ts.map +1 -0
- package/dist/types/index.d.ts +219 -0
- package/dist/validate-cli.d.ts +3 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate.d.ts +25 -0
- package/dist/validate.d.ts.map +1 -0
- package/package.json +75 -0
- package/src/avp/OWNERSHIP.md +125 -0
- package/src/avp/ambient.test.ts +113 -0
- package/src/avp/ambient.ts +124 -0
- package/src/avp/client.ts +310 -0
- package/src/avp/describe-resources.test.ts +316 -0
- package/src/avp/describe-resources.ts +215 -0
- package/src/avp/embed.test.ts +114 -0
- package/src/avp/embed.ts +190 -0
- package/src/avp/live-export.test.ts +232 -0
- package/src/avp/live-export.ts +185 -0
- package/src/avp/ownership.test.ts +101 -0
- package/src/avp/ownership.ts +170 -0
- package/src/avp/statement.ts +50 -0
- package/src/avp/store.ts +152 -0
- package/src/avp/testdata/mock-transport.ts +147 -0
- package/src/codegen/docs-cli.ts +7 -0
- package/src/codegen/docs.ts +873 -0
- package/src/codegen/emit.ts +496 -0
- package/src/codegen/generate-cli.ts +18 -0
- package/src/codegen/generate.test.ts +128 -0
- package/src/codegen/generate.ts +123 -0
- package/src/codegen/naming.ts +101 -0
- package/src/codegen/package.ts +52 -0
- package/src/composites/composites.test.ts +206 -0
- package/src/composites/deny-by-default-set.ts +98 -0
- package/src/composites/index.ts +13 -0
- package/src/composites/owner-can-manage.ts +80 -0
- package/src/config-namespace.test.ts +44 -0
- package/src/config.test.ts +82 -0
- package/src/config.ts +119 -0
- package/src/coverage.test.ts +61 -0
- package/src/coverage.ts +166 -0
- package/src/detect.test.ts +64 -0
- package/src/detect.ts +59 -0
- package/src/generated/index.d.ts +219 -0
- package/src/generated/index.ts +279 -0
- package/src/generated/lexicon-cedar.json +699 -0
- package/src/generated/runtime.ts +2 -0
- package/src/import/adapter.ts +63 -0
- package/src/import/clause-text.ts +178 -0
- package/src/import/generator.test.ts +133 -0
- package/src/import/generator.ts +219 -0
- package/src/import/parser.test.ts +265 -0
- package/src/import/parser.ts +352 -0
- package/src/import/roundtrip.test.ts +127 -0
- package/src/import/testdata/full.cedar +36 -0
- package/src/import/testdata/full.cedar.json +238 -0
- package/src/import/testdata/realistic.cedar +35 -0
- package/src/import/testdata/simple.cedar +6 -0
- package/src/index.ts +94 -0
- package/src/init-templates.test.ts +158 -0
- package/src/init-templates.ts +358 -0
- package/src/lint/audit-catalog.ts +130 -0
- package/src/lint/post-synth/cedar-helpers.ts +209 -0
- package/src/lint/post-synth/cedc010.ts +80 -0
- package/src/lint/post-synth/cedc011.ts +47 -0
- package/src/lint/post-synth/cedc012.ts +64 -0
- package/src/lint/post-synth/cedc013.ts +68 -0
- package/src/lint/post-synth/cedc014.ts +73 -0
- package/src/lint/post-synth/cede010.ts +89 -0
- package/src/lint/post-synth/cede011.ts +58 -0
- package/src/lint/post-synth/ceds010.ts +57 -0
- package/src/lint/post-synth/ceds011.ts +42 -0
- package/src/lint/post-synth/ceds012.ts +50 -0
- package/src/lint/post-synth/index.ts +25 -0
- package/src/lint/post-synth/post-synth.test.ts +474 -0
- package/src/lint/post-synth/wasm-helpers.ts +315 -0
- package/src/lint/rules/index.ts +12 -0
- package/src/lint/rules/policy-shape.test.ts +90 -0
- package/src/lint/rules/policy-shape.ts +148 -0
- package/src/lsp/completions.test.ts +111 -0
- package/src/lsp/completions.ts +55 -0
- package/src/lsp/hover.test.ts +82 -0
- package/src/lsp/hover.ts +75 -0
- package/src/lsp/registry.ts +74 -0
- package/src/mcp/index.ts +103 -0
- package/src/mcp/policy-coverage.test.ts +176 -0
- package/src/mcp/policy-coverage.ts +205 -0
- package/src/package-cli.ts +22 -0
- package/src/plugin.test.ts +115 -0
- package/src/plugin.ts +312 -0
- package/src/serializer.test.ts +502 -0
- package/src/serializer.ts +335 -0
- package/src/skills/chant-cedar-authoring.md +180 -0
- package/src/skills/chant-cedar-avp-embedding.md +125 -0
- package/src/skills/chant-cedar-meta-policy.md +119 -0
- package/src/spec/default-schema.cedarschema +108 -0
- package/src/spec/fetch.ts +107 -0
- package/src/spec/parse.test.ts +123 -0
- package/src/spec/parse.ts +253 -0
- package/src/spec/pin.test.ts +88 -0
- package/src/spec/pin.ts +243 -0
- package/src/spec/pinned-names.json +18 -0
- package/src/spec/wasm.ts +283 -0
- package/src/validate-cli.ts +8 -0
- package/src/validate.ts +85 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every template scaffolds a project that builds — checked against the codegen
|
|
3
|
+
* rather than asserted in prose.
|
|
4
|
+
*
|
|
5
|
+
* "Builds" for cedar means something specific: the policy file imports classes
|
|
6
|
+
* and action constants that do not exist until `chant generate` has read the
|
|
7
|
+
* project's own schema. So the test runs the same pipeline stage `generate()`
|
|
8
|
+
* does — parse the template's `.cedarschema`, build the emit model — and
|
|
9
|
+
* requires every identifier the template imports to be in it. A template whose
|
|
10
|
+
* schema and policies drift apart fails here rather than in a user's terminal.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
14
|
+
import { checkParsePolicySet, checkParseSchema } from "@cedar-policy/cedar-wasm/nodejs";
|
|
15
|
+
import { CEDAR_INIT_TEMPLATES, cedarInitTemplates } from "./init-templates";
|
|
16
|
+
import { parseCedarSchema } from "./spec/parse";
|
|
17
|
+
import { buildEmitModel } from "./codegen/emit";
|
|
18
|
+
import { createNaming, POLICY_TS_NAME } from "./codegen/naming";
|
|
19
|
+
|
|
20
|
+
/** Names exported by the generated index for a given schema. */
|
|
21
|
+
function generatedNames(schemaText: string): Set<string> {
|
|
22
|
+
const { decls } = parseCedarSchema(schemaText);
|
|
23
|
+
const model = buildEmitModel(decls, createNaming(decls));
|
|
24
|
+
|
|
25
|
+
const names = new Set<string>([
|
|
26
|
+
POLICY_TS_NAME,
|
|
27
|
+
"EntityTypeName",
|
|
28
|
+
"EntityUid",
|
|
29
|
+
"ActionUid",
|
|
30
|
+
"PolicyRef",
|
|
31
|
+
"PolicyEffect",
|
|
32
|
+
"PolicyScope",
|
|
33
|
+
"PolicyProps",
|
|
34
|
+
"ALL_ACTIONS",
|
|
35
|
+
"ALL_ENTITY_TYPES",
|
|
36
|
+
]);
|
|
37
|
+
for (const entity of model.entities) {
|
|
38
|
+
names.add(entity.tsName);
|
|
39
|
+
names.add(entity.attributesTsName);
|
|
40
|
+
names.add(entity.uidTsName);
|
|
41
|
+
names.add(`${entity.attributesTsName}Props`);
|
|
42
|
+
}
|
|
43
|
+
for (const action of model.actions) {
|
|
44
|
+
names.add(action.tsName);
|
|
45
|
+
names.add(action.contextTsName);
|
|
46
|
+
names.add(`${action.contextTsName}Props`);
|
|
47
|
+
}
|
|
48
|
+
return names;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Identifiers a policy file imports from the lexicon package (any subpath). */
|
|
52
|
+
function importedNames(source: string): string[] {
|
|
53
|
+
const names: string[] = [];
|
|
54
|
+
const importRe = /import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+"@intentius\/chant-lexicon-cedar[^"]*"/g;
|
|
55
|
+
for (const match of source.matchAll(importRe)) {
|
|
56
|
+
for (const raw of match[1].split(",")) {
|
|
57
|
+
const name = raw.trim().replace(/^type\s+/, "").split(/\s+as\s+/)[0].trim();
|
|
58
|
+
if (name) names.push(name);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return names;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Names the composites barrel exports — not schema-derived, so listed here. */
|
|
65
|
+
const COMPOSITE_EXPORTS = new Set(["OwnerCanManage", "DenyByDefaultSet"]);
|
|
66
|
+
|
|
67
|
+
/** Every entity type the schema declares, as a policy scope would spell it. */
|
|
68
|
+
function entityTypeNames(schemaText: string): Set<string> {
|
|
69
|
+
return new Set(parseCedarSchema(schemaText).decls.filter((d) => d.kind === "entity").map((d) => d.typeName));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe("cedarInitTemplates", () => {
|
|
73
|
+
it("names three templates", () => {
|
|
74
|
+
expect(CEDAR_INIT_TEMPLATES).toEqual(["default", "avp-embedding", "gateway-policy-set"]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("falls back to the default for an unknown name", () => {
|
|
78
|
+
expect(cedarInitTemplates("no-such-template")).toEqual(cedarInitTemplates());
|
|
79
|
+
expect(cedarInitTemplates("default")).toEqual(cedarInitTemplates());
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("gives each named template its own schema and policies", () => {
|
|
83
|
+
const avp = cedarInitTemplates("avp-embedding");
|
|
84
|
+
const gateway = cedarInitTemplates("gateway-policy-set");
|
|
85
|
+
|
|
86
|
+
expect(avp.root?.["schema.cedarschema"]).not.toEqual(gateway.root?.["schema.cedarschema"]);
|
|
87
|
+
expect(avp.src["policies.ts"]).not.toEqual(gateway.src["policies.ts"]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
for (const template of CEDAR_INIT_TEMPLATES) {
|
|
91
|
+
describe(template, () => {
|
|
92
|
+
const set = cedarInitTemplates(template);
|
|
93
|
+
const schemaText = set.root?.["schema.cedarschema"] ?? "";
|
|
94
|
+
const policies = set.src["policies.ts"] ?? "";
|
|
95
|
+
|
|
96
|
+
it("ships a schema at the path cedar resolves without any config", () => {
|
|
97
|
+
// spec/fetch.ts step 2: `schema.cedarschema` in the project root.
|
|
98
|
+
expect(schemaText.length).toBeGreaterThan(0);
|
|
99
|
+
expect(checkParseSchema(schemaText).type).toBe("success");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("ships a policy file and a README", () => {
|
|
103
|
+
expect(policies).toContain("export const");
|
|
104
|
+
expect(set.root?.["README.md"]).toContain("chant generate --lexicon cedar");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("wires the generate and build scripts into package.json", () => {
|
|
108
|
+
expect(set.scripts?.generate).toBe("chant generate --lexicon cedar");
|
|
109
|
+
expect(set.scripts?.build).toBe("chant build");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("imports only names its own schema generates", () => {
|
|
113
|
+
const available = generatedNames(schemaText);
|
|
114
|
+
const missing = importedNames(policies).filter(
|
|
115
|
+
(name) => !available.has(name) && !COMPOSITE_EXPORTS.has(name),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(missing, `${template}: policies.ts imports names its schema does not produce`).toEqual([]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("names only entity types its own schema declares", () => {
|
|
122
|
+
const declared = entityTypeNames(schemaText);
|
|
123
|
+
const referenced = [...policies.matchAll(/is:\s*"([^"]+)"/g)].map((m) => m[1]);
|
|
124
|
+
|
|
125
|
+
expect(referenced.length).toBeGreaterThan(0);
|
|
126
|
+
for (const name of referenced) {
|
|
127
|
+
expect(declared, `${template}: ${name} is not in this template's schema`).toContain(name);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("declares at least one forbid — Cedar's only override construct", () => {
|
|
132
|
+
expect(policies).toMatch(/effect:\s*"forbid"|DenyByDefaultSet/);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
it("emits a bare-permit-free default policy set", () => {
|
|
138
|
+
// The meta-policy wall fails `permit (principal, action, resource);` in a
|
|
139
|
+
// prod build, so no scaffold may ship one.
|
|
140
|
+
const policies = cedarInitTemplates().src["policies.ts"];
|
|
141
|
+
|
|
142
|
+
expect(policies).toContain("principal: { is:");
|
|
143
|
+
expect(policies).toContain("when:");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("produces schemas cedar-wasm accepts alongside a parsable policy shape", () => {
|
|
147
|
+
// A sanity check that the scope forms the templates use survive the
|
|
148
|
+
// round-trip through Cedar's own parser.
|
|
149
|
+
const probe = `permit (
|
|
150
|
+
principal is App::User,
|
|
151
|
+
action == App::Action::"read",
|
|
152
|
+
resource is App::Document
|
|
153
|
+
)
|
|
154
|
+
when { resource.owner == principal };`;
|
|
155
|
+
|
|
156
|
+
expect(checkParsePolicySet({ staticPolicies: probe }).type).toBe("success");
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant init --lexicon cedar --template <name>` scaffolds.
|
|
3
|
+
*
|
|
4
|
+
* Every template ships a `schema.cedarschema` at the project root. That is not
|
|
5
|
+
* decoration: cedar's codegen input is the project's own schema (epic #1645),
|
|
6
|
+
* and a scaffold without one generates against the bundled default — a project
|
|
7
|
+
* whose typed classes describe somebody else's entity model.
|
|
8
|
+
*
|
|
9
|
+
* The filename is fixed rather than configured because `schema.cedarschema` in
|
|
10
|
+
* the project root is step 2 of the resolution order in `spec/fetch.ts`, so a
|
|
11
|
+
* scaffolded project needs no `cedar.schema` key at all. It also has to be
|
|
12
|
+
* fixed: core writes `chant.config.ts` before a plugin's root files and
|
|
13
|
+
* `writeIfNotExists` keeps the first one, so a template that shipped its own
|
|
14
|
+
* config would be silently discarded. The README each template ships is where
|
|
15
|
+
* `requireProjectSchema` gets recommended, which is the honest place for advice
|
|
16
|
+
* a scaffold cannot enforce.
|
|
17
|
+
*
|
|
18
|
+
* The policy files use `entityType`-string scopes (`{ is: "App::Document" }`)
|
|
19
|
+
* and generated action constants, so a scaffolded project compiles the moment
|
|
20
|
+
* `chant generate` has run against its own schema.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { InitTemplateSet } from "@intentius/chant/lexicon";
|
|
24
|
+
|
|
25
|
+
/** Filename every template writes its schema to — see spec/fetch.ts step 2. */
|
|
26
|
+
const SCHEMA_FILE = "schema.cedarschema";
|
|
27
|
+
|
|
28
|
+
function readme(title: string, body: string): string {
|
|
29
|
+
return `# ${title}
|
|
30
|
+
|
|
31
|
+
\`\`\`bash
|
|
32
|
+
npm install
|
|
33
|
+
npx chant generate --lexicon cedar # schema.cedarschema -> typed classes
|
|
34
|
+
npx chant build # emits .cedar text + policies.cedar.json
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
Generate first. The classes and action constants \`src/policies.ts\` imports do
|
|
38
|
+
not exist until \`chant generate\` has read \`${SCHEMA_FILE}\`.
|
|
39
|
+
|
|
40
|
+
${body}
|
|
41
|
+
|
|
42
|
+
## Before this is real
|
|
43
|
+
|
|
44
|
+
Add \`requireProjectSchema\` once you are past the scaffold:
|
|
45
|
+
|
|
46
|
+
\`\`\`typescript
|
|
47
|
+
// chant.config.ts
|
|
48
|
+
export default {
|
|
49
|
+
lexicons: ["cedar"],
|
|
50
|
+
cedar: {
|
|
51
|
+
validation: { mode: "strict", requireProjectSchema: true },
|
|
52
|
+
},
|
|
53
|
+
} satisfies ChantConfig;
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
Without it, deleting or renaming \`${SCHEMA_FILE}\` falls back to the schema
|
|
57
|
+
bundled with the lexicon and the build still succeeds — against an entity model
|
|
58
|
+
this project never declared.
|
|
59
|
+
|
|
60
|
+
## What comes out
|
|
61
|
+
|
|
62
|
+
| File | Who reads it |
|
|
63
|
+
|------|--------------|
|
|
64
|
+
| \`dist/*.cedar\` | Every Cedar evaluator — AVP, cedar-agent, an embedded cedar-wasm |
|
|
65
|
+
| \`dist/policies.cedar.json\` | The Cedar JSON policy format; also the parse source for import |
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── default ───────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
const DEFAULT_SCHEMA = `// The entity model your policies are typed against.
|
|
72
|
+
//
|
|
73
|
+
// \`chant generate --lexicon cedar\` turns every declaration below into a
|
|
74
|
+
// TypeScript class or constant, so a renamed entity type becomes a
|
|
75
|
+
// compiler-guided refactor rather than a runtime validation failure.
|
|
76
|
+
|
|
77
|
+
namespace App {
|
|
78
|
+
entity User = {
|
|
79
|
+
"email": String,
|
|
80
|
+
"department": String,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
entity Document = {
|
|
84
|
+
"title": String,
|
|
85
|
+
"owner": User,
|
|
86
|
+
"classification": String,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
action read, write appliesTo {
|
|
90
|
+
principal: [User],
|
|
91
|
+
resource: [Document],
|
|
92
|
+
context: {
|
|
93
|
+
"mfa": Bool,
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const DEFAULT_POLICIES = `import { Policy, ReadAction, WriteAction } from "@intentius/chant-lexicon-cedar";
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* A permit and a forbid — the smallest policy set worth deploying.
|
|
103
|
+
*
|
|
104
|
+
* Cedar is default-deny, so the permit is what grants anything at all. The
|
|
105
|
+
* forbid is not the absence of a grant: it beats every permit in the set
|
|
106
|
+
* unconditionally, which is what makes it survive a wider grant added later.
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/** Owners read and write their own documents. */
|
|
110
|
+
export const ownerAccess = new Policy({
|
|
111
|
+
effect: "permit",
|
|
112
|
+
principal: { is: "App::User" },
|
|
113
|
+
action: { in: [ReadAction, WriteAction] },
|
|
114
|
+
resource: { is: "App::Document" },
|
|
115
|
+
when: ["resource.owner == principal"],
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/** Nothing confidential moves without MFA, owner or not. */
|
|
119
|
+
export const requireMfaOnConfidential = new Policy({
|
|
120
|
+
effect: "forbid",
|
|
121
|
+
principal: { is: "App::User" },
|
|
122
|
+
resource: { is: "App::Document" },
|
|
123
|
+
when: ['resource.classification == "confidential"'],
|
|
124
|
+
unless: ["context.mfa == true"],
|
|
125
|
+
});
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
// ── avp-embedding ─────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
const AVP_SCHEMA = `// The entity model behind an Amazon Verified Permissions policy store.
|
|
131
|
+
//
|
|
132
|
+
// AVP is one deployment vehicle for Cedar; the schema and the policies are
|
|
133
|
+
// ordinary Cedar either way, and the same emitted \`.cedar\` file is read by any
|
|
134
|
+
// other evaluator with no AWS involved.
|
|
135
|
+
|
|
136
|
+
namespace Store {
|
|
137
|
+
entity Tenant = {
|
|
138
|
+
"name": String,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
entity User in [Tenant] = {
|
|
142
|
+
"email": String,
|
|
143
|
+
"tenant": Tenant,
|
|
144
|
+
"admin": Bool,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
entity Record in [Tenant] = {
|
|
148
|
+
"tenant": Tenant,
|
|
149
|
+
"owner": User,
|
|
150
|
+
"sensitive": Bool,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
action view, edit appliesTo {
|
|
154
|
+
principal: [User],
|
|
155
|
+
resource: [Record],
|
|
156
|
+
context: {
|
|
157
|
+
"mfa": Bool,
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
const AVP_POLICIES = `import { Policy, EditAction, ViewAction } from "@intentius/chant-lexicon-cedar";
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Policies destined for an AVP policy store.
|
|
167
|
+
*
|
|
168
|
+
* The statement each of these serializes to is what goes in a
|
|
169
|
+
* \`AWS::VerifiedPermissions::Policy\`'s \`definition.static.statement\` — the
|
|
170
|
+
* same bytes as the emitted \`.cedar\` file, so the deployed policy and the
|
|
171
|
+
* reviewed file cannot disagree.
|
|
172
|
+
*
|
|
173
|
+
* The typed handoff (a VerifiedPermissionsPolicy whose statement accepts a
|
|
174
|
+
* Policy value directly, plus the policy-store lifecycle and the ownership
|
|
175
|
+
* channel) is landing with INTENTIUS/chant#1652. Until it does, emit the
|
|
176
|
+
* \`.cedar\` file and reference its text; do not hand-type a statement string.
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
/** Tenancy: nobody touches a record outside their own tenant. */
|
|
180
|
+
export const tenantIsolation = new Policy({
|
|
181
|
+
effect: "forbid",
|
|
182
|
+
principal: { is: "Store::User" },
|
|
183
|
+
resource: { is: "Store::Record" },
|
|
184
|
+
unless: ["resource.tenant == principal.tenant"],
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
/** Members view records in their tenant. */
|
|
188
|
+
export const tenantView = new Policy({
|
|
189
|
+
effect: "permit",
|
|
190
|
+
principal: { is: "Store::User" },
|
|
191
|
+
action: { eq: ViewAction },
|
|
192
|
+
resource: { is: "Store::Record" },
|
|
193
|
+
when: ["resource.tenant == principal.tenant"],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
/** Owners and tenant admins edit; sensitive records also demand MFA. */
|
|
197
|
+
export const ownerEdit = new Policy({
|
|
198
|
+
effect: "permit",
|
|
199
|
+
principal: { is: "Store::User" },
|
|
200
|
+
action: { eq: EditAction },
|
|
201
|
+
resource: { is: "Store::Record" },
|
|
202
|
+
when: ["resource.owner == principal || principal.admin == true"],
|
|
203
|
+
unless: ["resource.sensitive == true && context.mfa == false"],
|
|
204
|
+
});
|
|
205
|
+
`;
|
|
206
|
+
|
|
207
|
+
// ── gateway-policy-set ────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
const GATEWAY_SCHEMA = `// An API gateway's authorization model.
|
|
210
|
+
//
|
|
211
|
+
// The principal is a caller identity, the resource is a route, and the action
|
|
212
|
+
// is an HTTP method. Modelling routes as entities rather than strings is what
|
|
213
|
+
// lets a policy say \`resource.public == true\` instead of matching paths.
|
|
214
|
+
|
|
215
|
+
namespace Gateway {
|
|
216
|
+
entity Scope = {
|
|
217
|
+
"name": String,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
entity Caller in [Scope] = {
|
|
221
|
+
"clientId": String,
|
|
222
|
+
"internal": Bool,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
entity Route = {
|
|
226
|
+
"path": String,
|
|
227
|
+
"public": Bool,
|
|
228
|
+
"deprecated": Bool,
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
action get, post, delete appliesTo {
|
|
232
|
+
principal: [Caller],
|
|
233
|
+
resource: [Route],
|
|
234
|
+
context: {
|
|
235
|
+
"sourceIp": String,
|
|
236
|
+
"authenticated": Bool,
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
`;
|
|
241
|
+
|
|
242
|
+
const GATEWAY_POLICIES = `import {
|
|
243
|
+
DeleteAction,
|
|
244
|
+
DenyByDefaultSet,
|
|
245
|
+
GetAction,
|
|
246
|
+
Policy,
|
|
247
|
+
PostAction,
|
|
248
|
+
} from "@intentius/chant-lexicon-cedar";
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* A gateway policy set with an explicit deny floor.
|
|
252
|
+
*
|
|
253
|
+
* \`DenyByDefaultSet\` returns the forbid and the permits it governs from one
|
|
254
|
+
* call, so the floor cannot be deleted in a refactor while the grants survive.
|
|
255
|
+
* A forbid beats every permit unconditionally — that is the whole reason to
|
|
256
|
+
* write one under a default-deny engine.
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
/** Anonymous callers reach public routes, read-only. */
|
|
260
|
+
const publicRead = new Policy({
|
|
261
|
+
effect: "permit",
|
|
262
|
+
principal: { is: "Gateway::Caller" },
|
|
263
|
+
action: { eq: GetAction },
|
|
264
|
+
resource: { is: "Gateway::Route" },
|
|
265
|
+
when: ["resource.public == true"],
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
/** Authenticated callers may write. */
|
|
269
|
+
const authenticatedWrite = new Policy({
|
|
270
|
+
effect: "permit",
|
|
271
|
+
principal: { is: "Gateway::Caller" },
|
|
272
|
+
action: { in: [PostAction, DeleteAction] },
|
|
273
|
+
resource: { is: "Gateway::Route" },
|
|
274
|
+
when: ["context.authenticated == true"],
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
/** Deprecated routes are closed to everyone but internal callers. */
|
|
278
|
+
const guarded = DenyByDefaultSet({
|
|
279
|
+
policies: [publicRead, authenticatedWrite],
|
|
280
|
+
entityType: "Gateway::Route",
|
|
281
|
+
when: ["resource.deprecated == true"],
|
|
282
|
+
unless: ["principal.internal == true"],
|
|
283
|
+
annotations: { id: "deprecated-route-floor" },
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
export const deprecatedRouteFloor = guarded.floor;
|
|
287
|
+
export const publicReadGrant = guarded.members[0];
|
|
288
|
+
export const authenticatedWriteGrant = guarded.members[1];
|
|
289
|
+
`;
|
|
290
|
+
|
|
291
|
+
// ── The template set ──────────────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Scaffolds for `chant init`.
|
|
295
|
+
*
|
|
296
|
+
* An unrecognized name falls through to the default rather than throwing —
|
|
297
|
+
* the same behaviour every other lexicon's `initTemplates` has.
|
|
298
|
+
*/
|
|
299
|
+
export function cedarInitTemplates(template?: string): InitTemplateSet {
|
|
300
|
+
const scripts = {
|
|
301
|
+
generate: "chant generate --lexicon cedar",
|
|
302
|
+
build: "chant build",
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
if (template === "avp-embedding") {
|
|
306
|
+
return {
|
|
307
|
+
src: { "policies.ts": AVP_POLICIES },
|
|
308
|
+
root: {
|
|
309
|
+
[SCHEMA_FILE]: AVP_SCHEMA,
|
|
310
|
+
"README.md": readme(
|
|
311
|
+
"Cedar policies for a Verified Permissions store",
|
|
312
|
+
"The `Store` namespace models a multi-tenant record store. `tenantIsolation` is a\n" +
|
|
313
|
+
"`forbid`, deliberately: a forbid beats every permit in the set unconditionally,\n" +
|
|
314
|
+
"so a tenancy boundary written that way survives a wider grant added later.\n\n" +
|
|
315
|
+
"The statement each policy serializes to is what goes in an\n" +
|
|
316
|
+
"`AWS::VerifiedPermissions::Policy`. The typed handoff is landing with\n" +
|
|
317
|
+
"INTENTIUS/chant#1652 — until then, reference the emitted `.cedar` text rather\n" +
|
|
318
|
+
"than hand-typing a statement string.",
|
|
319
|
+
),
|
|
320
|
+
},
|
|
321
|
+
scripts,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (template === "gateway-policy-set") {
|
|
326
|
+
return {
|
|
327
|
+
src: { "policies.ts": GATEWAY_POLICIES },
|
|
328
|
+
root: {
|
|
329
|
+
[SCHEMA_FILE]: GATEWAY_SCHEMA,
|
|
330
|
+
"README.md": readme(
|
|
331
|
+
"Cedar policies for an API gateway",
|
|
332
|
+
"Routes are entities, not path strings, which is what lets a policy say\n" +
|
|
333
|
+
"`resource.public == true` instead of matching globs. The `DenyByDefaultSet`\n" +
|
|
334
|
+
"composite returns the deprecated-route floor and the grants it governs from one\n" +
|
|
335
|
+
"call, so a refactor cannot delete the floor and leave the grants behind.",
|
|
336
|
+
),
|
|
337
|
+
},
|
|
338
|
+
scripts,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
src: { "policies.ts": DEFAULT_POLICIES },
|
|
344
|
+
root: {
|
|
345
|
+
[SCHEMA_FILE]: DEFAULT_SCHEMA,
|
|
346
|
+
"README.md": readme(
|
|
347
|
+
"Cedar policies",
|
|
348
|
+
"One permit and one forbid. Cedar is default-deny, so the permit is what grants\n" +
|
|
349
|
+
"anything at all; the forbid is not the absence of a grant but an override that\n" +
|
|
350
|
+
"beats every permit in the set.",
|
|
351
|
+
),
|
|
352
|
+
},
|
|
353
|
+
scripts,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Every template name this lexicon scaffolds, for docs and tests. */
|
|
358
|
+
export const CEDAR_INIT_TEMPLATES = ["default", "avp-embedding", "gateway-policy-set"] as const;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cedar lexicon's `chant audit` catalog — metadata for every CED check,
|
|
3
|
+
* contributed via `cedarPlugin.auditCatalog()` (#687, #1346).
|
|
4
|
+
*
|
|
5
|
+
* A check's own definition says what it looks for. It does not say how severe
|
|
6
|
+
* the finding is, whether the fix is mechanical, what backs the rule, or what
|
|
7
|
+
* to title it in a report. `resolveAuditCatalog` merges this map over core's
|
|
8
|
+
* static catalog to answer all four — and it skips a lexicon that omits the
|
|
9
|
+
* method *silently*, which is how fly's and temporal's checks reached the
|
|
10
|
+
* report with no metadata at all. A repo-level test fails on a gap in either
|
|
11
|
+
* direction, so this map and the shipped checks move together.
|
|
12
|
+
*
|
|
13
|
+
* Every entry here is `yamlBased: true`: each check reads `ctx.outputs` — the
|
|
14
|
+
* emitted policy set — and nothing reads `ctx.entities`, so all of them fire
|
|
15
|
+
* on an audit of a standalone `policies.cedar.json` exactly as they do on a
|
|
16
|
+
* `chant build`. `auditRule()` hardcodes that, so it is used throughout rather
|
|
17
|
+
* than constructing `RuleMeta` by hand the way fly and fountain must.
|
|
18
|
+
*
|
|
19
|
+
* `authority` is left off deliberately. The catalog test treats a citation as
|
|
20
|
+
* proof that a finding is `security`, and Cedar's own docs are a language
|
|
21
|
+
* reference rather than a benchmark like CIS or OSSF Scorecard; citing them
|
|
22
|
+
* would be dressing up chant's own opinion. The one place a citation would be
|
|
23
|
+
* honest — the bare-permit wall — is chant's convention, not upstream's, and
|
|
24
|
+
* the verification report is explicit that Cedar's validator says nothing
|
|
25
|
+
* about it.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { auditRule, type RuleMeta } from "@intentius/chant/audit/catalog";
|
|
29
|
+
|
|
30
|
+
export const cedarAuditCatalog: Record<string, RuleMeta> = {
|
|
31
|
+
// ── Pre-synth lint rule ────────────────────────────────────────
|
|
32
|
+
//
|
|
33
|
+
// Not a post-synth check, and so not required by the coverage test — but a
|
|
34
|
+
// reader who hits CEDC001 wants the same metadata as one who hits CEDC010,
|
|
35
|
+
// which is the reason fountain catalogs FTN001.
|
|
36
|
+
CEDC001: auditRule(
|
|
37
|
+
"CEDC001",
|
|
38
|
+
"merge-worthy",
|
|
39
|
+
"guidance",
|
|
40
|
+
"Cedar policy has an unusable effect or an empty guard",
|
|
41
|
+
'Use effect: "permit" or "forbid" — anything else is emitted as a permit — and remove empty when/unless entries.',
|
|
42
|
+
{ category: "correctness" },
|
|
43
|
+
),
|
|
44
|
+
|
|
45
|
+
// ── Correctness ────────────────────────────────────────────────
|
|
46
|
+
CEDC010: auditRule(
|
|
47
|
+
"CEDC010",
|
|
48
|
+
"merge-worthy",
|
|
49
|
+
"guidance",
|
|
50
|
+
"Cedar policy set does not parse",
|
|
51
|
+
"Fix the policy set so Cedar's own parser accepts it — no evaluator can load it as it stands.",
|
|
52
|
+
{ category: "correctness" },
|
|
53
|
+
),
|
|
54
|
+
CEDC011: auditRule(
|
|
55
|
+
"CEDC011",
|
|
56
|
+
"merge-worthy",
|
|
57
|
+
"guidance",
|
|
58
|
+
"Cedar condition expression does not parse",
|
|
59
|
+
"Correct the when/unless expression source named in the finding; the rest of the policy set cannot load until it parses.",
|
|
60
|
+
{ category: "correctness" },
|
|
61
|
+
),
|
|
62
|
+
CEDC012: auditRule(
|
|
63
|
+
"CEDC012",
|
|
64
|
+
"merge-worthy",
|
|
65
|
+
"guidance",
|
|
66
|
+
"Duplicate Cedar policy id",
|
|
67
|
+
"Rename one of the colliding declarations, or give it an explicit and distinct @id annotation — the JSON policy set keeps only one of them.",
|
|
68
|
+
{ category: "correctness" },
|
|
69
|
+
),
|
|
70
|
+
CEDC013: auditRule(
|
|
71
|
+
"CEDC013",
|
|
72
|
+
"report-only",
|
|
73
|
+
"guidance",
|
|
74
|
+
"Cedar policy annotation is empty or disagrees with the policy id",
|
|
75
|
+
"Make @id match the policy's id (or drop it and let chant derive one), and give every other annotation a real value.",
|
|
76
|
+
{ category: "best-practice" },
|
|
77
|
+
),
|
|
78
|
+
CEDC014: auditRule(
|
|
79
|
+
"CEDC014",
|
|
80
|
+
"merge-worthy",
|
|
81
|
+
"guidance",
|
|
82
|
+
"Cedar scope constraint names a bare type instead of an entity",
|
|
83
|
+
'Write the reference as a full UID — Namespace::Type::"id" — so it resolves to an entity rather than degrading to a type name with an empty id.',
|
|
84
|
+
{ category: "correctness" },
|
|
85
|
+
),
|
|
86
|
+
|
|
87
|
+
// ── Evaluability (the validator) ───────────────────────────────
|
|
88
|
+
CEDE010: auditRule(
|
|
89
|
+
"CEDE010",
|
|
90
|
+
"merge-worthy",
|
|
91
|
+
"guidance",
|
|
92
|
+
"Cedar policy fails validation against the schema",
|
|
93
|
+
"Fix the entity type, action, or attribute the validator names — a policy the validator rejects can never grant anything. If the finding is the advisory, emit a .cedarschema beside the policies so validation can run at all.",
|
|
94
|
+
{ category: "correctness" },
|
|
95
|
+
),
|
|
96
|
+
CEDE011: auditRule(
|
|
97
|
+
"CEDE011",
|
|
98
|
+
"report-only",
|
|
99
|
+
"guidance",
|
|
100
|
+
"Cedar validator warns about a policy",
|
|
101
|
+
"Read the validator's warning — an impossible policy evaluates to false for every valid request, so the access it was written to grant does not exist.",
|
|
102
|
+
{ category: "correctness" },
|
|
103
|
+
),
|
|
104
|
+
|
|
105
|
+
// ── Security ───────────────────────────────────────────────────
|
|
106
|
+
CEDS010: auditRule(
|
|
107
|
+
"CEDS010",
|
|
108
|
+
"merge-worthy",
|
|
109
|
+
"guidance",
|
|
110
|
+
"Bare permit(principal, action, resource) grants everything",
|
|
111
|
+
"Constrain a scope or add a when/unless guard. Cedar's validator does not flag this policy; a production build fails on it.",
|
|
112
|
+
{ category: "security" },
|
|
113
|
+
),
|
|
114
|
+
CEDS011: auditRule(
|
|
115
|
+
"CEDS011",
|
|
116
|
+
"report-only",
|
|
117
|
+
"guidance",
|
|
118
|
+
"Cedar policy set has no forbid",
|
|
119
|
+
"Add a forbid for whatever the set must never allow — a forbid beats every permit, so it is the only invariant a later grant cannot widen.",
|
|
120
|
+
{ category: "security" },
|
|
121
|
+
),
|
|
122
|
+
CEDS012: auditRule(
|
|
123
|
+
"CEDS012",
|
|
124
|
+
"report-only",
|
|
125
|
+
"guidance",
|
|
126
|
+
"Cedar permit leaves the action scope unconstrained",
|
|
127
|
+
'Name the actions the grant needs (action == Action::"read", or action in [ … ]) so it does not widen as the schema gains actions.',
|
|
128
|
+
{ category: "security" },
|
|
129
|
+
),
|
|
130
|
+
};
|