@lovrozagar/oat 0.6.1 → 0.7.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 +148 -21
- package/dist/cli.js +7 -0
- package/dist/config/define-config.d.ts +95 -1
- package/dist/config/define-config.d.ts.map +1 -1
- package/dist/config/define-config.js +6 -0
- package/dist/config/define-config.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/report/console.d.ts.map +1 -1
- package/dist/report/console.js +2 -0
- package/dist/report/console.js.map +1 -1
- package/dist/report/render.d.ts.map +1 -1
- package/dist/report/render.js +4 -2
- package/dist/report/render.js.map +1 -1
- package/dist/runtime/auth.d.ts +22 -2
- package/dist/runtime/auth.d.ts.map +1 -1
- package/dist/runtime/auth.js +129 -16
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/body.d.ts.map +1 -1
- package/dist/runtime/body.js +6 -3
- package/dist/runtime/body.js.map +1 -1
- package/dist/runtime/checks.d.ts +6 -0
- package/dist/runtime/checks.d.ts.map +1 -1
- package/dist/runtime/checks.js +103 -4
- package/dist/runtime/checks.js.map +1 -1
- package/dist/runtime/client.d.ts +8 -2
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js +42 -10
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/finding.d.ts +2 -0
- package/dist/runtime/finding.d.ts.map +1 -1
- package/dist/runtime/finding.js.map +1 -1
- package/dist/runtime/input.d.ts +7 -0
- package/dist/runtime/input.d.ts.map +1 -0
- package/dist/runtime/input.js +46 -0
- package/dist/runtime/input.js.map +1 -0
- package/dist/runtime/poll.d.ts +29 -0
- package/dist/runtime/poll.d.ts.map +1 -0
- package/dist/runtime/poll.js +59 -0
- package/dist/runtime/poll.js.map +1 -0
- package/dist/runtime/principals.d.ts +29 -0
- package/dist/runtime/principals.d.ts.map +1 -0
- package/dist/runtime/principals.js +97 -0
- package/dist/runtime/principals.js.map +1 -0
- package/dist/runtime/rate-limit.d.ts +40 -2
- package/dist/runtime/rate-limit.d.ts.map +1 -1
- package/dist/runtime/rate-limit.js +115 -4
- package/dist/runtime/rate-limit.js.map +1 -1
- package/dist/runtime/run.d.ts +10 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +119 -23
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/upload.d.ts +1 -0
- package/dist/runtime/upload.d.ts.map +1 -1
- package/dist/runtime/upload.js.map +1 -1
- package/dist/runtime/wait.d.ts +32 -0
- package/dist/runtime/wait.d.ts.map +1 -0
- package/dist/runtime/wait.js +125 -0
- package/dist/runtime/wait.js.map +1 -0
- package/dist/runtime/world.d.ts +16 -0
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +91 -0
- package/dist/runtime/world.js.map +1 -1
- package/dist/spec/extensions.d.ts +16 -0
- package/dist/spec/extensions.d.ts.map +1 -1
- package/dist/spec/extensions.js +24 -1
- package/dist/spec/extensions.js.map +1 -1
- package/dist/spec/graph.d.ts +2 -1
- package/dist/spec/graph.d.ts.map +1 -1
- package/dist/spec/graph.js +2 -1
- package/dist/spec/graph.js.map +1 -1
- package/package.json +4 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/runtime/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,KAAK,EAAkB,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjE,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;IACnD,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX;
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/runtime/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,KAAK,EAAkB,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjE,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;IACnD,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX;;;2BAGuB;IACvB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAA;CACrC;AA0DD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,GAC/C,qBAAqB,EAAE,CAuCzB;AAED,sGAAsG;AACtG,eAAO,MAAM,uBAAuB,mBAAmB,CAAA;AACvD,eAAO,MAAM,iBAAiB,aAAa,CAAA;AAE3C,iGAAiG;AACjG,eAAO,MAAM,eAAe,IAAI,CAAA;AAChC,eAAO,MAAM,wBAAwB,OAAQ,CAAA;AAC7C,eAAO,MAAM,oBAAoB,QAAS,CAAA;AAG1C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAa,GAAG,MAAM,GAAG,IAAI,CAU1F;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM,CAK3G;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7F;AAMD;;;;GAIG;AACH,qBAAa,UAAU;IAMV,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,KAAK,CAAmC;gBAEnB,GAAG,EAAE,MAAM;IAIxC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO9B,6FAA6F;IACvF,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;CA0BjC;AAED,qGAAqG;AACrG,qBAAa,WAAW;IAKX,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJlC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4B;gBAE7B,KAAK,EAAE,SAAS,qBAAqB,EAAE;IAEpE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS;IAI5E;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS;IAW/D;;;OAGG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,qBAAqB;IAiBpF,sFAAsF;IAChF,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ9C,OAAO,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5D,OAAO,CAAC,SAAS;CAQjB"}
|
|
@@ -107,6 +107,51 @@ export function buildRateLimitRules(model, configRules) {
|
|
|
107
107
|
}
|
|
108
108
|
return rules;
|
|
109
109
|
}
|
|
110
|
+
/** Writes that never declared `x-rate-limit` still share a real backend budget (JWT writes, etc.). */
|
|
111
|
+
export const UNTAGGED_WRITE_CATEGORY = "untagged-write";
|
|
112
|
+
export const UNTAGGED_CATEGORY = "untagged";
|
|
113
|
+
/** Extra attempts after the first 429. The first 429 is never a seed/check failure by itself. */
|
|
114
|
+
export const MAX_429_RETRIES = 5;
|
|
115
|
+
export const RETRY_BACKOFF_INITIAL_MS = 1_000;
|
|
116
|
+
export const RETRY_BACKOFF_CAP_MS = 30_000;
|
|
117
|
+
const WRITE_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
118
|
+
/**
|
|
119
|
+
* `Retry-After` as a wait in ms. Delta-seconds or HTTP-date; anything unparseable is `null`
|
|
120
|
+
* so the caller can fall back to exponential backoff. Capped so a tester cannot hang for an hour.
|
|
121
|
+
*/
|
|
122
|
+
export function parseRetryAfter(value, now = Date.now()) {
|
|
123
|
+
if (value === undefined)
|
|
124
|
+
return null;
|
|
125
|
+
const trimmed = value.trim();
|
|
126
|
+
if (trimmed === "")
|
|
127
|
+
return null;
|
|
128
|
+
if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
|
|
129
|
+
return Math.min(RETRY_BACKOFF_CAP_MS, Math.max(0, Number(trimmed) * 1000));
|
|
130
|
+
}
|
|
131
|
+
const date = Date.parse(trimmed);
|
|
132
|
+
if (Number.isNaN(date))
|
|
133
|
+
return null;
|
|
134
|
+
return Math.min(RETRY_BACKOFF_CAP_MS, Math.max(0, date - now));
|
|
135
|
+
}
|
|
136
|
+
/** Wait before retry `attempt` (0-based) of a 429. Header wins; otherwise 1s, 2s, 4s… capped. */
|
|
137
|
+
export function retryWaitMs(retryAfterHeader, attempt, now = Date.now()) {
|
|
138
|
+
const parsed = parseRetryAfter(retryAfterHeader, now);
|
|
139
|
+
if (parsed !== null)
|
|
140
|
+
return parsed;
|
|
141
|
+
const exp = RETRY_BACKOFF_INITIAL_MS * 2 ** Math.max(0, attempt);
|
|
142
|
+
return Math.min(RETRY_BACKOFF_CAP_MS, exp);
|
|
143
|
+
}
|
|
144
|
+
export function headerValue(headers, name) {
|
|
145
|
+
const want = name.toLowerCase();
|
|
146
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
147
|
+
if (key.toLowerCase() === want)
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
function implicitCategory(method) {
|
|
153
|
+
return WRITE_METHODS.has(method.toUpperCase()) ? UNTAGGED_WRITE_CATEGORY : UNTAGGED_CATEGORY;
|
|
154
|
+
}
|
|
110
155
|
/**
|
|
111
156
|
* A token bucket with a queue: concurrent requests against the same category are admitted one at
|
|
112
157
|
* a time, each computing its wait from the bucket's current state rather than racing on it.
|
|
@@ -116,21 +161,37 @@ export class RateBucket {
|
|
|
116
161
|
rps;
|
|
117
162
|
tokens;
|
|
118
163
|
last = performance.now();
|
|
164
|
+
cooldownUntil = 0;
|
|
119
165
|
queue = Promise.resolve();
|
|
120
166
|
constructor(rps) {
|
|
121
167
|
this.rps = rps;
|
|
122
168
|
this.tokens = rps;
|
|
123
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* A 429 said this budget is exhausted. Hold the next acquire for `waitMs`, then admit exactly
|
|
172
|
+
* one request — a full burst refill would immediately re-trip the limit we just hit.
|
|
173
|
+
*/
|
|
174
|
+
penalize(waitMs) {
|
|
175
|
+
const until = performance.now() + Math.max(0, waitMs);
|
|
176
|
+
this.cooldownUntil = Math.max(this.cooldownUntil, until);
|
|
177
|
+
this.tokens = 1;
|
|
178
|
+
this.last = this.cooldownUntil;
|
|
179
|
+
}
|
|
124
180
|
/** Resolves once a token is consumed. Returns `false` when the caller had to wait for it. */
|
|
125
181
|
async acquire() {
|
|
126
182
|
let hadRoom = false;
|
|
127
183
|
const previous = this.queue;
|
|
128
184
|
this.queue = previous.then(async () => {
|
|
129
185
|
const now = performance.now();
|
|
130
|
-
|
|
131
|
-
|
|
186
|
+
if (now < this.cooldownUntil) {
|
|
187
|
+
await new Promise((resolve) => setTimeout(resolve, this.cooldownUntil - now));
|
|
188
|
+
}
|
|
189
|
+
const after = performance.now();
|
|
190
|
+
this.tokens = Math.min(this.rps, this.tokens + ((after - this.last) / 1000) * this.rps);
|
|
191
|
+
this.last = after;
|
|
132
192
|
if (this.tokens >= 1) {
|
|
133
|
-
|
|
193
|
+
/* A cooldown wait is not room — oat did not believe it was under its own pace. */
|
|
194
|
+
hadRoom = now >= this.cooldownUntil;
|
|
134
195
|
this.tokens -= 1;
|
|
135
196
|
return;
|
|
136
197
|
}
|
|
@@ -138,6 +199,7 @@ export class RateBucket {
|
|
|
138
199
|
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
139
200
|
this.tokens = 0;
|
|
140
201
|
this.last = performance.now();
|
|
202
|
+
hadRoom = false;
|
|
141
203
|
});
|
|
142
204
|
await this.queue;
|
|
143
205
|
return hadRoom;
|
|
@@ -147,19 +209,68 @@ export class RateBucket {
|
|
|
147
209
|
export class RateLimiter {
|
|
148
210
|
rules;
|
|
149
211
|
buckets = new Map();
|
|
212
|
+
/** Cooldown-only: after an untagged 429, later untagged writes wait this out, then run free. */
|
|
213
|
+
implicitUntil = new Map();
|
|
150
214
|
constructor(rules) {
|
|
151
215
|
this.rules = rules;
|
|
152
216
|
}
|
|
153
217
|
resolve(method, pathname) {
|
|
154
218
|
return this.rules.find((rule) => rule.test(method, pathname));
|
|
155
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* After a 429 on an untagged route, later untagged writes share this cooldown so they do not
|
|
222
|
+
* immediately re-trip. No ongoing rps — we do not know the undocumented rate.
|
|
223
|
+
*/
|
|
224
|
+
implicitRule(method) {
|
|
225
|
+
const category = implicitCategory(method);
|
|
226
|
+
if (!this.implicitUntil.has(category))
|
|
227
|
+
return undefined;
|
|
228
|
+
return {
|
|
229
|
+
category,
|
|
230
|
+
rps: 0,
|
|
231
|
+
source: "implicit",
|
|
232
|
+
test: (m) => implicitCategory(m) === category,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Feed a 429 wait into the matching bucket, or open the implicit untagged cooldown when the
|
|
237
|
+
* operation never declared a rate. Tags stay the proactive path; this is the reactive one.
|
|
238
|
+
*/
|
|
239
|
+
noteBackoff(method, pathname, waitMs) {
|
|
240
|
+
const tagged = this.resolve(method, pathname);
|
|
241
|
+
if (tagged !== undefined) {
|
|
242
|
+
this.bucketFor(tagged).penalize(waitMs);
|
|
243
|
+
return tagged;
|
|
244
|
+
}
|
|
245
|
+
const category = implicitCategory(method);
|
|
246
|
+
const until = performance.now() + Math.max(0, waitMs);
|
|
247
|
+
this.implicitUntil.set(category, Math.max(this.implicitUntil.get(category) ?? 0, until));
|
|
248
|
+
return {
|
|
249
|
+
category,
|
|
250
|
+
rps: 0,
|
|
251
|
+
source: "implicit",
|
|
252
|
+
test: (m) => implicitCategory(m) === category,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/** Wait out an implicit 429 cooldown. Returns `false` when the caller had to wait. */
|
|
256
|
+
async waitImplicit(method) {
|
|
257
|
+
const until = this.implicitUntil.get(implicitCategory(method)) ?? 0;
|
|
258
|
+
const now = performance.now();
|
|
259
|
+
if (now >= until)
|
|
260
|
+
return true;
|
|
261
|
+
await new Promise((resolve) => setTimeout(resolve, until - now));
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
156
264
|
async acquire(rule) {
|
|
265
|
+
return this.bucketFor(rule).acquire();
|
|
266
|
+
}
|
|
267
|
+
bucketFor(rule) {
|
|
157
268
|
let bucket = this.buckets.get(rule.category);
|
|
158
269
|
if (bucket === undefined) {
|
|
159
270
|
bucket = new RateBucket(rule.rps);
|
|
160
271
|
this.buckets.set(rule.category, bucket);
|
|
161
272
|
}
|
|
162
|
-
return bucket
|
|
273
|
+
return bucket;
|
|
163
274
|
}
|
|
164
275
|
}
|
|
165
276
|
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/runtime/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/runtime/rate-limit.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/run.d.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* per case — which is what made prior attempts produce dozens of failures from one broken fixture.
|
|
7
7
|
*/
|
|
8
8
|
import { type SpecModel } from "../spec/graph.ts";
|
|
9
|
-
import type { Hooks, Principal, ProfileSpec, RateLimitSpec, Uploads } from "../config/define-config.ts";
|
|
9
|
+
import type { Hooks, OriginSpec, OutOfBandConfig, Principal, ProfileSpec, RateLimitSpec, Uploads } from "../config/define-config.ts";
|
|
10
|
+
import { type PersistedPrincipal } from "./principals.ts";
|
|
10
11
|
import { Client } from "./client.ts";
|
|
11
12
|
import type { ProgressHandler } from "./progress.ts";
|
|
12
13
|
import { type Finding, type Inconclusive } from "./finding.ts";
|
|
@@ -37,6 +38,12 @@ export interface RunOptions {
|
|
|
37
38
|
rateLimits?: RateLimitSpec[];
|
|
38
39
|
/** Live status. Called on phase/entity/check/request; the CLI prints a heartbeat from this. */
|
|
39
40
|
onProgress?: ProgressHandler;
|
|
41
|
+
/** Extra hosts with their own OpenAPI. Auth stays on the primary. */
|
|
42
|
+
origins?: OriginSpec[];
|
|
43
|
+
/** Backoff for `resolveOutOfBand` / `resolvePrincipalAuth`. */
|
|
44
|
+
outOfBand?: OutOfBandConfig;
|
|
45
|
+
/** Skip `teardownPrincipal` — used when this run is a secondary origin sharing accounts. */
|
|
46
|
+
skipPrincipalTeardown?: boolean;
|
|
40
47
|
}
|
|
41
48
|
export interface RunResult {
|
|
42
49
|
findings: Finding[];
|
|
@@ -75,6 +82,8 @@ export interface RunResult {
|
|
|
75
82
|
}>;
|
|
76
83
|
created: number;
|
|
77
84
|
teardown: TeardownReport | null;
|
|
85
|
+
/** Credentials as they stood after acquire — written to `oat-out/principals.json` by the CLI. */
|
|
86
|
+
principals: PersistedPrincipal[];
|
|
78
87
|
}
|
|
79
88
|
export declare function run(options: RunOptions): Promise<RunResult>;
|
|
80
89
|
//# sourceMappingURL=run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runtime/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEpG,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runtime/run.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/run.js
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { buildModel } from "../spec/graph.js";
|
|
9
9
|
import { dereference, loadSpec } from "../spec/load.js";
|
|
10
|
+
import { isAuthFlow } from "../config/define-config.js";
|
|
10
11
|
import { createPrincipal } from "./auth.js";
|
|
12
|
+
import { resolveBackoff } from "./poll.js";
|
|
13
|
+
import { persistedToPrincipal, snapshotPrincipal } from "./principals.js";
|
|
11
14
|
import { CHECKS } from "./checks.js";
|
|
12
15
|
import { Client } from "./client.js";
|
|
13
16
|
import { FindingCollector } from "./finding.js";
|
|
@@ -17,7 +20,7 @@ import { buildRateLimitRules, RateLimiter } from "./rate-limit.js";
|
|
|
17
20
|
import { Ledger } from "./teardown.js";
|
|
18
21
|
import { SchemaValidator } from "./validate.js";
|
|
19
22
|
import { isOverflowError, overflowFrom } from "./fixture.js";
|
|
20
|
-
import { SeedError, fillPath, probeCreateFixtures, resolveScope, seedCohort, } from "./world.js";
|
|
23
|
+
import { SeedError, fillPath, listExisting, probeCreateFixtures, resolveScope, seedCohort, } from "./world.js";
|
|
21
24
|
function readPointer(body, pointer) {
|
|
22
25
|
const path = pointer
|
|
23
26
|
.replace(/^\$\.?/, "")
|
|
@@ -103,7 +106,7 @@ function reportRateLimitViolations(client, findings) {
|
|
|
103
106
|
* rather than a snapshot is what lets a long run outlive a short-lived token — a five-minute TTL
|
|
104
107
|
* would otherwise turn the back half of every run into spurious 401s.
|
|
105
108
|
*/
|
|
106
|
-
async function resolvePrincipal(principal, model, client, hooks) {
|
|
109
|
+
async function resolvePrincipal(principal, model, client, hooks, outOfBand, originClients) {
|
|
107
110
|
const configured = principal.roots ?? {};
|
|
108
111
|
/* A principal without a flow authenticates by static header — a long-lived API key needs no
|
|
109
112
|
* acquisition at all, and forcing one would be ceremony. */
|
|
@@ -121,7 +124,9 @@ async function resolvePrincipal(principal, model, client, hooks) {
|
|
|
121
124
|
client,
|
|
122
125
|
hooks,
|
|
123
126
|
model,
|
|
127
|
+
outOfBand,
|
|
124
128
|
principalId: principal.id,
|
|
129
|
+
...(originClients === undefined ? {} : { originClients }),
|
|
125
130
|
});
|
|
126
131
|
/* A flow that provisions a tenant produces its own roots — the run then needs no fixture
|
|
127
132
|
* identifiers configured at all. */
|
|
@@ -157,28 +162,17 @@ async function readExisting(listOp, client, headers, roots) {
|
|
|
157
162
|
if (scope[param] === undefined)
|
|
158
163
|
return { records: [], scope };
|
|
159
164
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (exchange.status >= 300)
|
|
163
|
-
return { records: [], scope };
|
|
164
|
-
const body = exchange.responseBody;
|
|
165
|
-
const key = listOp.collection?.key ?? null;
|
|
166
|
-
const items = Array.isArray(body)
|
|
167
|
-
? body
|
|
168
|
-
: body !== null && typeof body === "object" && key !== null
|
|
169
|
-
? (body[key] ?? [])
|
|
170
|
-
: [];
|
|
171
|
-
return { records: Array.isArray(items) ? items : [], scope };
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
return { records: [], scope };
|
|
175
|
-
}
|
|
165
|
+
const records = await listExisting(listOp, client, headers, scope);
|
|
166
|
+
return { records, scope };
|
|
176
167
|
}
|
|
177
168
|
/** operationIds named in any principal `auth.steps` — those creates already ran during login. */
|
|
178
169
|
function authStepOperationIds(principals) {
|
|
179
170
|
const ids = new Set();
|
|
180
171
|
for (const principal of principals) {
|
|
181
|
-
|
|
172
|
+
const auth = principal.auth;
|
|
173
|
+
if (auth === undefined || !isAuthFlow(auth))
|
|
174
|
+
continue;
|
|
175
|
+
for (const step of auth.steps) {
|
|
182
176
|
if ("operationId" in step)
|
|
183
177
|
ids.add(step.operationId);
|
|
184
178
|
}
|
|
@@ -252,6 +246,7 @@ export async function run(options) {
|
|
|
252
246
|
if (!isOverflowError(error))
|
|
253
247
|
throw error;
|
|
254
248
|
}
|
|
249
|
+
const hooks = options.hooks ?? {};
|
|
255
250
|
const authCreates = authStepOperationIds(options.principals);
|
|
256
251
|
const rateLimiter = new RateLimiter(buildRateLimitRules(model, options.rateLimits));
|
|
257
252
|
const client = new Client(options.baseUrl, options.globalHeaders ?? {}, options.maxInFlight ?? 4, (exchange) => {
|
|
@@ -282,22 +277,26 @@ export async function run(options) {
|
|
|
282
277
|
snap.entityTotal = entityTotal;
|
|
283
278
|
publish(snap);
|
|
284
279
|
}, rateLimiter);
|
|
280
|
+
if (hooks.resolveHeaders !== undefined)
|
|
281
|
+
client.setResolveHeaders(hooks.resolveHeaders);
|
|
285
282
|
const validator = new SchemaValidator();
|
|
286
283
|
const ledger = new Ledger();
|
|
287
284
|
const seed = options.seed ?? 1;
|
|
285
|
+
const outOfBand = resolveBackoff(options.outOfBand);
|
|
288
286
|
if (options.principals[0] === undefined)
|
|
289
287
|
throw new Error("oat: at least one principal is required");
|
|
290
|
-
const
|
|
288
|
+
const originClients = await loadOriginClients(options.origins ?? [], hooks, options.maxInFlight ?? 4, options.globalHeaders ?? {});
|
|
291
289
|
const uploads = {
|
|
292
290
|
seed,
|
|
293
291
|
...(options.uploads === undefined ? {} : { uploads: options.uploads }),
|
|
294
292
|
...(options.configDir === undefined ? {} : { configDir: options.configDir }),
|
|
295
293
|
...(hooks.resolveUpload === undefined ? {} : { resolveUpload: hooks.resolveUpload }),
|
|
294
|
+
...(hooks.resolveInput === undefined ? {} : { resolveInput: hooks.resolveInput }),
|
|
296
295
|
};
|
|
297
296
|
const worldUploads = (seedOffset = 0) => seedOffset === 0 ? uploads : { ...uploads, seed: seed + seedOffset };
|
|
298
297
|
const resolved = [];
|
|
299
298
|
for (const principal of options.principals) {
|
|
300
|
-
resolved.push(await resolvePrincipal(principal, model, client, hooks));
|
|
299
|
+
resolved.push(await resolvePrincipal(principal, model, client, hooks, outOfBand, originClients.size === 0 ? undefined : originClients));
|
|
301
300
|
}
|
|
302
301
|
tick({
|
|
303
302
|
message: `${resolved.length} principal(s)`,
|
|
@@ -406,7 +405,26 @@ export async function run(options) {
|
|
|
406
405
|
seed,
|
|
407
406
|
uploads,
|
|
408
407
|
}, scope);
|
|
409
|
-
if (cohort.
|
|
408
|
+
if (cohort.adopted === true) {
|
|
409
|
+
/* Plan limit after an effect already created the row: keep the id so children
|
|
410
|
+
* (row after extract→table) can seed, but do not assert write-path oracles
|
|
411
|
+
* against a body oat never submitted. */
|
|
412
|
+
findings.gap("world.seed", entity.name, `seeding "${entity.name}" hit a plan limit; using an existing same-tenant record`, `${createOp.operationId} returned a plan-limit refusal and the list already ` +
|
|
413
|
+
"had a record — likely an earlier x-effects create. Write-path checks stand " +
|
|
414
|
+
"down rather than treat payment_required as a backend defect.");
|
|
415
|
+
records = cohort.records;
|
|
416
|
+
degraded = true;
|
|
417
|
+
for (const ancestor of scope.created) {
|
|
418
|
+
ledger.record(ancestor.entity, ancestor.id, scope.values);
|
|
419
|
+
}
|
|
420
|
+
for (const record of records) {
|
|
421
|
+
const id = record[entity.identity ?? "id"];
|
|
422
|
+
if (typeof id === "string" || typeof id === "number") {
|
|
423
|
+
ledger.record(entity.name, String(id), scope.values);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
else if (cohort.featureGate !== null) {
|
|
410
428
|
/* Same degradation a profile-excluded create takes: the tag said this
|
|
411
429
|
* principal cannot create the row, so a correct 403 is coverage, not a
|
|
412
430
|
* seed defect. The 403 body still has to match the documented schema. */
|
|
@@ -583,6 +601,9 @@ export async function run(options) {
|
|
|
583
601
|
altScope,
|
|
584
602
|
asyncOps: model.operations.filter((op) => op.entity === entity.name && op.async !== null && invocable(op)),
|
|
585
603
|
effectOps: model.operations.filter((op) => op.entity === entity.name && op.effects.length > 0 && invocable(op)),
|
|
604
|
+
waitOps: model.operations.filter((op) => op.entity === entity.name && op.wait !== null && invocable(op)),
|
|
605
|
+
hooks,
|
|
606
|
+
outOfBand,
|
|
586
607
|
auth: alpha.headers,
|
|
587
608
|
...(alpha.runtime === undefined ? {} : { refreshIfStale: alpha.runtime.refreshIfStale }),
|
|
588
609
|
client: trackingClient,
|
|
@@ -742,8 +763,23 @@ export async function run(options) {
|
|
|
742
763
|
findings.gap("world.teardown", teardown.unsupported.join(", "), "records created during the run could not be removed", `no delete operation is reachable for ${teardown.unsupported.join(", ")}, so this run left ` +
|
|
743
764
|
"fixtures behind. Declare x-cleanup to name the route that removes them.");
|
|
744
765
|
}
|
|
745
|
-
await teardownPrincipals(resolved, hooks, findings);
|
|
746
766
|
reportRateLimitViolations(client, findings);
|
|
767
|
+
for (const principal of resolved)
|
|
768
|
+
await principal.runtime?.refreshIfStale();
|
|
769
|
+
const persisted = resolved.map((principal) => snapshotPrincipal({
|
|
770
|
+
headers: principal.headers,
|
|
771
|
+
id: principal.id,
|
|
772
|
+
roots: principal.roots,
|
|
773
|
+
...(principal.role === undefined ? {} : { role: principal.role }),
|
|
774
|
+
rank: principal.rank,
|
|
775
|
+
...(principal.inviteAs === undefined ? {} : { inviteAs: principal.inviteAs }),
|
|
776
|
+
}));
|
|
777
|
+
if ((options.origins ?? []).length > 0 && options.skipPrincipalTeardown !== true) {
|
|
778
|
+
await runSecondaryOrigins(options, persisted, findings, checksRun, checksSkipped, checksSuppressed, entitiesTested);
|
|
779
|
+
}
|
|
780
|
+
if (options.skipPrincipalTeardown !== true) {
|
|
781
|
+
await teardownPrincipals(resolved, hooks, findings);
|
|
782
|
+
}
|
|
747
783
|
tick({
|
|
748
784
|
message: "done",
|
|
749
785
|
phase: "done",
|
|
@@ -759,9 +795,69 @@ export async function run(options) {
|
|
|
759
795
|
entitiesTested,
|
|
760
796
|
findings: findings.findings,
|
|
761
797
|
model,
|
|
798
|
+
principals: persisted,
|
|
762
799
|
profile: profile.name,
|
|
763
800
|
profileExclusions,
|
|
764
801
|
teardown,
|
|
765
802
|
};
|
|
766
803
|
}
|
|
804
|
+
async function loadOriginClients(origins, hooks, maxInFlight, globalHeaders) {
|
|
805
|
+
const map = new Map();
|
|
806
|
+
for (const origin of origins) {
|
|
807
|
+
const raw = await loadSpec(origin.spec, origin.baseUrl);
|
|
808
|
+
const { doc } = dereference(raw);
|
|
809
|
+
const originModel = buildModel(doc);
|
|
810
|
+
const originClient = new Client(origin.baseUrl, globalHeaders, maxInFlight);
|
|
811
|
+
if (hooks.resolveHeaders !== undefined)
|
|
812
|
+
originClient.setResolveHeaders(hooks.resolveHeaders);
|
|
813
|
+
map.set(origin.id, { client: originClient, model: originModel });
|
|
814
|
+
}
|
|
815
|
+
return map;
|
|
816
|
+
}
|
|
817
|
+
async function runSecondaryOrigins(options, persisted, findings, checksRun, checksSkipped, checksSuppressed, entitiesTested) {
|
|
818
|
+
for (const origin of options.origins ?? []) {
|
|
819
|
+
const originHooks = options.hooks === undefined
|
|
820
|
+
? undefined
|
|
821
|
+
: (() => {
|
|
822
|
+
const { teardownPrincipal: _removed, ...rest } = options.hooks;
|
|
823
|
+
return rest;
|
|
824
|
+
})();
|
|
825
|
+
const result = await run({
|
|
826
|
+
baseUrl: origin.baseUrl,
|
|
827
|
+
principals: persisted.map(persistedToPrincipal),
|
|
828
|
+
spec: origin.spec,
|
|
829
|
+
skipPrincipalTeardown: true,
|
|
830
|
+
...(originHooks === undefined ? {} : { hooks: originHooks }),
|
|
831
|
+
...(options.uploads === undefined ? {} : { uploads: options.uploads }),
|
|
832
|
+
...(options.configDir === undefined ? {} : { configDir: options.configDir }),
|
|
833
|
+
...(options.globalHeaders === undefined ? {} : { globalHeaders: options.globalHeaders }),
|
|
834
|
+
...(options.roots === undefined ? {} : { roots: options.roots }),
|
|
835
|
+
...(options.seed === undefined ? {} : { seed: options.seed }),
|
|
836
|
+
...(options.cohortSize === undefined ? {} : { cohortSize: options.cohortSize }),
|
|
837
|
+
...(options.only === undefined ? {} : { only: options.only }),
|
|
838
|
+
...(options.profiles === undefined ? {} : { profiles: options.profiles }),
|
|
839
|
+
...(options.profile === undefined ? {} : { profile: options.profile }),
|
|
840
|
+
...(options.rateLimits === undefined ? {} : { rateLimits: options.rateLimits }),
|
|
841
|
+
...(options.keepFixtures === undefined ? {} : { keepFixtures: options.keepFixtures }),
|
|
842
|
+
...(options.maxInFlight === undefined ? {} : { maxInFlight: options.maxInFlight }),
|
|
843
|
+
...(options.outOfBand === undefined ? {} : { outOfBand: options.outOfBand }),
|
|
844
|
+
...(options.onProgress === undefined ? {} : { onProgress: options.onProgress }),
|
|
845
|
+
});
|
|
846
|
+
for (const finding of result.findings) {
|
|
847
|
+
findings.report({ ...finding, origin: origin.id });
|
|
848
|
+
}
|
|
849
|
+
for (const check of result.checksRun)
|
|
850
|
+
checksRun.add(check);
|
|
851
|
+
for (const skip of result.checksSkipped)
|
|
852
|
+
checksSkipped.push({ ...skip, entity: `${origin.id}:${skip.entity}` });
|
|
853
|
+
for (const suppressed of result.checksSuppressed) {
|
|
854
|
+
checksSuppressed.push({ ...suppressed, entity: `${origin.id}:${suppressed.entity}` });
|
|
855
|
+
}
|
|
856
|
+
for (const entity of result.entitiesTested)
|
|
857
|
+
entitiesTested.push(`${origin.id}:${entity}`);
|
|
858
|
+
for (const item of result.inconclusive) {
|
|
859
|
+
findings.unresolved(item.check, `${origin.id}:${item.entity}`, item.reason);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
767
863
|
//# sourceMappingURL=run.js.map
|