@indorania/contracts 0.1.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/README.md +117 -0
- package/dist/common.d.ts +144 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/common.js +162 -0
- package/dist/common.js.map +1 -0
- package/dist/constitution/index.d.ts +9 -0
- package/dist/constitution/index.d.ts.map +1 -0
- package/dist/constitution/index.js +9 -0
- package/dist/constitution/index.js.map +1 -0
- package/dist/constitution/openapi.d.ts +23 -0
- package/dist/constitution/openapi.d.ts.map +1 -0
- package/dist/constitution/openapi.js +375 -0
- package/dist/constitution/openapi.js.map +1 -0
- package/dist/constitution/report.d.ts +63 -0
- package/dist/constitution/report.d.ts.map +1 -0
- package/dist/constitution/report.js +73 -0
- package/dist/constitution/report.js.map +1 -0
- package/dist/constitution/tables.d.ts +53 -0
- package/dist/constitution/tables.d.ts.map +1 -0
- package/dist/constitution/tables.js +96 -0
- package/dist/constitution/tables.js.map +1 -0
- package/dist/constitution/words.d.ts +39 -0
- package/dist/constitution/words.d.ts.map +1 -0
- package/dist/constitution/words.js +126 -0
- package/dist/constitution/words.js.map +1 -0
- package/dist/document.d.ts +12 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +106 -0
- package/dist/document.js.map +1 -0
- package/dist/domain-error.d.ts +14 -0
- package/dist/domain-error.d.ts.map +1 -0
- package/dist/domain-error.js +23 -0
- package/dist/domain-error.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/op.d.ts +92 -0
- package/dist/op.d.ts.map +1 -0
- package/dist/op.js +113 -0
- package/dist/op.js.map +1 -0
- package/dist/routes/asks.d.ts +77 -0
- package/dist/routes/asks.d.ts.map +1 -0
- package/dist/routes/asks.js +182 -0
- package/dist/routes/asks.js.map +1 -0
- package/dist/routes/backup.d.ts +12 -0
- package/dist/routes/backup.d.ts.map +1 -0
- package/dist/routes/backup.js +63 -0
- package/dist/routes/backup.js.map +1 -0
- package/dist/routes/capabilities.d.ts +67 -0
- package/dist/routes/capabilities.d.ts.map +1 -0
- package/dist/routes/capabilities.js +88 -0
- package/dist/routes/capabilities.js.map +1 -0
- package/dist/routes/entitlements.d.ts +137 -0
- package/dist/routes/entitlements.d.ts.map +1 -0
- package/dist/routes/entitlements.js +101 -0
- package/dist/routes/entitlements.js.map +1 -0
- package/dist/routes/guest.d.ts +57 -0
- package/dist/routes/guest.d.ts.map +1 -0
- package/dist/routes/guest.js +140 -0
- package/dist/routes/guest.js.map +1 -0
- package/dist/routes/integration.d.ts +187 -0
- package/dist/routes/integration.d.ts.map +1 -0
- package/dist/routes/integration.js +243 -0
- package/dist/routes/integration.js.map +1 -0
- package/dist/routes/meta.d.ts +50 -0
- package/dist/routes/meta.d.ts.map +1 -0
- package/dist/routes/meta.js +90 -0
- package/dist/routes/meta.js.map +1 -0
- package/dist/routes/organisations.d.ts +121 -0
- package/dist/routes/organisations.d.ts.map +1 -0
- package/dist/routes/organisations.js +175 -0
- package/dist/routes/organisations.js.map +1 -0
- package/dist/routes/presentations.d.ts +95 -0
- package/dist/routes/presentations.d.ts.map +1 -0
- package/dist/routes/presentations.js +121 -0
- package/dist/routes/presentations.js.map +1 -0
- package/dist/routes/sessions.d.ts +180 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +240 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/standing.d.ts +24 -0
- package/dist/routes/standing.d.ts.map +1 -0
- package/dist/routes/standing.js +74 -0
- package/dist/routes/standing.js.map +1 -0
- package/dist/routes/thank-yous.d.ts +30 -0
- package/dist/routes/thank-yous.d.ts.map +1 -0
- package/dist/routes/thank-yous.js +139 -0
- package/dist/routes/thank-yous.js.map +1 -0
- package/dist/versions.d.ts +46 -0
- package/dist/versions.d.ts.map +1 -0
- package/dist/versions.js +54 -0
- package/dist/versions.js.map +1 -0
- package/dist/webhooks.d.ts +55 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +76 -0
- package/dist/webhooks.js.map +1 -0
- package/dist/zod.d.ts +3 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +7 -0
- package/dist/zod.js.map +1 -0
- package/node/kernel-esm.mjs +27 -0
- package/node/register.mjs +5 -0
- package/openapi/2026-09-25.json +6959 -0
- package/openapi/versions.json +10 -0
- package/package.json +49 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The constitution, checked against an OpenAPI 3.1 document. Pure: it reads the document and
|
|
3
|
+
* reports; it imports nothing from the kernel, so any member can run it on its own contract.
|
|
4
|
+
*/
|
|
5
|
+
import { summarise } from "./report.js";
|
|
6
|
+
import { DECLINE_TOKENS, MEMBER_NAMES, MEMBERSHIP_TOKENS, METER_TOKENS, ORIGIN_TOKENS, PERSON_TOKENS, SCORE_TOKENS, SECRET_TOKENS, hasToken, } from "./words.js";
|
|
7
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
8
|
+
/** The one person-side identifier component (see `RelationshipId` in common.ts). */
|
|
9
|
+
export const PERSON_SIDE_SCHEMA = "RelationshipId";
|
|
10
|
+
export const ORGANISATION_ID_SCHEMA = "OrganisationId";
|
|
11
|
+
export const ENVELOPE_SCHEMA = "DsseEnvelope";
|
|
12
|
+
/**
|
|
13
|
+
* The only reads allowed to return a list (d41: no endpoint answers "everything matching X", for
|
|
14
|
+
* anyone, admin included). Each is the caller's own, or public by design; its reason is on the
|
|
15
|
+
* operation as `x-indorania-collection`. Adding one is a reviewed edit to this list.
|
|
16
|
+
*/
|
|
17
|
+
export const COLLECTIONS = [
|
|
18
|
+
"listVersions",
|
|
19
|
+
"getWebhookKeys",
|
|
20
|
+
"listSeats",
|
|
21
|
+
"getCapabilities",
|
|
22
|
+
"getEntitlements",
|
|
23
|
+
"listAsks",
|
|
24
|
+
"listStandingRules",
|
|
25
|
+
"listSessionLines",
|
|
26
|
+
];
|
|
27
|
+
/** A list may be paged and narrowed by state — never searched or filtered. */
|
|
28
|
+
const COLLECTION_QUERY = new Set(["cursor", "limit", "state", "after"]);
|
|
29
|
+
const MEMBERSHIP_NOUNS = new Set(["member", "members", "membership", "memberships", "roster", "rosters"]);
|
|
30
|
+
const METHODS = ["get", "put", "post", "delete", "patch", "head", "options", "trace"];
|
|
31
|
+
const esc = (s) => s.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
32
|
+
function* operations(doc) {
|
|
33
|
+
for (const [kind, section] of [
|
|
34
|
+
["path", doc.paths],
|
|
35
|
+
["webhook", doc.webhooks],
|
|
36
|
+
]) {
|
|
37
|
+
if (!isObj(section))
|
|
38
|
+
continue;
|
|
39
|
+
for (const [key, item] of Object.entries(section)) {
|
|
40
|
+
if (!isObj(item))
|
|
41
|
+
continue;
|
|
42
|
+
for (const method of METHODS) {
|
|
43
|
+
const op = item[method];
|
|
44
|
+
if (isObj(op))
|
|
45
|
+
yield { kind, key, method, op, pointer: `/${kind === "path" ? "paths" : "webhooks"}/${esc(key)}/${method}` };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function refName(node) {
|
|
51
|
+
if (isObj(node) && typeof node.$ref === "string" && node.$ref.startsWith("#/components/schemas/")) {
|
|
52
|
+
return node.$ref.slice("#/components/schemas/".length);
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function component(doc, kind, name) {
|
|
57
|
+
const section = isObj(doc.components) ? doc.components[kind] : undefined;
|
|
58
|
+
const found = isObj(section) ? section[name] : undefined;
|
|
59
|
+
return isObj(found) ? found : undefined;
|
|
60
|
+
}
|
|
61
|
+
/** Every schema node reachable from `root`, following $refs (each once per path), noting whether it sits inside a list. */
|
|
62
|
+
function walk(doc, root, pointer, visit) {
|
|
63
|
+
const open = new Set();
|
|
64
|
+
const go = (node, at, inArray) => {
|
|
65
|
+
if (!isObj(node))
|
|
66
|
+
return;
|
|
67
|
+
const ref = refName(node);
|
|
68
|
+
const personSide = ref === PERSON_SIDE_SCHEMA || (ref === null && node["x-indorania-person-side"] === true);
|
|
69
|
+
visit(node, { pointer: at, inArray, ref, personSide });
|
|
70
|
+
if (personSide)
|
|
71
|
+
return; // a leaf: counted once, here
|
|
72
|
+
if (ref) {
|
|
73
|
+
const target = component(doc, "schemas", ref);
|
|
74
|
+
if (!target || open.has(ref))
|
|
75
|
+
return;
|
|
76
|
+
open.add(ref);
|
|
77
|
+
go(target, `/components/schemas/${esc(ref)}`, inArray);
|
|
78
|
+
open.delete(ref);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (isObj(node.properties))
|
|
82
|
+
for (const [k, v] of Object.entries(node.properties))
|
|
83
|
+
go(v, `${at}/properties/${esc(k)}`, inArray);
|
|
84
|
+
if (node.items !== undefined)
|
|
85
|
+
go(node.items, `${at}/items`, true);
|
|
86
|
+
if (Array.isArray(node.prefixItems))
|
|
87
|
+
node.prefixItems.forEach((v, i) => go(v, `${at}/prefixItems/${i}`, true));
|
|
88
|
+
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
89
|
+
const list = node[key];
|
|
90
|
+
if (Array.isArray(list))
|
|
91
|
+
list.forEach((v, i) => go(v, `${at}/${key}/${i}`, inArray));
|
|
92
|
+
}
|
|
93
|
+
// A map of values is a list by another name.
|
|
94
|
+
if (isObj(node.additionalProperties))
|
|
95
|
+
go(node.additionalProperties, `${at}/additionalProperties`, true);
|
|
96
|
+
};
|
|
97
|
+
go(root, pointer, false);
|
|
98
|
+
}
|
|
99
|
+
function parameters(doc, o) {
|
|
100
|
+
const list = Array.isArray(o.op.parameters) ? o.op.parameters : [];
|
|
101
|
+
return list.flatMap((p, i) => {
|
|
102
|
+
let param = p;
|
|
103
|
+
if (isObj(p) && typeof p.$ref === "string" && p.$ref.startsWith("#/components/parameters/")) {
|
|
104
|
+
param = component(doc, "parameters", p.$ref.slice("#/components/parameters/".length));
|
|
105
|
+
}
|
|
106
|
+
if (!isObj(param) || typeof param.name !== "string")
|
|
107
|
+
return [];
|
|
108
|
+
return [{ name: param.name, in: String(param.in), schema: param.schema, pointer: `${o.pointer}/parameters/${i}` }];
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function bodySchemas(container, pointer) {
|
|
112
|
+
if (!isObj(container) || !isObj(container.content))
|
|
113
|
+
return [];
|
|
114
|
+
return Object.entries(container.content).flatMap(([media, m]) => isObj(m) && m.schema !== undefined ? [{ schema: m.schema, pointer: `${pointer}/content/${esc(media)}/schema` }] : []);
|
|
115
|
+
}
|
|
116
|
+
function responseSchemas(o, onlySuccess) {
|
|
117
|
+
if (!isObj(o.op.responses))
|
|
118
|
+
return [];
|
|
119
|
+
return Object.entries(o.op.responses).flatMap(([status, r]) => onlySuccess && !/^2\d\d$/.test(status) ? [] : bodySchemas(r, `${o.pointer}/responses/${esc(status)}`));
|
|
120
|
+
}
|
|
121
|
+
/** What a caller sends in. For a webhook, the receiver's reply is what comes back in. */
|
|
122
|
+
function inputs(doc, o) {
|
|
123
|
+
if (o.kind === "webhook")
|
|
124
|
+
return responseSchemas(o, false);
|
|
125
|
+
return [
|
|
126
|
+
...parameters(doc, o).map((p) => ({ schema: p.schema, pointer: p.pointer })),
|
|
127
|
+
...bodySchemas(o.op.requestBody, `${o.pointer}/requestBody`),
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
/** What goes out. For a webhook, its payload. */
|
|
131
|
+
function outputs(o) {
|
|
132
|
+
if (o.kind === "webhook")
|
|
133
|
+
return bodySchemas(o.op.requestBody, `${o.pointer}/requestBody`);
|
|
134
|
+
return responseSchemas(o, false);
|
|
135
|
+
}
|
|
136
|
+
/** Every structural name in the document: paths, operations, tags, parameters, properties, schema names, enum values. */
|
|
137
|
+
function names(doc) {
|
|
138
|
+
const out = [];
|
|
139
|
+
for (const [kind, section] of [
|
|
140
|
+
["paths", doc.paths],
|
|
141
|
+
["webhooks", doc.webhooks],
|
|
142
|
+
]) {
|
|
143
|
+
if (!isObj(section))
|
|
144
|
+
continue;
|
|
145
|
+
for (const key of Object.keys(section)) {
|
|
146
|
+
for (const segment of key.split(/[/.]/).filter(Boolean))
|
|
147
|
+
out.push({ kind: "path-segment", name: segment, where: `/${kind}/${esc(key)}` });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const o of operations(doc)) {
|
|
151
|
+
if (typeof o.op.operationId === "string")
|
|
152
|
+
out.push({ kind: "operation", name: o.op.operationId, where: o.pointer });
|
|
153
|
+
if (Array.isArray(o.op.tags))
|
|
154
|
+
for (const t of o.op.tags)
|
|
155
|
+
if (typeof t === "string")
|
|
156
|
+
out.push({ kind: "tag", name: t, where: o.pointer });
|
|
157
|
+
for (const p of parameters(doc, o))
|
|
158
|
+
out.push({ kind: "parameter", name: p.name, where: p.pointer, schema: p.schema });
|
|
159
|
+
}
|
|
160
|
+
const schemas = isObj(doc.components) && isObj(doc.components.schemas) ? doc.components.schemas : {};
|
|
161
|
+
for (const name of Object.keys(schemas))
|
|
162
|
+
out.push({ kind: "schema", name, where: `/components/schemas/${esc(name)}` });
|
|
163
|
+
const deep = (node, at) => {
|
|
164
|
+
if (Array.isArray(node)) {
|
|
165
|
+
node.forEach((v, i) => deep(v, `${at}/${i}`));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (!isObj(node))
|
|
169
|
+
return;
|
|
170
|
+
if (isObj(node.properties)) {
|
|
171
|
+
for (const [k, v] of Object.entries(node.properties))
|
|
172
|
+
out.push({ kind: "property", name: k, where: `${at}/properties/${esc(k)}`, schema: v });
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(node.enum))
|
|
175
|
+
for (const v of node.enum)
|
|
176
|
+
if (typeof v === "string")
|
|
177
|
+
out.push({ kind: "enum-value", name: v, where: `${at}/enum` });
|
|
178
|
+
if (typeof node.const === "string")
|
|
179
|
+
out.push({ kind: "enum-value", name: node.const, where: `${at}/const` });
|
|
180
|
+
for (const [k, v] of Object.entries(node)) {
|
|
181
|
+
if (k.startsWith("x-") || k === "description" || k === "example" || k === "examples" || k === "securitySchemes")
|
|
182
|
+
continue;
|
|
183
|
+
deep(v, `${at}/${esc(k)}`);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
deep(doc.paths, "/paths");
|
|
187
|
+
deep(doc.webhooks, "/webhooks");
|
|
188
|
+
deep(doc.components, "/components");
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
const isPersonSide = (schema) => {
|
|
192
|
+
if (refName(schema) === PERSON_SIDE_SCHEMA)
|
|
193
|
+
return true;
|
|
194
|
+
if (isObj(schema) && schema["x-indorania-person-side"] === true)
|
|
195
|
+
return true;
|
|
196
|
+
// A nullable person-side id is generated as anyOf [ref, null].
|
|
197
|
+
if (isObj(schema) && Array.isArray(schema.anyOf)) {
|
|
198
|
+
const ids = schema.anyOf.filter((s) => !(isObj(s) && s.type === "null"));
|
|
199
|
+
return ids.length === 1 && isPersonSide(ids[0]);
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Format identifiers are not names a client must learn: URIs, media types, and versioned format
|
|
205
|
+
* tags such as `kashscript-ask/1`, which attest requires verbatim.
|
|
206
|
+
*/
|
|
207
|
+
const isIdentifierValue = (value) => /^[a-z][a-z0-9+.-]*:\/\//i.test(value) || /^[a-z]+\/[a-z0-9.+-]+$/i.test(value) || /^[a-z0-9.-]+\/\d+$/i.test(value);
|
|
208
|
+
function isCollectionShape(doc, schema) {
|
|
209
|
+
let node = schema;
|
|
210
|
+
const ref = refName(node);
|
|
211
|
+
if (ref === ENVELOPE_SCHEMA)
|
|
212
|
+
return false;
|
|
213
|
+
if (ref)
|
|
214
|
+
node = component(doc, "schemas", ref);
|
|
215
|
+
if (!isObj(node))
|
|
216
|
+
return false;
|
|
217
|
+
if (node.type === "array")
|
|
218
|
+
return true;
|
|
219
|
+
if (isObj(node.properties) && "next" in node.properties) {
|
|
220
|
+
const items = node.properties.items;
|
|
221
|
+
const resolved = refName(items) ? component(doc, "schemas", refName(items) ?? "") : items;
|
|
222
|
+
return isObj(resolved) && resolved.type === "array";
|
|
223
|
+
}
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
export function checkOpenApi(document, options = {}) {
|
|
227
|
+
const doc = document;
|
|
228
|
+
const findings = [];
|
|
229
|
+
const add = (rule, where, why) => findings.push({ rule, where, why });
|
|
230
|
+
const allNames = names(doc);
|
|
231
|
+
// ── no-origin-fields ─────────────────────────────────────────────────────────────────────
|
|
232
|
+
for (const n of allNames) {
|
|
233
|
+
const hit = hasToken(n.name, ORIGIN_TOKENS);
|
|
234
|
+
if (hit)
|
|
235
|
+
add("no-origin-fields", n.where, `${n.kind} "${n.name}" names ${hit}`);
|
|
236
|
+
}
|
|
237
|
+
// ── no-cross-relationship-joins ──────────────────────────────────────────────────────────
|
|
238
|
+
const personSide = component(doc, "schemas", PERSON_SIDE_SCHEMA);
|
|
239
|
+
if (!personSide || personSide["x-indorania-person-side"] !== true) {
|
|
240
|
+
add("no-cross-relationship-joins", `/components/schemas/${PERSON_SIDE_SCHEMA}`, "the person-side identifier component is missing or unmarked, so nothing below could be checked");
|
|
241
|
+
}
|
|
242
|
+
for (const n of allNames) {
|
|
243
|
+
if (n.kind !== "property" && n.kind !== "parameter")
|
|
244
|
+
continue;
|
|
245
|
+
const hit = hasToken(n.name, PERSON_TOKENS);
|
|
246
|
+
if (hit && !isPersonSide(n.schema))
|
|
247
|
+
add("no-cross-relationship-joins", n.where, `${n.kind} "${n.name}" names a person (${hit}) but is not a ${PERSON_SIDE_SCHEMA}`);
|
|
248
|
+
}
|
|
249
|
+
for (const o of operations(doc)) {
|
|
250
|
+
const id = String(o.op.operationId ?? o.pointer);
|
|
251
|
+
let count = 0;
|
|
252
|
+
let listed = false;
|
|
253
|
+
for (const root of inputs(doc, o)) {
|
|
254
|
+
walk(doc, root.schema, root.pointer, (_node, at) => {
|
|
255
|
+
if (!at.personSide)
|
|
256
|
+
return;
|
|
257
|
+
count += 1;
|
|
258
|
+
if (at.inArray)
|
|
259
|
+
listed = true;
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (listed)
|
|
263
|
+
add("no-cross-relationship-joins", o.pointer, `${id} takes a list of person-side ids`);
|
|
264
|
+
else if (count > 1)
|
|
265
|
+
add("no-cross-relationship-joins", o.pointer, `${id} takes ${count} person-side ids in one request`);
|
|
266
|
+
let returnsOrgList = false;
|
|
267
|
+
for (const root of outputs(o)) {
|
|
268
|
+
walk(doc, root.schema, root.pointer, (_node, at) => {
|
|
269
|
+
if (at.personSide && at.inArray) {
|
|
270
|
+
add("no-cross-relationship-joins", `${o.pointer} → ${at.pointer}`, `${id} returns person-side ids in a list`);
|
|
271
|
+
add("no-house-member-list", `${o.pointer} → ${at.pointer}`, `${id} returns a list of person-side ids`);
|
|
272
|
+
}
|
|
273
|
+
if (at.ref === ORGANISATION_ID_SCHEMA && at.inArray)
|
|
274
|
+
returnsOrgList = true;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
// ── no-house-member-list: "which houses is Y in" ─────────────────────────────────────
|
|
278
|
+
if (count > 0 && returnsOrgList)
|
|
279
|
+
add("no-house-member-list", o.pointer, `${id} takes a person-side id and returns a list of organisations`);
|
|
280
|
+
if (o.kind === "path" && o.method === "get") {
|
|
281
|
+
for (const segment of o.key.split("/").filter(Boolean)) {
|
|
282
|
+
const hit = hasToken(segment, MEMBERSHIP_TOKENS);
|
|
283
|
+
if (hit)
|
|
284
|
+
add("no-house-member-list", o.pointer, `a read's path names ${hit}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
for (const n of allNames) {
|
|
289
|
+
if (n.kind !== "property" && n.kind !== "schema" && n.kind !== "parameter")
|
|
290
|
+
continue;
|
|
291
|
+
const hit = hasToken(n.name, MEMBERSHIP_NOUNS);
|
|
292
|
+
if (hit)
|
|
293
|
+
add("no-house-member-list", n.where, `${n.kind} "${n.name}" names ${hit}; staff are seats, and house members are never modelled`);
|
|
294
|
+
}
|
|
295
|
+
// ── collections-allowlisted ──────────────────────────────────────────────────────────────
|
|
296
|
+
const allow = new Set(options.collections ?? COLLECTIONS);
|
|
297
|
+
const seen = new Set();
|
|
298
|
+
for (const o of operations(doc)) {
|
|
299
|
+
if (o.kind !== "path" || o.method !== "get")
|
|
300
|
+
continue;
|
|
301
|
+
const id = String(o.op.operationId ?? o.pointer);
|
|
302
|
+
seen.add(id);
|
|
303
|
+
const declared = typeof o.op["x-indorania-collection"] === "string";
|
|
304
|
+
const shaped = responseSchemas(o, true).some((r) => isCollectionShape(doc, r.schema));
|
|
305
|
+
if (!declared && !shaped)
|
|
306
|
+
continue;
|
|
307
|
+
if (!allow.has(id))
|
|
308
|
+
add("collections-allowlisted", o.pointer, `${id} returns a list but is not on the allowlist`);
|
|
309
|
+
if (shaped && !declared)
|
|
310
|
+
add("collections-allowlisted", o.pointer, `${id} returns a list without saying why (x-indorania-collection)`);
|
|
311
|
+
for (const p of parameters(doc, o)) {
|
|
312
|
+
if (p.in === "query" && !COLLECTION_QUERY.has(p.name))
|
|
313
|
+
add("collections-allowlisted", p.pointer, `${id} narrows its list by "${p.name}" — a list is paged, never searched`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
for (const id of allow)
|
|
317
|
+
if (!seen.has(id))
|
|
318
|
+
add("collections-allowlisted", "/paths", `allowlisted ${id} is not a read in this document`);
|
|
319
|
+
// ── no-volume-meter ──────────────────────────────────────────────────────────────────────
|
|
320
|
+
for (const o of operations(doc)) {
|
|
321
|
+
if (!Array.isArray(o.op.tags) || !o.op.tags.includes("entitlements"))
|
|
322
|
+
continue;
|
|
323
|
+
for (const root of [...inputs(doc, o), ...outputs(o)]) {
|
|
324
|
+
walk(doc, root.schema, root.pointer, (node, at) => {
|
|
325
|
+
if (!isObj(node.properties))
|
|
326
|
+
return;
|
|
327
|
+
for (const k of Object.keys(node.properties)) {
|
|
328
|
+
const hit = hasToken(k, METER_TOKENS);
|
|
329
|
+
if (hit)
|
|
330
|
+
add("no-volume-meter", `${at.pointer}/properties/${esc(k)}`, `entitlement field "${k}" meters ${hit}; capacity is what costs work, volume never is`);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// ── no-decline-trace · no-member-names · no-score-or-balance · no-secret-material ───────
|
|
336
|
+
for (const n of allNames) {
|
|
337
|
+
const decline = hasToken(n.name, DECLINE_TOKENS);
|
|
338
|
+
if (decline)
|
|
339
|
+
add("no-decline-trace", n.where, `${n.kind} "${n.name}" names ${decline}`);
|
|
340
|
+
if (!(n.kind === "enum-value" && isIdentifierValue(n.name))) {
|
|
341
|
+
const member = hasToken(n.name, MEMBER_NAMES);
|
|
342
|
+
if (member)
|
|
343
|
+
add("no-member-names", n.where, `${n.kind} "${n.name}" names a member (${member})`);
|
|
344
|
+
}
|
|
345
|
+
if (n.kind === "property" || n.kind === "parameter") {
|
|
346
|
+
const score = hasToken(n.name, SCORE_TOKENS);
|
|
347
|
+
if (score)
|
|
348
|
+
add("no-score-or-balance", n.where, `${n.kind} "${n.name}" names ${score}`);
|
|
349
|
+
const secret = hasToken(n.name, SECRET_TOKENS);
|
|
350
|
+
if (secret)
|
|
351
|
+
add("no-secret-material", n.where, `${n.kind} "${n.name}" names ${secret}`);
|
|
352
|
+
if (n.kind === "property" && n.name === "d")
|
|
353
|
+
add("no-secret-material", n.where, `a property named "d" is a private JWK parameter`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const voucher = new Set((options.voucherFields ?? []).map((f) => f.toLowerCase()));
|
|
357
|
+
if (voucher.size > 0) {
|
|
358
|
+
for (const o of operations(doc)) {
|
|
359
|
+
if (!Array.isArray(o.op.tags) || !o.op.tags.includes("thank-yous"))
|
|
360
|
+
continue;
|
|
361
|
+
for (const root of [...inputs(doc, o), ...outputs(o)]) {
|
|
362
|
+
walk(doc, root.schema, root.pointer, (node, at) => {
|
|
363
|
+
if (!isObj(node.properties))
|
|
364
|
+
return;
|
|
365
|
+
for (const k of Object.keys(node.properties)) {
|
|
366
|
+
if (voucher.has(k.toLowerCase()))
|
|
367
|
+
add("no-score-or-balance", `${at.pointer}/properties/${esc(k)}`, `a thank-you carries "${k}", which could add up`);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return summarise(findings);
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../src/constitution/openapi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** The shape every constitutional check reports in, and a plain-text rendering of it. */
|
|
2
|
+
export declare const RULES: {
|
|
3
|
+
readonly "no-origin-fields": {
|
|
4
|
+
readonly required: true;
|
|
5
|
+
readonly title: "No origin, ethnicity, sect, caste or descent field anywhere (d36; content rule 2)";
|
|
6
|
+
};
|
|
7
|
+
readonly "no-cross-relationship-joins": {
|
|
8
|
+
readonly required: true;
|
|
9
|
+
readonly title: "Nothing joins a person across relationships: person-side ids are relationship ids, one at a time (d41, d47(g))";
|
|
10
|
+
};
|
|
11
|
+
readonly "no-house-member-list": {
|
|
12
|
+
readonly required: true;
|
|
13
|
+
readonly title: "Nothing lists a house's members, or the houses a person is in (d47(c))";
|
|
14
|
+
};
|
|
15
|
+
readonly "collections-allowlisted": {
|
|
16
|
+
readonly required: false;
|
|
17
|
+
readonly title: "Only allowlisted reads return lists; none answers \"everything matching X\" (d41; PL-4 edge 3)";
|
|
18
|
+
};
|
|
19
|
+
readonly "no-volume-meter": {
|
|
20
|
+
readonly required: false;
|
|
21
|
+
readonly title: "Entitlements carry capacity only — no meter, counter or price per record (d50; PL-4 edge 5)";
|
|
22
|
+
};
|
|
23
|
+
readonly "no-decline-trace": {
|
|
24
|
+
readonly required: false;
|
|
25
|
+
readonly title: "A decline has no endpoint, state or field (d49(a); PL-4 edge 6)";
|
|
26
|
+
};
|
|
27
|
+
readonly "no-member-names": {
|
|
28
|
+
readonly required: false;
|
|
29
|
+
readonly title: "No member is named in structure — members appear as capabilities (PL-4 edge 7)";
|
|
30
|
+
};
|
|
31
|
+
readonly "no-score-or-balance": {
|
|
32
|
+
readonly required: false;
|
|
33
|
+
readonly title: "No score, rank, percentage or balance; thank-yous never add up (d27, d43, d49)";
|
|
34
|
+
};
|
|
35
|
+
readonly "no-secret-material": {
|
|
36
|
+
readonly required: false;
|
|
37
|
+
readonly title: "No private key, secret or seed in any field (d47(g))";
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export type RuleId = keyof typeof RULES;
|
|
41
|
+
export interface Finding {
|
|
42
|
+
readonly rule: RuleId;
|
|
43
|
+
/** A JSON pointer into the OpenAPI document, or `schema.table.column`. */
|
|
44
|
+
readonly where: string;
|
|
45
|
+
readonly why: string;
|
|
46
|
+
}
|
|
47
|
+
/** A finding someone has reviewed and accepted, with the reason — printed in every report, never silent. */
|
|
48
|
+
export interface AcceptedFinding extends Finding {
|
|
49
|
+
readonly reason: string;
|
|
50
|
+
}
|
|
51
|
+
export interface RuleResult {
|
|
52
|
+
readonly id: RuleId;
|
|
53
|
+
readonly required: boolean;
|
|
54
|
+
readonly title: string;
|
|
55
|
+
readonly findings: readonly Finding[];
|
|
56
|
+
/** Findings a reviewer accepted, each with its reason. They do not fail the rule. */
|
|
57
|
+
readonly accepted: readonly AcceptedFinding[];
|
|
58
|
+
}
|
|
59
|
+
/** One result per rule that applies — by default, every rule. */
|
|
60
|
+
export declare function summarise(findings: readonly Finding[], applicable?: readonly RuleId[], accepted?: readonly AcceptedFinding[]): RuleResult[];
|
|
61
|
+
export declare function formatReport(heading: string, results: readonly RuleResult[]): string;
|
|
62
|
+
export declare function passed(results: readonly RuleResult[]): boolean;
|
|
63
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/constitution/report.ts"],"names":[],"mappings":"AAAA,yFAAyF;AAEzF,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCR,CAAC;AAEX,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,KAAK,CAAC;AAExC,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,4GAA4G;AAC5G,MAAM,WAAW,eAAgB,SAAQ,OAAO;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;AAED,iEAAiE;AACjE,wBAAgB,SAAS,CACvB,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,UAAU,GAAE,SAAS,MAAM,EAAmC,EAC9D,QAAQ,GAAE,SAAS,eAAe,EAAO,GACxC,UAAU,EAAE,CAYd;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAWpF;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAE9D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** The shape every constitutional check reports in, and a plain-text rendering of it. */
|
|
2
|
+
export const RULES = {
|
|
3
|
+
"no-origin-fields": {
|
|
4
|
+
required: true,
|
|
5
|
+
title: "No origin, ethnicity, sect, caste or descent field anywhere (d36; content rule 2)",
|
|
6
|
+
},
|
|
7
|
+
"no-cross-relationship-joins": {
|
|
8
|
+
required: true,
|
|
9
|
+
title: "Nothing joins a person across relationships: person-side ids are relationship ids, one at a time (d41, d47(g))",
|
|
10
|
+
},
|
|
11
|
+
"no-house-member-list": {
|
|
12
|
+
required: true,
|
|
13
|
+
title: "Nothing lists a house's members, or the houses a person is in (d47(c))",
|
|
14
|
+
},
|
|
15
|
+
"collections-allowlisted": {
|
|
16
|
+
required: false,
|
|
17
|
+
title: "Only allowlisted reads return lists; none answers \"everything matching X\" (d41; PL-4 edge 3)",
|
|
18
|
+
},
|
|
19
|
+
"no-volume-meter": {
|
|
20
|
+
required: false,
|
|
21
|
+
title: "Entitlements carry capacity only — no meter, counter or price per record (d50; PL-4 edge 5)",
|
|
22
|
+
},
|
|
23
|
+
"no-decline-trace": {
|
|
24
|
+
required: false,
|
|
25
|
+
title: "A decline has no endpoint, state or field (d49(a); PL-4 edge 6)",
|
|
26
|
+
},
|
|
27
|
+
"no-member-names": {
|
|
28
|
+
required: false,
|
|
29
|
+
title: "No member is named in structure — members appear as capabilities (PL-4 edge 7)",
|
|
30
|
+
},
|
|
31
|
+
"no-score-or-balance": {
|
|
32
|
+
required: false,
|
|
33
|
+
title: "No score, rank, percentage or balance; thank-yous never add up (d27, d43, d49)",
|
|
34
|
+
},
|
|
35
|
+
"no-secret-material": {
|
|
36
|
+
required: false,
|
|
37
|
+
title: "No private key, secret or seed in any field (d47(g))",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/** One result per rule that applies — by default, every rule. */
|
|
41
|
+
export function summarise(findings, applicable = Object.keys(RULES), accepted = []) {
|
|
42
|
+
return applicable.map((id) => {
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
const own = findings.filter((f) => {
|
|
45
|
+
if (f.rule !== id)
|
|
46
|
+
return false;
|
|
47
|
+
const key = `${f.where}\u0000${f.why}`;
|
|
48
|
+
if (seen.has(key))
|
|
49
|
+
return false;
|
|
50
|
+
seen.add(key);
|
|
51
|
+
return true;
|
|
52
|
+
});
|
|
53
|
+
return { id, required: RULES[id].required, title: RULES[id].title, findings: own, accepted: accepted.filter((a) => a.rule === id) };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export function formatReport(heading, results) {
|
|
57
|
+
const lines = [heading, ""];
|
|
58
|
+
for (const r of results) {
|
|
59
|
+
const mark = r.findings.length === 0 ? "PASS" : "FAIL";
|
|
60
|
+
lines.push(`${mark} ${r.id}${r.required ? "" : " (also checked)"} — ${r.title}`);
|
|
61
|
+
for (const f of r.findings)
|
|
62
|
+
lines.push(` ${f.where}: ${f.why}`);
|
|
63
|
+
for (const a of r.accepted)
|
|
64
|
+
lines.push(` ACCEPTED ${a.where}: ${a.why} — ${a.reason}`);
|
|
65
|
+
}
|
|
66
|
+
const failed = results.filter((r) => r.findings.length > 0).length;
|
|
67
|
+
lines.push("", failed === 0 ? `All ${results.length} rules pass.` : `${failed} of ${results.length} rules fail.`);
|
|
68
|
+
return lines.join("\n");
|
|
69
|
+
}
|
|
70
|
+
export function passed(results) {
|
|
71
|
+
return results.every((r) => r.findings.length === 0);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/constitution/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The constitution, checked against a database schema — described as plain data, so it works for
|
|
3
|
+
* any ORM. `@indorania/db` builds this model from its Drizzle tables; a member can build one from
|
|
4
|
+
* its own.
|
|
5
|
+
*/
|
|
6
|
+
import { type RuleId, type RuleResult } from "./report.ts";
|
|
7
|
+
export interface ColumnModel {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
/** e.g. "text", "jsonb", "timestamp with time zone". */
|
|
10
|
+
readonly sqlType: string;
|
|
11
|
+
readonly notNull: boolean;
|
|
12
|
+
readonly enumValues?: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export interface ForeignKeyModel {
|
|
15
|
+
readonly columns: readonly string[];
|
|
16
|
+
readonly foreignSchema: string;
|
|
17
|
+
readonly foreignTable: string;
|
|
18
|
+
}
|
|
19
|
+
export interface TableModel {
|
|
20
|
+
readonly schema: string;
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly columns: readonly ColumnModel[];
|
|
23
|
+
readonly foreignKeys: readonly ForeignKeyModel[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Every json column says what it holds. Party content — anything a person's or a counterparty's
|
|
27
|
+
* encounter produced — may only sit in a table that expires, so the platform keeps no store of it.
|
|
28
|
+
*/
|
|
29
|
+
export interface JsonColumnClass {
|
|
30
|
+
/** `schema.table.column` */
|
|
31
|
+
readonly column: string;
|
|
32
|
+
readonly holds: "party-content" | "configuration";
|
|
33
|
+
readonly reason: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A finding a reviewer has accepted, by rule and column, with the reason. For columns a library
|
|
37
|
+
* defines and we cannot rename (an identity library's `password`, held empty by a CHECK constraint).
|
|
38
|
+
* An exception that no longer matches a finding fails the check, so a stale one cannot linger.
|
|
39
|
+
*/
|
|
40
|
+
export interface AcceptedColumn {
|
|
41
|
+
/** `schema.table.column` */
|
|
42
|
+
readonly column: string;
|
|
43
|
+
readonly rule: RuleId;
|
|
44
|
+
readonly reason: string;
|
|
45
|
+
}
|
|
46
|
+
export interface DbModel {
|
|
47
|
+
readonly tables: readonly TableModel[];
|
|
48
|
+
readonly jsonColumns: readonly JsonColumnClass[];
|
|
49
|
+
readonly accepted?: readonly AcceptedColumn[];
|
|
50
|
+
}
|
|
51
|
+
export declare const EXPIRY_COLUMN = "expires_at";
|
|
52
|
+
export declare function checkTables(model: DbModel): RuleResult[];
|
|
53
|
+
//# sourceMappingURL=tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../src/constitution/tables.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAwD,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAajH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;CAClD;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,CAAC;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAID,eAAO,MAAM,aAAa,eAAe,CAAC;AAE1C,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,EAAE,CAmFxD"}
|