@substrat-run/kernel 0.135.0 → 0.137.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/async-invocation-log.d.ts +61 -0
- package/dist/async-invocation-log.d.ts.map +1 -0
- package/dist/async-invocation-log.js +149 -0
- package/dist/async-invocation-log.js.map +1 -0
- package/dist/base64url.d.ts +6 -0
- package/dist/base64url.d.ts.map +1 -0
- package/dist/base64url.js +19 -0
- package/dist/base64url.js.map +1 -0
- package/dist/capability.d.ts +4 -0
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +7 -8
- package/dist/capability.js.map +1 -1
- package/dist/carried-copy.d.ts +117 -0
- package/dist/carried-copy.d.ts.map +1 -0
- package/dist/carried-copy.js +134 -0
- package/dist/carried-copy.js.map +1 -0
- package/dist/index.d.ts +101 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -14
- package/dist/index.js.map +1 -1
- package/dist/invocation-log.d.ts +115 -9
- package/dist/invocation-log.d.ts.map +1 -1
- package/dist/invocation-log.js +78 -15
- package/dist/invocation-log.js.map +1 -1
- package/dist/job-run.d.ts +77 -15
- package/dist/job-run.d.ts.map +1 -1
- package/dist/job-run.js +107 -24
- package/dist/job-run.js.map +1 -1
- package/dist/lifecycle-flow.d.ts.map +1 -1
- package/dist/lifecycle-flow.js +2 -1
- package/dist/lifecycle-flow.js.map +1 -1
- package/dist/list-index.d.ts +19 -4
- package/dist/list-index.d.ts.map +1 -1
- package/dist/list-index.js +150 -8
- package/dist/list-index.js.map +1 -1
- package/dist/permission-eval.d.ts +9 -0
- package/dist/permission-eval.d.ts.map +1 -1
- package/dist/permission-eval.js +26 -0
- package/dist/permission-eval.js.map +1 -1
- package/dist/platform-call.d.ts +4 -37
- package/dist/platform-call.d.ts.map +1 -1
- package/dist/platform-call.js +5 -37
- package/dist/platform-call.js.map +1 -1
- package/dist/platform-sweep.d.ts +17 -0
- package/dist/platform-sweep.d.ts.map +1 -1
- package/dist/platform-sweep.js +22 -4
- package/dist/platform-sweep.js.map +1 -1
- package/dist/provider-error.d.ts.map +1 -1
- package/dist/provider-error.js +2 -1
- package/dist/provider-error.js.map +1 -1
- package/dist/refusal-query.d.ts +4 -1
- package/dist/refusal-query.d.ts.map +1 -1
- package/dist/refusal-query.js +6 -4
- package/dist/refusal-query.js.map +1 -1
- package/dist/refusals.d.ts +80 -8
- package/dist/refusals.d.ts.map +1 -1
- package/dist/refusals.js +141 -22
- package/dist/refusals.js.map +1 -1
- package/dist/routed-node.d.ts +3 -2
- package/dist/routed-node.d.ts.map +1 -1
- package/dist/routed-node.js.map +1 -1
- package/dist/scope-copy.d.ts +122 -0
- package/dist/scope-copy.d.ts.map +1 -0
- package/dist/scope-copy.js +187 -0
- package/dist/scope-copy.js.map +1 -0
- package/dist/scope-host.d.ts +95 -27
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/scope-host.js +5 -14
- package/dist/scope-host.js.map +1 -1
- package/dist/scope-lifecycle.d.ts +70 -0
- package/dist/scope-lifecycle.d.ts.map +1 -0
- package/dist/scope-lifecycle.js +124 -0
- package/dist/scope-lifecycle.js.map +1 -0
- package/dist/system-switch-record.d.ts +27 -11
- package/dist/system-switch-record.d.ts.map +1 -1
- package/dist/system-switch-record.js +59 -24
- package/dist/system-switch-record.js.map +1 -1
- package/dist/system-switch.d.ts +41 -11
- package/dist/system-switch.d.ts.map +1 -1
- package/dist/system-switch.js +48 -15
- package/dist/system-switch.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { storedScopeLifecycle, } from '@substrat-run/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* A scope's lifecycle, held in the scope's own storage (#1713).
|
|
4
|
+
*
|
|
5
|
+
* A CP-less hosted vertical has no directory. The router refuses a suspended scope's requests
|
|
6
|
+
* (#1730), but a deployment's own timer, retries and background work never pass the router, so
|
|
7
|
+
* the deployment needs the lifecycle in storage it can read. The platform pushes it on every
|
|
8
|
+
* transition (`/internal/lifecycle`), and its heal sweep re-pushes any scope whose last delivered
|
|
9
|
+
* state differs from the directory. That way a missed push converges instead of failing open.
|
|
10
|
+
*
|
|
11
|
+
* One `_substrat_meta` row, as JSON. No row means `active`: a scope this has never reached, and
|
|
12
|
+
* every scope from before it, runs as it always did.
|
|
13
|
+
*
|
|
14
|
+
* Deliveries are ordered by the directory's revisions, never by a clock (`supersedes`): two
|
|
15
|
+
* transitions' deliveries can overlap, and the later transition's must win whichever lands last.
|
|
16
|
+
*
|
|
17
|
+
* The row travels with a dump onto the same scope (a carry onto a new version lands in a fresh
|
|
18
|
+
* store). A load keeps the NEWER of the store's row and the dump's (`lifecycleAfterLoad`), so a
|
|
19
|
+
* restore of a backup taken before a suspension does not lift it. A copy (a fork, a snapshot, a
|
|
20
|
+
* preview) never takes the source's row: it has a directory row of its own, and its own pushes.
|
|
21
|
+
*/
|
|
22
|
+
export const SCOPE_LIFECYCLE_KEY = 'scope_lifecycle';
|
|
23
|
+
/**
|
|
24
|
+
* The one statement that stores a delivered lifecycle, with its key written in. A delivery changes
|
|
25
|
+
* what the store may run and none of its data, so the scope DO lets this statement through its
|
|
26
|
+
* bookkeeping path without advancing the write revision a carry fences on (`isLifecycleWrite`),
|
|
27
|
+
* as it does the copy marker. The key is a literal so that path cannot write any other row.
|
|
28
|
+
*/
|
|
29
|
+
export const WRITE_LIFECYCLE_SQL = `INSERT OR REPLACE INTO _substrat_meta (key, value) VALUES ('${SCOPE_LIFECYCLE_KEY}', ?)`;
|
|
30
|
+
/** Whether a statement is `WRITE_LIFECYCLE_SQL`, whitespace aside. */
|
|
31
|
+
export const isLifecycleWrite = (sql) => sql.trim().replace(/\s+/g, ' ') === WRITE_LIFECYCLE_SQL;
|
|
32
|
+
/** The stored lifecycle, or null when none was delivered. A row that does not parse reads as none. */
|
|
33
|
+
export function readLifecycle(sql) {
|
|
34
|
+
const row = sql.all('SELECT value FROM _substrat_meta WHERE key = ?', SCOPE_LIFECYCLE_KEY)[0];
|
|
35
|
+
return row ? parseLifecycle(row.value) : null;
|
|
36
|
+
}
|
|
37
|
+
/** A stored or dumped value as a lifecycle, or null when it is absent or does not parse. */
|
|
38
|
+
export function parseLifecycle(value) {
|
|
39
|
+
if (typeof value !== 'string')
|
|
40
|
+
return null;
|
|
41
|
+
try {
|
|
42
|
+
const parsed = storedScopeLifecycle.safeParse(JSON.parse(value));
|
|
43
|
+
return parsed.success ? parsed.data : null;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** What a lifecycle held before revisions existed counts as: older than every revisioned one. */
|
|
50
|
+
const UNREVISED = { epoch: -1, scope: -1, tenant: -1 };
|
|
51
|
+
/**
|
|
52
|
+
* Whether `next` replaces `current`. A newer epoch always does: it is a later history of the
|
|
53
|
+
* directory (a restore), whose counters may be lower than the ones the replaced history reached.
|
|
54
|
+
* Within one epoch, `next` must be strictly newer on at least one counter and older on neither.
|
|
55
|
+
* An equal revision is the same directory state delivered again, and refused, so that no two
|
|
56
|
+
* deliveries can tie. Counters that disagree (newer on one, older on the other) cannot come from
|
|
57
|
+
* one directory read and are refused too.
|
|
58
|
+
*/
|
|
59
|
+
function supersedes(next, current) {
|
|
60
|
+
if (current === null)
|
|
61
|
+
return true;
|
|
62
|
+
const n = next.revision ?? UNREVISED;
|
|
63
|
+
const c = current.revision ?? UNREVISED;
|
|
64
|
+
if (n.epoch !== c.epoch)
|
|
65
|
+
return n.epoch > c.epoch;
|
|
66
|
+
return n.scope >= c.scope && n.tenant >= c.tenant && (n.scope > c.scope || n.tenant > c.tenant);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Store a delivered lifecycle, unless the store already holds one as new or newer. `applied` says whether
|
|
70
|
+
* this delivery is now the stored state, and `changed` whether the gate's answer moved with it.
|
|
71
|
+
*/
|
|
72
|
+
export function writeLifecycle(sql, next) {
|
|
73
|
+
const current = readLifecycle(sql);
|
|
74
|
+
if (!supersedes(next, current))
|
|
75
|
+
return { applied: false, changed: false, lifecycle: current };
|
|
76
|
+
sql.run(WRITE_LIFECYCLE_SQL, JSON.stringify(next));
|
|
77
|
+
const changed = (lifecycleRefusal(current) === null) !== (lifecycleRefusal(next) === null);
|
|
78
|
+
return { applied: true, changed, lifecycle: next };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The row a load leaves (#1713): the store's own when the load is a copy, otherwise the newer of
|
|
82
|
+
* the store's and the dump's. Null means no row.
|
|
83
|
+
*/
|
|
84
|
+
export function lifecycleAfterLoad(before, dumped, copy) {
|
|
85
|
+
if (copy || dumped === null)
|
|
86
|
+
return before;
|
|
87
|
+
return supersedes(dumped, before) ? dumped : before;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Settle the row after a load replaced `_substrat_meta` wholesale (#1713): `lifecycleAfterLoad` of
|
|
91
|
+
* the row read before the load (`before`) and the one the dump brought, put in place or removed.
|
|
92
|
+
*/
|
|
93
|
+
export function settleLifecycleAfterLoad(sql, before, copy) {
|
|
94
|
+
const keep = lifecycleAfterLoad(before, readLifecycle(sql), copy);
|
|
95
|
+
if (keep)
|
|
96
|
+
sql.run(WRITE_LIFECYCLE_SQL, JSON.stringify(keep));
|
|
97
|
+
else
|
|
98
|
+
sql.run('DELETE FROM _substrat_meta WHERE key = ?', SCOPE_LIFECYCLE_KEY);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* THE lifecycle gate (#1713): null when the scope may run, or the refusal's message. Both halves must be
|
|
102
|
+
* `active`, the tenant judged first, exactly as the directory's `scopeAccessRefusal` judges them,
|
|
103
|
+
* so a CP-less deployment and a CP-backed one refuse the same scope in the same words. No stored
|
|
104
|
+
* lifecycle passes.
|
|
105
|
+
*/
|
|
106
|
+
export function lifecycleRefusal(state, ids) {
|
|
107
|
+
if (!state)
|
|
108
|
+
return null;
|
|
109
|
+
if (state.tenant !== 'active')
|
|
110
|
+
return `tenant not active (status: ${state.tenant})${ids ? `: ${ids.tenantId}` : ''}`;
|
|
111
|
+
if (state.scope !== 'active')
|
|
112
|
+
return `scope not active (status: ${state.scope})${ids ? `: ${ids.scopeId}` : ''}`;
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The directory's record of what a deployment last acknowledged, compared with the directory's
|
|
117
|
+
* own lifecycle by the heal sweep: the statuses AND the full revision, so a restore that left the
|
|
118
|
+
* statuses as they were still reads as drift, and the scope is brought onto the new epoch. Never
|
|
119
|
+
* `at`, so a re-read of an unchanged directory is not drift. A lifecycle stored before revisions
|
|
120
|
+
* has none, and reads as drift against any directory.
|
|
121
|
+
*/
|
|
122
|
+
export const lifecycleReceipt = (state) => `${state.scope}/${state.tenant}` +
|
|
123
|
+
(state.revision ? `@${state.revision.epoch}.${state.revision.scope}.${state.revision.tenant}` : '');
|
|
124
|
+
//# sourceMappingURL=scope-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-lifecycle.js","sourceRoot":"","sources":["../src/scope-lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,6 +119,14 @@ export declare function switchedOffModulesOf(db: SwitchSql, tenantId: string, sc
|
|
|
119
119
|
* tenant tuple's write together, on the handle both live on.
|
|
120
120
|
*/
|
|
121
121
|
export declare function scopesSwitchedOffFor(db: SwitchSql, tenantId: string, moduleId: string): string[];
|
|
122
|
+
/**
|
|
123
|
+
* Does the tenant hold a live TENANT-level grant for this module (#1823)? Asked of the
|
|
124
|
+
* directory, where the tenant tuple lives, and handed to the switch as `tenantHeld`: a module
|
|
125
|
+
* whose only authority on a scope is a tenant-level grant has nothing in the scope's storage
|
|
126
|
+
* for the switch to find, and must still be switchable there. One statement on both adapters'
|
|
127
|
+
* directories; the same "live" the evaluator judges a grant by (unrevoked, unexpired at `now`).
|
|
128
|
+
*/
|
|
129
|
+
export declare function tenantHoldsSystemGrant(db: SwitchSql, tenantId: string, moduleId: string, now: string): boolean;
|
|
122
130
|
/** What one switch call writes into the record. */
|
|
123
131
|
export interface SystemSwitchRecordWrite {
|
|
124
132
|
tenantId: string;
|
|
@@ -186,13 +194,21 @@ export declare function staleCarryRevertRow(moduleId: string, outcome: {
|
|
|
186
194
|
staleCarry: true;
|
|
187
195
|
};
|
|
188
196
|
/**
|
|
189
|
-
* OFF's write, made
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
197
|
+
* OFF's write, made BEFORE the scope's switch moves (#1823), and undone by
|
|
198
|
+
* `restoreSystemSwitchRecord` when the move throws or holds nothing. An upsert: a repeat OFF
|
|
199
|
+
* refreshes the actor, reason and time, as the status read reports the latest reason.
|
|
200
|
+
* Answers the row as it was.
|
|
201
|
+
*
|
|
202
|
+
* Before, because the other order left a window: between the scope moving and this write, a
|
|
203
|
+
* tenant-level `grantToSystem` read no `off` row and was accepted (#1743's refusal reads this
|
|
204
|
+
* table, in the unit that writes the tenant tuple). Written first, there is no instant at
|
|
205
|
+
* which the scope is off and the record is not. This order fails toward a record of `off`
|
|
206
|
+
* beside a scope still on, until the undo runs — the direction OFF wins anyway, and the one a
|
|
207
|
+
* kill switch should fail in. Still never LEFT behind for a call that held nothing: a row
|
|
208
|
+
* saying `off` for a module the scope never ran would switch it off on the day it is
|
|
209
|
+
* installed (the kernel's `held` check, for the same reason).
|
|
194
210
|
*/
|
|
195
|
-
export declare function recordSystemSwitchedOff(db: SwitchSql, row: SystemSwitchRecordWrite):
|
|
211
|
+
export declare function recordSystemSwitchedOff(db: SwitchSql, row: SystemSwitchRecordWrite): SystemSwitchRecordPrior;
|
|
196
212
|
/**
|
|
197
213
|
* ON's write, made BEFORE the scope's switch moves, and only to a row that exists. Before,
|
|
198
214
|
* because the other order fails unsafely: a scope switched on whose record write then
|
|
@@ -202,12 +218,12 @@ export declare function recordSystemSwitchedOff(db: SwitchSql, row: SystemSwitch
|
|
|
202
218
|
*/
|
|
203
219
|
export declare function recordSystemSwitchedOn(db: SwitchSql, row: SystemSwitchRecordWrite): SystemSwitchRecordPrior;
|
|
204
220
|
/**
|
|
205
|
-
* Put a row back as `recordSystemSwitchedOn` found it — the
|
|
206
|
-
* nothing. A
|
|
207
|
-
*
|
|
208
|
-
*
|
|
221
|
+
* Put a row back as `recordSystemSwitchedOn` or `recordSystemSwitchedOff` found it — the call
|
|
222
|
+
* that wrote it threw, or held nothing. A row that did not exist is removed again. A
|
|
223
|
+
* compare-and-set on the call's own `operationId`: if another switch call has written the row
|
|
224
|
+
* since, the row is left as that call wrote it, so an undo can never clobber a newer position.
|
|
209
225
|
*/
|
|
210
|
-
export declare function restoreSystemSwitchRecord(db: SwitchSql,
|
|
226
|
+
export declare function restoreSystemSwitchRecord(db: SwitchSql, call: {
|
|
211
227
|
tenantId: string;
|
|
212
228
|
scopeId: string;
|
|
213
229
|
moduleId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-switch-record.d.ts","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"system-switch-record.d.ts","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { liveTupleSql } from './permission-eval.js';
|
|
1
2
|
/** The record's table name, as the DDL below spells it. */
|
|
2
3
|
export const SYSTEM_SWITCHES_TABLE = '_substrat_system_switches';
|
|
3
4
|
/**
|
|
@@ -183,6 +184,19 @@ export function scopesSwitchedOffFor(db, tenantId, moduleId) {
|
|
|
183
184
|
WHERE tenant_id = ? AND module_id = ? AND position = 'off' ORDER BY scope_id`, tenantId, moduleId)
|
|
184
185
|
.map((r) => String(r.scope_id));
|
|
185
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Does the tenant hold a live TENANT-level grant for this module (#1823)? Asked of the
|
|
189
|
+
* directory, where the tenant tuple lives, and handed to the switch as `tenantHeld`: a module
|
|
190
|
+
* whose only authority on a scope is a tenant-level grant has nothing in the scope's storage
|
|
191
|
+
* for the switch to find, and must still be switchable there. One statement on both adapters'
|
|
192
|
+
* directories; the same "live" the evaluator judges a grant by (unrevoked, unexpired at `now`).
|
|
193
|
+
*/
|
|
194
|
+
export function tenantHoldsSystemGrant(db, tenantId, moduleId, now) {
|
|
195
|
+
const row = db.all(`SELECT EXISTS (SELECT 1 FROM _substrat_tenant_tuples
|
|
196
|
+
WHERE tenant_id = ? AND subject = ? AND object = ? AND substr(relation, 1, 8) = 'granted:'
|
|
197
|
+
AND ${liveTupleSql()}) AS held`, tenantId, `system:${moduleId}`, `tenant:${tenantId}`, now)[0];
|
|
198
|
+
return Number(row?.held) === 1;
|
|
199
|
+
}
|
|
186
200
|
/**
|
|
187
201
|
* The `reassertSystemSwitch` audit rows (less their `operationId`) for the in-unit moves:
|
|
188
202
|
* those that changed something, on a module the directory records `off` for this scope.
|
|
@@ -243,20 +257,44 @@ function setRecordRow(db, key, row, ifOperationId) {
|
|
|
243
257
|
WHERE tenant_id = ? AND scope_id = ? AND module_id = ?` +
|
|
244
258
|
(ifOperationId === undefined ? '' : ' AND operation_id = ?'), row.position, row.actor, row.reason, row.operationId, row.at, key.tenantId, key.scopeId, key.moduleId, ...(ifOperationId === undefined ? [] : [ifOperationId]));
|
|
245
259
|
}
|
|
260
|
+
/** The row as it stands now, or null — what a write answers so its undo can put it back. */
|
|
261
|
+
function priorOf(db, key) {
|
|
262
|
+
const prior = db.all(`SELECT position, actor, reason, operation_id, switched_at FROM _substrat_system_switches
|
|
263
|
+
WHERE tenant_id = ? AND scope_id = ? AND module_id = ?`, key.tenantId, key.scopeId, key.moduleId)[0];
|
|
264
|
+
if (!prior)
|
|
265
|
+
return null;
|
|
266
|
+
return {
|
|
267
|
+
position: positionOf(prior.position),
|
|
268
|
+
actor: String(prior.actor),
|
|
269
|
+
reason: String(prior.reason),
|
|
270
|
+
operationId: String(prior.operation_id),
|
|
271
|
+
at: String(prior.switched_at),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
246
274
|
/**
|
|
247
|
-
* OFF's write, made
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
275
|
+
* OFF's write, made BEFORE the scope's switch moves (#1823), and undone by
|
|
276
|
+
* `restoreSystemSwitchRecord` when the move throws or holds nothing. An upsert: a repeat OFF
|
|
277
|
+
* refreshes the actor, reason and time, as the status read reports the latest reason.
|
|
278
|
+
* Answers the row as it was.
|
|
279
|
+
*
|
|
280
|
+
* Before, because the other order left a window: between the scope moving and this write, a
|
|
281
|
+
* tenant-level `grantToSystem` read no `off` row and was accepted (#1743's refusal reads this
|
|
282
|
+
* table, in the unit that writes the tenant tuple). Written first, there is no instant at
|
|
283
|
+
* which the scope is off and the record is not. This order fails toward a record of `off`
|
|
284
|
+
* beside a scope still on, until the undo runs — the direction OFF wins anyway, and the one a
|
|
285
|
+
* kill switch should fail in. Still never LEFT behind for a call that held nothing: a row
|
|
286
|
+
* saying `off` for a module the scope never ran would switch it off on the day it is
|
|
287
|
+
* installed (the kernel's `held` check, for the same reason).
|
|
252
288
|
*/
|
|
253
289
|
export function recordSystemSwitchedOff(db, row) {
|
|
290
|
+
const prior = priorOf(db, row);
|
|
254
291
|
db.run(`INSERT INTO _substrat_system_switches
|
|
255
292
|
(tenant_id, scope_id, module_id, position, actor, reason, operation_id, switched_at)
|
|
256
293
|
VALUES (?, ?, ?, 'off', ?, ?, ?, ?)
|
|
257
294
|
ON CONFLICT (tenant_id, scope_id, module_id) DO UPDATE SET
|
|
258
295
|
position = 'off', actor = excluded.actor, reason = excluded.reason,
|
|
259
296
|
operation_id = excluded.operation_id, switched_at = excluded.switched_at`, row.tenantId, row.scopeId, row.moduleId, row.actor, row.reason, row.operationId, row.at);
|
|
297
|
+
return prior;
|
|
260
298
|
}
|
|
261
299
|
/**
|
|
262
300
|
* ON's write, made BEFORE the scope's switch moves, and only to a row that exists. Before,
|
|
@@ -266,28 +304,25 @@ export function recordSystemSwitchedOff(db, row) {
|
|
|
266
304
|
* the marker wins. Answers the row as it was, for `restoreSystemSwitchRecord`.
|
|
267
305
|
*/
|
|
268
306
|
export function recordSystemSwitchedOn(db, row) {
|
|
269
|
-
const prior = db
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return {
|
|
275
|
-
position: positionOf(prior.position),
|
|
276
|
-
actor: String(prior.actor),
|
|
277
|
-
reason: String(prior.reason),
|
|
278
|
-
operationId: String(prior.operation_id),
|
|
279
|
-
at: String(prior.switched_at),
|
|
280
|
-
};
|
|
307
|
+
const prior = priorOf(db, row);
|
|
308
|
+
if (prior) {
|
|
309
|
+
setRecordRow(db, row, { position: 'on', actor: row.actor, reason: row.reason, operationId: row.operationId, at: row.at });
|
|
310
|
+
}
|
|
311
|
+
return prior;
|
|
281
312
|
}
|
|
282
313
|
/**
|
|
283
|
-
* Put a row back as `recordSystemSwitchedOn` found it — the
|
|
284
|
-
* nothing. A
|
|
285
|
-
*
|
|
286
|
-
*
|
|
314
|
+
* Put a row back as `recordSystemSwitchedOn` or `recordSystemSwitchedOff` found it — the call
|
|
315
|
+
* that wrote it threw, or held nothing. A row that did not exist is removed again. A
|
|
316
|
+
* compare-and-set on the call's own `operationId`: if another switch call has written the row
|
|
317
|
+
* since, the row is left as that call wrote it, so an undo can never clobber a newer position.
|
|
287
318
|
*/
|
|
288
|
-
export function restoreSystemSwitchRecord(db,
|
|
289
|
-
if (prior)
|
|
290
|
-
setRecordRow(db,
|
|
319
|
+
export function restoreSystemSwitchRecord(db, call, prior) {
|
|
320
|
+
if (prior) {
|
|
321
|
+
setRecordRow(db, call, prior, call.operationId);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
db.run(`DELETE FROM _substrat_system_switches
|
|
325
|
+
WHERE tenant_id = ? AND scope_id = ? AND module_id = ? AND operation_id = ?`, call.tenantId, call.scopeId, call.moduleId, call.operationId);
|
|
291
326
|
}
|
|
292
327
|
/**
|
|
293
328
|
* Forget one scope's switch records — the scope's directory row is going too (a reaped
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-switch-record.js","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"system-switch-record.js","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"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"}
|
package/dist/system-switch.d.ts
CHANGED
|
@@ -19,19 +19,25 @@
|
|
|
19
19
|
* `scope:<id>` marker. The gate is OFF while that marker is live, whatever grants are
|
|
20
20
|
* live beside it. **Restore is the lever; a grant is not.** The marker is an ordinary
|
|
21
21
|
* K-21 tuple: switching back on tombstones it, so the row stays as evidence of when the
|
|
22
|
-
* switch was last pulled. The permission walk reads only `role:` and `granted:` relations
|
|
23
|
-
*
|
|
22
|
+
* switch was last pulled. The permission walk reads only `role:` and `granted:` relations,
|
|
23
|
+
* so the marker authorizes nothing; what it denies, it denies through the one question the
|
|
24
|
+
* evaluator asks before the walk (below).
|
|
24
25
|
*
|
|
25
26
|
* Switching off ALSO tombstones every live `granted:` tuple the module holds on the scope.
|
|
26
27
|
* That is what makes it a kill switch rather than a schedule pause: anything that acts
|
|
27
28
|
* with the module's system authority — a resumable job run (#1577), a `getSystemScope`
|
|
28
29
|
* invoke — is denied by its own `ctx.check` while the switch is off.
|
|
29
30
|
*
|
|
30
|
-
* **And
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* **And the checker reads the marker too** (#1823), which is what makes that denial hold
|
|
32
|
+
* against a grant OFF cannot tombstone. A TENANT-level `system:` grant lives in the directory
|
|
33
|
+
* (and in every scope's projection of it), not at `scope:<id>`, so OFF leaves it live. The
|
|
34
|
+
* permission evaluator asks the scope reader's `switchedOff` before it reads any tuple, and a
|
|
35
|
+
* live marker denies the subject on that scope whatever it holds (`permission-eval.ts`). The
|
|
36
|
+
* write side stays closed as well, so a switched-off scope does not accumulate grants that
|
|
37
|
+
* ON would then hand back:
|
|
33
38
|
* - `grantToSystem` refuses while the module is switched off on that scope (the adapters
|
|
34
|
-
* ask `systemSwitchedOff` in the same unit as the write)
|
|
39
|
+
* ask `systemSwitchedOff` in the same unit as the write), and a tenant-level grant while
|
|
40
|
+
* the directory records it off on any scope (#1743);
|
|
35
41
|
* - provisioning's seat (`seatScopeTuple`) seats nothing for a subject whose marker is
|
|
36
42
|
* live, so a reconcile cannot create a grant a newer version declares.
|
|
37
43
|
*
|
|
@@ -97,8 +103,15 @@ export interface SystemGrantsEntry {
|
|
|
97
103
|
export declare function systemGrantsStatus(db: SwitchSql, now: string): SystemGrantsEntry[];
|
|
98
104
|
/** Is this module switched off on the scope `db` is? What `grantToSystem` refuses on. */
|
|
99
105
|
export declare function systemSwitchedOff(db: SwitchSql, moduleId: string): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* `SYSTEM_SWITCH_OFF_PREDICATE` as a whole statement answering `off` (0/1), over the one bound
|
|
108
|
+
* subject — what `subjectSwitchedOff` runs, and what each adapter's permission reader prepares
|
|
109
|
+
* once and runs on every check of a switchable subject (#1823).
|
|
110
|
+
*/
|
|
111
|
+
export declare const SYSTEM_SWITCH_OFF_QUERY = "SELECT EXISTS (SELECT 1 FROM _substrat_tuples\n WHERE subject = ? AND relation = 'switch:off' AND revoked_at IS NULL) AS off";
|
|
100
112
|
/** Is this subject's OFF marker live on the scope `db` is? Any subject — see `switchSubjectGrants`. */
|
|
101
113
|
export declare function subjectSwitchedOff(db: SwitchSql, subject: string): boolean;
|
|
114
|
+
export declare const isSwitchableSubjectKind: (kind: string) => boolean;
|
|
102
115
|
/** The refusal `grantToSystem` throws while the switch is off — one wording, both adapters. */
|
|
103
116
|
export declare function systemSwitchedOffMessage(moduleId: string, scopeId: string): string;
|
|
104
117
|
/**
|
|
@@ -111,6 +124,15 @@ export interface SwitchOutcome {
|
|
|
111
124
|
held: boolean;
|
|
112
125
|
changed: boolean;
|
|
113
126
|
permissions: string[];
|
|
127
|
+
/**
|
|
128
|
+
* #1823: this code's evaluator denies a module on a scope whose marker is live, its
|
|
129
|
+
* TENANT-level grants included. Set by `switchSystemSchedules` on every answer, because it
|
|
130
|
+
* is a fact about the code that answered, not about the call: a deployment built before
|
|
131
|
+
* #1823 omits it, and its OFF leaves a tenant-level grant authorizing. The platform reads
|
|
132
|
+
* its absence on an OFF of a module it found tenant-held as "this deployment cannot hold
|
|
133
|
+
* that OFF", and refuses it rather than record a scope off that is not.
|
|
134
|
+
*/
|
|
135
|
+
deniesTenantGrants?: true;
|
|
114
136
|
}
|
|
115
137
|
/**
|
|
116
138
|
* Move one module's switch on one scope. Idempotent: a repeat changes nothing and says so.
|
|
@@ -121,9 +143,13 @@ export interface SwitchOutcome {
|
|
|
121
143
|
* marker. A repeated OFF re-asserts the whole position: a grant that became live meanwhile
|
|
122
144
|
* (only a raw write can do that now) is tombstoned and recorded too.
|
|
123
145
|
*
|
|
124
|
-
* `held: false`, with nothing written, when the
|
|
125
|
-
*
|
|
126
|
-
*
|
|
146
|
+
* `held: false`, with nothing written, when the module has no authority reaching the scope:
|
|
147
|
+
* no grant and no marker here, and no live TENANT-level grant (`tenantHeld`, which the caller
|
|
148
|
+
* reads from the directory, since the scope's storage cannot answer it). The caller named
|
|
149
|
+
* something this scope never ran, and turning "nothing" off must not write a marker that
|
|
150
|
+
* silently disables a module the day it is installed. A module whose only authority here is a
|
|
151
|
+
* tenant-level grant IS held (#1823): OFF writes the marker, which the evaluator then denies
|
|
152
|
+
* the module on, and tombstones nothing, because nothing of it is here to tombstone.
|
|
127
153
|
*
|
|
128
154
|
* Run it inside one transaction; the reads and writes here are meant to be one unit.
|
|
129
155
|
*/
|
|
@@ -132,6 +158,7 @@ export declare function switchSystemSchedules(db: SwitchSql, input: {
|
|
|
132
158
|
scopeId: string;
|
|
133
159
|
to: 'on' | 'off';
|
|
134
160
|
at: string;
|
|
161
|
+
tenantHeld?: boolean;
|
|
135
162
|
}): SwitchOutcome;
|
|
136
163
|
/** One module `switchRecordedOff` switched off — `SwitchedOffInUnit`'s shape. */
|
|
137
164
|
export interface SwitchedOff extends SwitchOutcome {
|
|
@@ -147,13 +174,15 @@ export interface SwitchedOff extends SwitchOutcome {
|
|
|
147
174
|
* `scopeId` is the scope `db` is, and the caller passes the one the request provisions or
|
|
148
175
|
* restores, never a second id: the list names modules, never scopes, so it can only reach
|
|
149
176
|
* the scope that unit is already writing. A module the scope holds nothing for answers
|
|
150
|
-
* `held: false` and writes nothing, as the switch always does
|
|
151
|
-
* a
|
|
177
|
+
* `held: false` and writes nothing, as the switch always does — unless it is in `tenantHeld`,
|
|
178
|
+
* the recorded-off modules the caller found a live tenant-level grant for (#1823). Off only:
|
|
179
|
+
* nothing here turns a module on.
|
|
152
180
|
*/
|
|
153
181
|
export declare function switchRecordedOff(db: SwitchSql, input: {
|
|
154
182
|
scopeId: string;
|
|
155
183
|
moduleIds: readonly string[];
|
|
156
184
|
at: string;
|
|
185
|
+
tenantHeld?: readonly string[];
|
|
157
186
|
}): SwitchedOff[];
|
|
158
187
|
/**
|
|
159
188
|
* The switch itself, for ANY non-person subject's scope-level grants — `switchSystemSchedules`
|
|
@@ -169,5 +198,6 @@ export declare function switchSubjectGrants(db: SwitchSql, input: {
|
|
|
169
198
|
scopeId: string;
|
|
170
199
|
to: 'on' | 'off';
|
|
171
200
|
at: string;
|
|
201
|
+
tenantHeld?: boolean;
|
|
172
202
|
}): SwitchOutcome;
|
|
173
203
|
//# sourceMappingURL=system-switch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-switch.d.ts","sourceRoot":"","sources":["../src/system-switch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"system-switch.d.ts","sourceRoot":"","sources":["../src/system-switch.ts"],"names":[],"mappings":"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"}
|