@substrat-run/control-plane-api 0.160.0 → 0.161.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/dist/api.d.ts +8 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +105 -9
- package/dist/api.js.map +1 -1
- package/dist/cf-observability.d.ts.map +1 -1
- package/dist/cf-observability.js +31 -8
- package/dist/cf-observability.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/observability.d.ts +6 -2
- package/dist/observability.d.ts.map +1 -1
- package/dist/observability.js +1 -1
- package/dist/observability.js.map +1 -1
- package/dist/platform-drain.d.ts +26 -2
- package/dist/platform-drain.d.ts.map +1 -1
- package/dist/platform-drain.js +203 -88
- package/dist/platform-drain.js.map +1 -1
- package/dist/scope-copy-cleanup.js +1 -1
- package/dist/scope-copy-cleanup.js.map +1 -1
- package/dist/vertical-client.d.ts +58 -2
- package/dist/vertical-client.d.ts.map +1 -1
- package/dist/vertical-client.js +224 -21
- package/dist/vertical-client.js.map +1 -1
- package/dist/wire-settings.d.ts +77 -0
- package/dist/wire-settings.d.ts.map +1 -0
- package/dist/wire-settings.js +155 -0
- package/dist/wire-settings.js.map +1 -0
- package/dist/wire-upload.d.ts +26 -0
- package/dist/wire-upload.d.ts.map +1 -1
- package/dist/wire-upload.js +29 -2
- package/dist/wire-upload.js.map +1 -1
- package/dist/wire-walk.d.ts +140 -0
- package/dist/wire-walk.d.ts.map +1 -0
- package/dist/wire-walk.js +339 -0
- package/dist/wire-walk.js.map +1 -0
- package/package.json +9 -9
package/dist/api.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type { PlatformRuntime } from './platform-runtime.js';
|
|
|
17
17
|
import { type DoNamespaceReader } from './do-namespaces.js';
|
|
18
18
|
import type { DirectoryBackupStore, ScopeBackupStore } from './backups.js';
|
|
19
19
|
import { type WireUploadSettings } from './wire-upload.js';
|
|
20
|
+
import type { WireSettingsApi } from './wire-settings.js';
|
|
20
21
|
import { type LakeQueryEngine } from './lake-gateway.js';
|
|
21
22
|
import { type CustomHostnameProvisioner } from './custom-hostnames.js';
|
|
22
23
|
import { type SocialRelayOptions } from './social-relay.js';
|
|
@@ -163,6 +164,13 @@ export interface ControlPlaneApiOptions {
|
|
|
163
164
|
* unset, no upload gives anything, and each still records that it gave nothing.
|
|
164
165
|
*/
|
|
165
166
|
wireUpload?: WireUploadSettings;
|
|
167
|
+
/**
|
|
168
|
+
* RFC wire-signing follow-on 4: the namespace's script-settings endpoint, through which the fleet
|
|
169
|
+
* walk (`POST /wire-auth/walk`) brings a deployed script's four `SUBSTRAT_WIRE_*` settings to what
|
|
170
|
+
* `wireUpload` gives now, without uploading it again (`createWfpWireSettingsApi`). Absent, the walk
|
|
171
|
+
* answers 501.
|
|
172
|
+
*/
|
|
173
|
+
wireSettings?: WireSettingsApi;
|
|
166
174
|
/** #1722: how long a copy move owns its ledger entries, and so how long its restore may land
|
|
167
175
|
* (`CopyRestoreFence`). `SCOPE_COPY_LEASE_MS` unless a test needs a lease it can outlive. */
|
|
168
176
|
copyLeaseMs?: number;
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAE9G,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAsBL,KAAK,qBAAqB,EAqF1B,CAAC,EAeD,KAAK,cAAc,EAEnB,KAAK,uBAAuB,EAE7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAKV,UAAU,EACV,kBAAkB,EAGlB,wBAAwB,EACxB,oBAAoB,EAEpB,eAAe,EAKf,eAAe,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -67,7 +67,8 @@ import { parseTenantRequestQuery, parseTenantWindowQuery, refineTenantWindow, sc
|
|
|
67
67
|
import { namespacesForScript } from './do-namespaces.js';
|
|
68
68
|
import { backupDirectoryIfDue } from './directory-backup.js';
|
|
69
69
|
import { deployedDoClasses, platformSweeperDecision } from './platform-entry.js';
|
|
70
|
-
import { wireUploadFor } from './wire-upload.js';
|
|
70
|
+
import { wireSettingsRefusal, wireUploadFor } from './wire-upload.js';
|
|
71
|
+
import { parseWireWalkCursor, runWireWalk, WIRE_WALK_LIMIT_DEFAULT, WIRE_WALK_LIMIT_MAX, WIRE_WALK_RELEASE_MAX, } from './wire-walk.js';
|
|
71
72
|
import { STORAGE_PAGE_DEFAULT, STORAGE_PAGE_MAX, readStoragePage } from './storage-meter.js';
|
|
72
73
|
import { queryLakeEvents } from './lake-gateway.js';
|
|
73
74
|
import { LakeQueryError } from './r2-sql-engine.js';
|
|
@@ -3468,7 +3469,7 @@ export function createControlPlaneApi(options) {
|
|
|
3468
3469
|
};
|
|
3469
3470
|
/** Whether the scope's store in `holder` is a wiped copy: it holds the `carried_away` tombstone. */
|
|
3470
3471
|
const isCarriedAway = async (holder, scope) => {
|
|
3471
|
-
const page = await holder.
|
|
3472
|
+
const page = await holder.readTombstoneTable(scope.id, { table: '_substrat_meta', limit: 100, offset: 0 });
|
|
3472
3473
|
return metaValueIn(page.rows, page.columns, CARRIED_AWAY_KEY) !== null;
|
|
3473
3474
|
};
|
|
3474
3475
|
const recordCarryCleanup = (c, scope, versionId, stage, e) => {
|
|
@@ -3837,12 +3838,24 @@ export function createControlPlaneApi(options) {
|
|
|
3837
3838
|
return refuse(c, 'not_found', `unknown scope for tenant: (${tenantId}, ${scopeId})`);
|
|
3838
3839
|
// Health reads the scope the same way the Data view does, so it leaves the same
|
|
3839
3840
|
// row: an auditor should not be able to tell which route reached the tables.
|
|
3841
|
+
// #2544: a deployment that does not hold the scope refuses the table read. Health is the one
|
|
3842
|
+
// reader that wants the answer "nothing stored" for it: the scope has no role rows, which is
|
|
3843
|
+
// what `roleProjectionEmpty` reports for an active one, rather than a refusal of the whole route.
|
|
3844
|
+
let notHeld = false;
|
|
3840
3845
|
const tables = await delegatedRead(c, tenantId, scopeId, scope, 'listScopeTables', null, {
|
|
3841
3846
|
viaVertical: (v) => v.listScopeTables(scopeId),
|
|
3842
3847
|
colocated: () => c.var.admin.listScopeTables(c.get('actor'), tenantId, scopeId),
|
|
3843
|
-
}, (r) => r.length)
|
|
3848
|
+
}, (r) => r.length).catch((err) => {
|
|
3849
|
+
if (!isScopeNotHeld(err, scopeId))
|
|
3850
|
+
throw err;
|
|
3851
|
+
notHeld = true;
|
|
3852
|
+
return [];
|
|
3853
|
+
});
|
|
3844
3854
|
const roles = tables.find((t) => t.name === '_substrat_roles');
|
|
3845
|
-
|
|
3855
|
+
// #2531: the roles in force. A dropped role is kept as a tombstone, so the table's own row count
|
|
3856
|
+
// would read a projection that defines nothing as populated. A host from before tombstones
|
|
3857
|
+
// answers no `liveRowCount`, and kept none, so its `rowCount` is that count.
|
|
3858
|
+
const roleCount = notHeld ? 0 : roles ? (roles.liveRowCount ?? roles.rowCount) : null;
|
|
3846
3859
|
const roleProjectionEmpty = scope.status === 'active' && roleCount === 0;
|
|
3847
3860
|
const missingStores = scope.vertical
|
|
3848
3861
|
? await missingStoresForTenant({
|
|
@@ -8472,7 +8485,12 @@ export function createControlPlaneApi(options) {
|
|
|
8472
8485
|
});
|
|
8473
8486
|
// #1877: scoped to the app's own scripts — the scan and trust boundary.
|
|
8474
8487
|
const services = await appServices(c.get('actor'), input.tenantId, input.scopeId, input.vertical);
|
|
8475
|
-
|
|
8488
|
+
const { events, incomplete } = await options.observability.tenantLogs({ ...input, services });
|
|
8489
|
+
// The body stays the list every caller reads; a page that may be missing lines behind a cut
|
|
8490
|
+
// says so beside it, as `/observability/logs` does (#2521).
|
|
8491
|
+
if (incomplete)
|
|
8492
|
+
c.header(LOGS_INCOMPLETE_HEADER, '1');
|
|
8493
|
+
return c.json(events);
|
|
8476
8494
|
});
|
|
8477
8495
|
// #1331: one app's sampled field reports, joined to the router's own request lines.
|
|
8478
8496
|
app.get('/observability/tenant-field-coverage', async (c) => {
|
|
@@ -10461,19 +10479,19 @@ export function createControlPlaneApi(options) {
|
|
|
10461
10479
|
* `text/plain` beacon cannot set it without a CORS preflight, 415) and refuse a request a
|
|
10462
10480
|
* browser marks as from another origin (403). A request with neither header is the CLI's.
|
|
10463
10481
|
*/
|
|
10464
|
-
const byAPerson = async (c) => {
|
|
10482
|
+
const byAPerson = async (c, words = { write: 'a store driver release write', person: 'a store driver release is published by a person' }) => {
|
|
10465
10483
|
if (!/^application\/json\s*(;|$)/i.test(c.req.header('content-type') ?? '')) {
|
|
10466
|
-
throw new ControlPlaneError(415,
|
|
10484
|
+
throw new ControlPlaneError(415, `${words.write} takes application/json`);
|
|
10467
10485
|
}
|
|
10468
10486
|
const origin = c.req.header('origin');
|
|
10469
10487
|
const site = c.req.header('sec-fetch-site');
|
|
10470
10488
|
if ((origin && origin !== new URL(c.req.url).origin) || (site && site !== 'same-origin' && site !== 'none')) {
|
|
10471
|
-
throw new ControlPlaneError(403,
|
|
10489
|
+
throw new ControlPlaneError(403, `${words.write} is not taken from another origin`);
|
|
10472
10490
|
}
|
|
10473
10491
|
const actor = c.get('actor');
|
|
10474
10492
|
const person = options.humanStaffActor ? await options.humanStaffActor(c.req.raw) : null;
|
|
10475
10493
|
if (!person || person !== actor) {
|
|
10476
|
-
throw new ControlPlaneError(403,
|
|
10494
|
+
throw new ControlPlaneError(403, `${words.person}: this takes a staff sign-in, not a service token`);
|
|
10477
10495
|
}
|
|
10478
10496
|
return actor;
|
|
10479
10497
|
};
|
|
@@ -10637,8 +10655,86 @@ export function createControlPlaneApi(options) {
|
|
|
10637
10655
|
const again = ran.outcome === 'paused' || ran.outcome === 'held' || ran.outcome === 'busy';
|
|
10638
10656
|
return c.json({ pass: ran, rebuild }, again ? 202 : 200);
|
|
10639
10657
|
});
|
|
10658
|
+
// RFC wire-signing follow-on 4: one pass of the fleet walk, which brings every script's key lists,
|
|
10659
|
+
// audience and state to what this control plane gives now (`runWireWalk`). A person's act; a dry run
|
|
10660
|
+
// unless the body says `apply: true`; at most `limit` scripts, from `cursor`, answering where the next
|
|
10661
|
+
// pass starts. `release` names held scripts a person has looked at. Audited as `walkWireAuth`
|
|
10662
|
+
// however the pass ends. Not to be run while a push or promote of a walked vertical is in flight.
|
|
10663
|
+
app.post('/wire-auth/walk', async (c) => {
|
|
10664
|
+
const actor = await byAPerson(c, { write: 'a wire walk', person: 'the wire walk is run by a person' });
|
|
10665
|
+
const api = options.wireSettings;
|
|
10666
|
+
if (!api || !c.var.admin.listWireAuth || !c.var.admin.recordWireAuth || !c.var.admin.recordWireWalk) {
|
|
10667
|
+
throw new ControlPlaneError(501, 'this control plane does not walk the fleet’s wire settings');
|
|
10668
|
+
}
|
|
10669
|
+
const body = z
|
|
10670
|
+
.object({
|
|
10671
|
+
apply: z.boolean().optional(),
|
|
10672
|
+
confirm: z.boolean().optional(),
|
|
10673
|
+
cursor: z.string().min(1).max(512).optional(),
|
|
10674
|
+
limit: z.number().int().min(1).max(WIRE_WALK_LIMIT_MAX).optional(),
|
|
10675
|
+
release: z.array(z.string().min(1).max(255)).max(WIRE_WALK_RELEASE_MAX).optional(),
|
|
10676
|
+
})
|
|
10677
|
+
.strict()
|
|
10678
|
+
.parse(await readCappedJson(c.req.raw, WIRE_WALK_REQUEST_MAX_BYTES));
|
|
10679
|
+
const cursor = body.cursor === undefined ? null : parseWireWalkCursor(body.cursor);
|
|
10680
|
+
if (body.cursor !== undefined && cursor === null)
|
|
10681
|
+
throw new ControlPlaneError(422, 'the cursor is not one a pass answered');
|
|
10682
|
+
const apply = body.apply === true;
|
|
10683
|
+
const confirm = body.confirm === true;
|
|
10684
|
+
// Refused settings give every script nothing, which an applied pass would write as a fleet-wide
|
|
10685
|
+
// withdrawal: the pass is refused before it walks anything, dry or applied, and audited as such.
|
|
10686
|
+
const refused = await wireSettingsRefusal(options.wireUpload);
|
|
10687
|
+
if (refused) {
|
|
10688
|
+
await c.var.admin.recordWireWalk(actor, {
|
|
10689
|
+
apply, confirm, from: body.cursor ?? null, next: null, walked: 0,
|
|
10690
|
+
updated: [], held: [], released: [], skipped: [], failed: [],
|
|
10691
|
+
refused: `${refused.withheld}: ${refused.reason}`,
|
|
10692
|
+
});
|
|
10693
|
+
throw new ControlPlaneError(409, `the wire walk is refused: ${refused.withheld}: ${refused.reason}; fix the control plane's setting, then walk`);
|
|
10694
|
+
}
|
|
10695
|
+
// The pass puts each script's result here as it goes, so a pass that ends in an error is still
|
|
10696
|
+
// audited with what it did.
|
|
10697
|
+
const walked = [];
|
|
10698
|
+
let pass = null;
|
|
10699
|
+
let failedWith;
|
|
10700
|
+
try {
|
|
10701
|
+
pass = await runWireWalk({
|
|
10702
|
+
admin: c.var.admin,
|
|
10703
|
+
actor,
|
|
10704
|
+
settings: options.wireUpload,
|
|
10705
|
+
api,
|
|
10706
|
+
...(options.fetchVerticalModules ? { fetchModules: options.fetchVerticalModules } : {}),
|
|
10707
|
+
fail: ({ vertical, version, stage, message }) => recordFailure({ actor, operation: 'wire-walk', stage, vertical, ...(version ? { version } : {}), message }),
|
|
10708
|
+
}, { apply, confirm, cursor, limit: body.limit ?? WIRE_WALK_LIMIT_DEFAULT, release: body.release ?? [], sink: walked });
|
|
10709
|
+
}
|
|
10710
|
+
catch (error) {
|
|
10711
|
+
failedWith = 'the pass stopped on a directory read it could not make; the scripts it walked before are listed';
|
|
10712
|
+
throw error;
|
|
10713
|
+
}
|
|
10714
|
+
finally {
|
|
10715
|
+
// Written however the pass ended: a person reached the fleet, or tried to.
|
|
10716
|
+
const named = (pick) => walked.filter(pick).map((s) => s.deploymentRef);
|
|
10717
|
+
const why = (action) => walked.filter((s) => s.action === action).map((s) => ({ deploymentRef: s.deploymentRef, reason: s.reason ?? action }));
|
|
10718
|
+
await c.var.admin.recordWireWalk(actor, {
|
|
10719
|
+
apply,
|
|
10720
|
+
confirm,
|
|
10721
|
+
from: body.cursor ?? null,
|
|
10722
|
+
next: pass?.next ?? null,
|
|
10723
|
+
walked: walked.length,
|
|
10724
|
+
updated: named((s) => s.action === 'updated'),
|
|
10725
|
+
held: named((s) => s.held === true),
|
|
10726
|
+
released: named((s) => s.released === true),
|
|
10727
|
+
skipped: why('skipped'),
|
|
10728
|
+
failed: why('failed'),
|
|
10729
|
+
...(failedWith ? { error: failedWith } : {}),
|
|
10730
|
+
});
|
|
10731
|
+
}
|
|
10732
|
+
return c.json(pass);
|
|
10733
|
+
});
|
|
10640
10734
|
return app;
|
|
10641
10735
|
}
|
|
10736
|
+
/** The most a wire walk's request body may be: a cursor and up to `WIRE_WALK_RELEASE_MAX` script names. */
|
|
10737
|
+
const WIRE_WALK_REQUEST_MAX_BYTES = 64 * 1024;
|
|
10642
10738
|
/**
|
|
10643
10739
|
* The most a release upload's body may be: the decoded cap, as base64 (4 bytes per 3), plus room
|
|
10644
10740
|
* for the JSON around it. A bigger body is refused (413) before it is read whole.
|