@lovrozagar/oat 0.12.14 → 0.12.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/conformance/suite.d.ts.map +1 -1
  2. package/dist/conformance/suite.js +2 -0
  3. package/dist/conformance/suite.js.map +1 -1
  4. package/dist/reference/defects.d.ts +4 -0
  5. package/dist/reference/defects.d.ts.map +1 -1
  6. package/dist/reference/defects.js +4 -0
  7. package/dist/reference/defects.js.map +1 -1
  8. package/dist/reference/http.d.ts.map +1 -1
  9. package/dist/reference/http.js +27 -3
  10. package/dist/reference/http.js.map +1 -1
  11. package/dist/reference/spec.d.ts.map +1 -1
  12. package/dist/reference/spec.js +81 -1
  13. package/dist/reference/spec.js.map +1 -1
  14. package/dist/report/console.d.ts.map +1 -1
  15. package/dist/report/console.js +2 -1
  16. package/dist/report/console.js.map +1 -1
  17. package/dist/runtime/check-costs.d.ts.map +1 -1
  18. package/dist/runtime/check-costs.js +2 -0
  19. package/dist/runtime/check-costs.js.map +1 -1
  20. package/dist/runtime/check-ids.d.ts +1 -1
  21. package/dist/runtime/check-ids.d.ts.map +1 -1
  22. package/dist/runtime/check-ids.js +3 -0
  23. package/dist/runtime/check-ids.js.map +1 -1
  24. package/dist/runtime/checks.d.ts.map +1 -1
  25. package/dist/runtime/checks.js +4 -0
  26. package/dist/runtime/checks.js.map +1 -1
  27. package/dist/runtime/disposable.d.ts +31 -0
  28. package/dist/runtime/disposable.d.ts.map +1 -0
  29. package/dist/runtime/disposable.js +168 -0
  30. package/dist/runtime/disposable.js.map +1 -0
  31. package/dist/runtime/root-read.d.ts +20 -0
  32. package/dist/runtime/root-read.d.ts.map +1 -0
  33. package/dist/runtime/root-read.js +66 -0
  34. package/dist/runtime/root-read.js.map +1 -0
  35. package/dist/runtime/run.d.ts.map +1 -1
  36. package/dist/runtime/run.js +41 -1
  37. package/dist/runtime/run.js.map +1 -1
  38. package/dist/runtime/scope.d.ts.map +1 -1
  39. package/dist/runtime/scope.js +3 -0
  40. package/dist/runtime/scope.js.map +1 -1
  41. package/dist/runtime/self.d.ts +4 -2
  42. package/dist/runtime/self.d.ts.map +1 -1
  43. package/dist/runtime/self.js +53 -6
  44. package/dist/runtime/self.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `x-destructive` runs as a second user registered through the spec, never the suite caller.
3
+ * Afterwards the suite caller's own read still returns 200. When the operation invalidates
4
+ * that read, the disposable credential's next read is 401.
5
+ */
6
+ import type { Check } from "./checks.ts";
7
+ import type { Client } from "./client.ts";
8
+ import { type FindingCollector } from "./finding.ts";
9
+ import type { OperationModel, SpecModel } from "../spec/graph.ts";
10
+ import type { GradeLedger } from "./scope.ts";
11
+ import type { Hooks, PrincipalAuth } from "../config/define-config.ts";
12
+ export declare const DISPOSABLE_CHECK_ID: "auth.destructive-spares-the-caller";
13
+ export declare function destructiveOps(model: SpecModel): OperationModel[];
14
+ export declare function signupOperationId(auth: PrincipalAuth | undefined): string | undefined;
15
+ export declare function runDisposableOps(input: {
16
+ auth: () => Record<string, string>;
17
+ client: Client;
18
+ findings: FindingCollector;
19
+ checksRun?: Set<string>;
20
+ grades: GradeLedger;
21
+ inScope: (operationId: string) => boolean;
22
+ mode: "full" | "targeted";
23
+ model: SpecModel;
24
+ nonce?: string;
25
+ /** The suite principal's signup operation, when its auth flow names one. */
26
+ registerOperationId?: string;
27
+ resolveInput?: Hooks["resolveInput"];
28
+ seed?: number;
29
+ }): Promise<void>;
30
+ export declare const disposableCheck: Check;
31
+ //# sourceMappingURL=disposable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposable.d.ts","sourceRoot":"","sources":["../../src/runtime/disposable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAY,KAAK,gBAAgB,EAAgB,MAAM,cAAc,CAAA;AAE5E,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAI7C,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAEtE,eAAO,MAAM,mBAAmB,sCAAkE,CAAA;AAIlG,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,EAAE,CAEjE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMrF;AA0CD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC7C,IAAI,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACvB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAA;IACzC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;IACzB,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,YAAY,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IACpC,IAAI,CAAC,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,IAAI,CAAC,CA8GhB;AAcD,eAAO,MAAM,eAAe,EAAE,KAQ7B,CAAA"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * `x-destructive` runs as a second user registered through the spec, never the suite caller.
3
+ * Afterwards the suite caller's own read still returns 200. When the operation invalidates
4
+ * that read, the disposable credential's next read is 401.
5
+ */
6
+ import { ASSERTED } from "./finding.js";
7
+ import { buildCohort, isOverflowError } from "./fixture.js";
8
+ import { applyResolveInput } from "./input.js";
9
+ import { requestSchemaOf } from "./world.js";
10
+ export const DISPOSABLE_CHECK_ID = "auth.destructive-spares-the-caller";
11
+ const REGISTER_LIKE = /register|sign[-_]?up/i;
12
+ export function destructiveOps(model) {
13
+ return model.operations.filter((op) => op.destructive);
14
+ }
15
+ export function signupOperationId(auth) {
16
+ if (auth === undefined || !("steps" in auth))
17
+ return undefined;
18
+ for (const step of auth.steps) {
19
+ if ("operationId" in step && typeof step.operationId === "string")
20
+ return step.operationId;
21
+ }
22
+ return undefined;
23
+ }
24
+ function looksLikeSignup(op) {
25
+ if (/passkey/i.test(op.operationId) || /passkey/i.test(op.path))
26
+ return false;
27
+ return REGISTER_LIKE.test(op.operationId) || REGISTER_LIKE.test(op.path);
28
+ }
29
+ function registerOperation(model, preferredId) {
30
+ const preferred = preferredId === undefined ? undefined : model.byOperationId.get(preferredId);
31
+ if (preferred !== undefined && (preferred.freshPrincipal || looksLikeSignup(preferred)))
32
+ return preferred;
33
+ return model.operations.find((op) => op.freshPrincipal || looksLikeSignup(op));
34
+ }
35
+ function callerRead(model) {
36
+ const reads = model.operations.filter((op) => op.identity === "self" && op.action === "read" && op.pathParams.length === 0);
37
+ return (reads.find((op) => op.operationId === "auth.getProfile" || op.path === "/v1/auth/me" || op.path === "/v1/me") ??
38
+ reads[0]);
39
+ }
40
+ function requiredSchema(schema) {
41
+ const required = Array.isArray(schema.required)
42
+ ? schema.required.filter((name) => typeof name === "string")
43
+ : [];
44
+ if (required.length === 0)
45
+ return schema;
46
+ const properties = schema.properties;
47
+ if (properties === null || typeof properties !== "object" || Array.isArray(properties))
48
+ return schema;
49
+ const source = properties;
50
+ const picked = {};
51
+ for (const name of required)
52
+ if (name in source)
53
+ picked[name] = source[name];
54
+ return { ...schema, properties: picked, required };
55
+ }
56
+ function tokenOf(body) {
57
+ if (body === null || typeof body !== "object")
58
+ return null;
59
+ const token = body.access_token;
60
+ return typeof token === "string" && token !== "" ? token : null;
61
+ }
62
+ export async function runDisposableOps(input) {
63
+ const ops = destructiveOps(input.model).filter((op) => input.mode === "full" || input.inScope(op.operationId));
64
+ if (ops.length === 0)
65
+ return;
66
+ input.checksRun?.add(DISPOSABLE_CHECK_ID);
67
+ const ids = ops.map((op) => op.operationId);
68
+ const register = registerOperation(input.model, input.registerOperationId);
69
+ const read = callerRead(input.model);
70
+ if (register === undefined || read === undefined) {
71
+ const reason = register === undefined ? "no register operation" : "no caller read";
72
+ input.grades.skipped(ids, reason);
73
+ return;
74
+ }
75
+ const schema = requestSchemaOf(register, input.model);
76
+ let body = {};
77
+ if (schema !== null) {
78
+ try {
79
+ const [member] = buildCohort(requiredSchema(schema), input.seed ?? 1, ["baseline"], register.operationId, input.nonce === undefined ? {} : { nonce: input.nonce });
80
+ body = member?.body ?? {};
81
+ }
82
+ catch (error) {
83
+ if (!isOverflowError(error))
84
+ throw error;
85
+ input.grades.skipped(ids, error instanceof Error ? error.message : "register body could not be generated");
86
+ return;
87
+ }
88
+ if (input.resolveInput !== undefined) {
89
+ body = await applyResolveInput(body, register.operationId, schema, input.resolveInput);
90
+ }
91
+ }
92
+ const signed = await input.client.request(register.method, register.path, {
93
+ body,
94
+ headers: {},
95
+ operationId: register.operationId,
96
+ });
97
+ const token = tokenOf(signed.responseBody);
98
+ const issued = signed.responseBody !== null && typeof signed.responseBody === "object"
99
+ ? signed.responseBody
100
+ : {};
101
+ if (signed.status < 200 || signed.status >= 300 || token === null) {
102
+ input.findings
103
+ .attributed(ids)
104
+ .ownedBy(DISPOSABLE_CHECK_ID)
105
+ .backend(DISPOSABLE_CHECK_ID, read.entity ?? "caller", "the disposable signup failed", `${register.operationId} returned ${signed.status}.`, [signed]);
106
+ input.grades.graded(ids, DISPOSABLE_CHECK_ID);
107
+ return;
108
+ }
109
+ const disposable = { authorization: `Bearer ${token}` };
110
+ for (const op of ops) {
111
+ const blame = input.findings.attributed([op.operationId]).ownedBy(DISPOSABLE_CHECK_ID);
112
+ const sent = bodyFrom(requestSchemaOf(op, input.model), issued);
113
+ const called = await input.client.request(op.method, op.path, {
114
+ ...(Object.keys(sent).length === 0 ? {} : { body: sent }),
115
+ headers: disposable,
116
+ operationId: op.operationId,
117
+ });
118
+ if (called.status < 200 || called.status >= 300) {
119
+ blame.backend(DISPOSABLE_CHECK_ID, op.entity ?? read.entity ?? "caller", "the disposable call failed", `${op.operationId} returned ${called.status} for the second user.`, [signed, called]);
120
+ input.grades.graded([op.operationId], DISPOSABLE_CHECK_ID);
121
+ continue;
122
+ }
123
+ const caller = await input.client.request(read.method, read.path, {
124
+ headers: input.auth,
125
+ operationId: read.operationId,
126
+ });
127
+ if (caller.status !== 200) {
128
+ blame.backend(DISPOSABLE_CHECK_ID, read.entity ?? "caller", "the suite caller was logged out", `${op.operationId} ran as the second user, and the suite ${read.operationId} then returned ${caller.status}.`, [called, caller]);
129
+ input.grades.graded([op.operationId], DISPOSABLE_CHECK_ID);
130
+ continue;
131
+ }
132
+ const endsSession = op.invalidates.some((route) => route.endsWith(read.path));
133
+ if (endsSession) {
134
+ const gone = await input.client.request(read.method, read.path, {
135
+ headers: disposable,
136
+ operationId: read.operationId,
137
+ });
138
+ if (gone.status !== 401) {
139
+ blame.backend(DISPOSABLE_CHECK_ID, op.entity ?? read.entity ?? "caller", "the disposable session was still accepted", `${op.operationId} invalidates ${read.operationId}, and that read then returned ${gone.status} with the second user's credential.`, [called, gone]);
140
+ }
141
+ }
142
+ input.grades.graded([op.operationId], DISPOSABLE_CHECK_ID);
143
+ }
144
+ }
145
+ function bodyFrom(schema, issued) {
146
+ if (schema === null)
147
+ return {};
148
+ const properties = schema.properties;
149
+ if (properties === null || typeof properties !== "object" || Array.isArray(properties))
150
+ return {};
151
+ const body = {};
152
+ for (const name of Object.keys(properties)) {
153
+ const value = issued[name];
154
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
155
+ body[name] = value;
156
+ }
157
+ return body;
158
+ }
159
+ export const disposableCheck = {
160
+ id: DISPOSABLE_CHECK_ID,
161
+ mutates: true,
162
+ needs: "x-destructive, a register operation, and a caller read",
163
+ plan: () => ({ ok: false }),
164
+ run: () => Promise.resolve(ASSERTED),
165
+ /* Destructive routes have no entity. `runDisposableOps` grades them after the entity loop. */
166
+ subjects: () => [],
167
+ };
168
+ //# sourceMappingURL=disposable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposable.js","sourceRoot":"","sources":["../../src/runtime/disposable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `x-entity.identity: root` — the path id is the signed-up caller's root.
3
+ * No list and no create. No token is a 401. The authed read uses that root.
4
+ */
5
+ import type { Check } from "./checks.ts";
6
+ import type { Client } from "./client.ts";
7
+ import { type FindingCollector, type Outcome } from "./finding.ts";
8
+ import type { EntityModel, SpecModel } from "../spec/graph.ts";
9
+ export declare const ROOT_READ_CHECK_ID: "read.matches-caller-root";
10
+ export declare function rootReadIds(entity: EntityModel): string[];
11
+ export declare function runRootRead(input: {
12
+ auth: () => Record<string, string>;
13
+ client: Client;
14
+ entity: EntityModel;
15
+ findings: FindingCollector;
16
+ model: SpecModel;
17
+ roots: Record<string, string>;
18
+ }): Promise<Outcome>;
19
+ export declare const rootReadCheck: Check;
20
+ //# sourceMappingURL=root-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-read.d.ts","sourceRoot":"","sources":["../../src/runtime/root-read.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAY,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAG9D,eAAO,MAAM,kBAAkB,4BAAwD,CAAA;AAEvF,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAIzD;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE;IACxC,IAAI,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,WAAW,CAAA;IACnB,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC7B,GAAG,OAAO,CAAC,OAAO,CAAC,CA4CnB;AAUD,eAAO,MAAM,aAAa,EAAE,KAO3B,CAAA"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * `x-entity.identity: root` — the path id is the signed-up caller's root.
3
+ * No list and no create. No token is a 401. The authed read uses that root.
4
+ */
5
+ import { ASSERTED } from "./finding.js";
6
+ import { fillPath } from "./world.js";
7
+ export const ROOT_READ_CHECK_ID = "read.matches-caller-root";
8
+ export function rootReadIds(entity) {
9
+ if (entity.identity !== "root")
10
+ return [];
11
+ if (entity.reads !== undefined && entity.reads.length > 0)
12
+ return entity.reads;
13
+ return entity.read === undefined ? [] : [entity.read];
14
+ }
15
+ export async function runRootRead(input) {
16
+ const ids = rootReadIds(input.entity);
17
+ const findings = input.findings.attributed(ids).ownedBy(ROOT_READ_CHECK_ID);
18
+ for (const id of ids) {
19
+ const op = input.model.byOperationId.get(id);
20
+ if (op === undefined)
21
+ continue;
22
+ let path;
23
+ try {
24
+ path = fillPath(op.path, input.roots);
25
+ }
26
+ catch {
27
+ return findings.unresolved(ROOT_READ_CHECK_ID, input.entity.name, `${op.operationId} needs a path id`);
28
+ }
29
+ const query = dateWindow(op.queryParamNames);
30
+ const anonymous = await input.client.request(op.method, path, {
31
+ headers: {},
32
+ operationId: op.operationId,
33
+ ...(query === undefined ? {} : { query }),
34
+ skipAuthRefresh: true,
35
+ });
36
+ if (anonymous.status !== 401) {
37
+ return findings.security(ROOT_READ_CHECK_ID, input.entity.name, "the parent read answered without a token", `${op.operationId} returned ${anonymous.status} with no credential.`, [anonymous]);
38
+ }
39
+ const read = await input.client.request(op.method, path, {
40
+ headers: input.auth,
41
+ operationId: op.operationId,
42
+ ...(query === undefined ? {} : { query }),
43
+ });
44
+ if (read.status !== 200) {
45
+ return findings.backend(ROOT_READ_CHECK_ID, input.entity.name, "the parent read failed", `${op.operationId} returned ${read.status} for ${path}.`, [anonymous, read]);
46
+ }
47
+ }
48
+ return ASSERTED;
49
+ }
50
+ /** `from` is a week before `to` when a read asks for both. */
51
+ function dateWindow(names) {
52
+ if (!names.includes("from") || !names.includes("to"))
53
+ return undefined;
54
+ const to = new Date();
55
+ const from = new Date(to.getTime() - 7 * 24 * 60 * 60 * 1000);
56
+ return { from: from.toISOString(), to: to.toISOString() };
57
+ }
58
+ export const rootReadCheck = {
59
+ id: ROOT_READ_CHECK_ID,
60
+ needs: "x-entity.identity: root and a read",
61
+ plan: () => ({ ok: false }),
62
+ run: () => Promise.resolve(ASSERTED),
63
+ /* The entity loop calls `runRootRead` and returns. This entry keeps the id registered. */
64
+ subjects: () => [],
65
+ };
66
+ //# sourceMappingURL=root-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-read.js","sourceRoot":"","sources":["../../src/runtime/root-read.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runtime/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runtime/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAc,KAAK,WAAW,EAAuB,KAAK,SAAS,EAAqB,MAAM,kBAAkB,CAAA;AAEvH,OAAO,KAAK,EACX,YAAY,EACZ,KAAK,EACL,UAAU,EACV,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,OAAO,EACP,MAAM,4BAA4B,CAAA;AAGnC,OAAO,EAIN,KAAK,WAAW,EAMhB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,KAAK,kBAAkB,EAA2C,MAAM,iBAAiB,CAAA;AAMlG,OAAO,EAEN,MAAM,EAKN,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,eAAe,EAAoD,MAAM,eAAe,CAAA;AACtG,OAAO,EAAE,KAAK,OAAO,EAAoB,KAAK,YAAY,EAA6B,MAAM,cAAc,CAAA;AAG3G,OAAO,EAMN,KAAK,WAAW,EAGhB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAgBvE,MAAM,MAAM,aAAa,GAAG,SAAS,CAAA;AAErC,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;IACd,iGAAiG;IACjG,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACtC,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iFAAiF;IACjF,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4FAA4F;IAC5F,UAAU,CAAC,EAAE,aAAa,EAAE,CAAA;IAC5B,+FAA+F;IAC/F,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,qEAAqE;IACrE,OAAO,CAAC,EAAE,UAAU,EAAE,CAAA;IACtB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,4FAA4F;IAC5F,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,sCAAsC;IACtC,KAAK,CAAC,EAAE,iBAAiB,CAAA;IACzB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACvC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,oEAAoE;QACpE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KACzB,CAAA;CACD;AAED,yFAAyF;AACzF,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,gGAAgG;IAChG,aAAa,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACtE;;;;;;;OAOG;IACH,gBAAgB,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3E;;;OAGG;IACH,gBAAgB,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1D,0EAA0E;IAC1E,YAAY,EAAE,YAAY,EAAE,CAAA;IAC5B,gEAAgE;IAChE,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,4EAA4E;IAC5E,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClE,oGAAoG;IACpG,OAAO,EAAE,MAAM,CAAA;IACf,mGAAmG;IACnG,iBAAiB,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjF,mGAAmG;IACnG,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAA;IAC/B,6GAA6G;IAC7G,UAAU,EAAE,kBAAkB,EAAE,CAAA;IAChC,mEAAmE;IACnE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+CAA+C;IAC/C,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7B,8FAA8F;IAC9F,OAAO,CAAC,EAAE;QACT,IAAI,EAAE,WAAW,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,OAAO,CAAA;QACnB,GAAG,EAAE,MAAM,CAAA;KACX,CAAA;CACD;AA4LD,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAwyCjE;AAgHD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,EAAE,CAwC/F"}
@@ -16,6 +16,8 @@ import { resolveBackoff } from "./poll.js";
16
16
  import { persistedToPrincipal, snapshotPrincipal } from "./principals.js";
17
17
  import { CHECKS } from "./checks.js";
18
18
  import { runPublicGets } from "./one-shot.js";
19
+ import { runDisposableOps, signupOperationId } from "./disposable.js";
20
+ import { rootReadIds, ROOT_READ_CHECK_ID, runRootRead } from "./root-read.js";
19
21
  import { entityIsSelf, runSelfIdentity, SELF_CHECK_ID, selfOperationIds } from "./self.js";
20
22
  import { AuthRefreshError, Client, } from "./client.js";
21
23
  import { FindingCollector, isRootCause } from "./finding.js";
@@ -501,6 +503,29 @@ export async function run(options) {
501
503
  const testEntity = async (entity) => {
502
504
  const listOp = model.byOperationId.get(entity.list ?? "");
503
505
  const createOp = model.byOperationId.get(entity.create ?? "");
506
+ /* The path id is the caller's root. Nothing to create. */
507
+ if (listOp === undefined && rootReadIds(entity).length > 0) {
508
+ entitiesTested.push(entity.name);
509
+ currentEntity = entity.name;
510
+ currentCheck = ROOT_READ_CHECK_ID;
511
+ currentPhase = "test";
512
+ const ops = rootReadIds(entity);
513
+ checksRun.add(ROOT_READ_CHECK_ID);
514
+ const outcome = await runRootRead({
515
+ auth: alpha.headers,
516
+ client,
517
+ entity,
518
+ findings,
519
+ model,
520
+ roots: { ...options.roots, ...alpha.roots },
521
+ });
522
+ if (outcome.kind === "stood-down" || outcome.kind === "unresolved") {
523
+ grades.skipped(ops, outcome.reason);
524
+ return;
525
+ }
526
+ grades.graded(ops, ROOT_READ_CHECK_ID);
527
+ return;
528
+ }
504
529
  /* The caller is the record. Nothing to list, and register is not a create. */
505
530
  if (listOp === undefined) {
506
531
  if (!entityIsSelf(entity))
@@ -509,7 +534,7 @@ export async function run(options) {
509
534
  currentEntity = entity.name;
510
535
  currentCheck = SELF_CHECK_ID;
511
536
  currentPhase = "test";
512
- const ops = selfOperationIds(entity);
537
+ const ops = selfOperationIds(entity, model);
513
538
  checksRun.add(SELF_CHECK_ID);
514
539
  const outcome = await runSelfIdentity({
515
540
  auth: alpha.headers,
@@ -1205,6 +1230,21 @@ export async function run(options) {
1205
1230
  * was created is still removed below, and the report still written. */
1206
1231
  findings.blocked("run.error", "run", "testing stopped on an unexpected error", errorText(error));
1207
1232
  }
1233
+ const registerOperationId = signupOperationId(options.principals[0]?.auth);
1234
+ await runDisposableOps({
1235
+ auth: alpha.headers,
1236
+ checksRun,
1237
+ client,
1238
+ findings,
1239
+ grades,
1240
+ inScope: (operationId) => runScope.inScope(operationId),
1241
+ mode: runScope.mode,
1242
+ model,
1243
+ nonce,
1244
+ ...(registerOperationId === undefined ? {} : { registerOperationId }),
1245
+ ...(hooks.resolveInput === undefined ? {} : { resolveInput: hooks.resolveInput }),
1246
+ seed,
1247
+ });
1208
1248
  /* Unwind after every check has run, never per case: a check may legitimately depend on records
1209
1249
  * another one created, and tearing down early turns that into a phantom defect. */
1210
1250
  currentPhase = "teardown";