@substrat-run/adapter-sqlite 0.95.0 → 0.96.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/checker.d.ts +16 -1
- package/dist/checker.d.ts.map +1 -1
- package/dist/checker.js +8 -1
- package/dist/checker.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/checker.d.ts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import type Database from 'better-sqlite3';
|
|
2
2
|
import { type RoleDefinition } from '@substrat-run/contracts';
|
|
3
|
-
import type { PermissionChecker } from '@substrat-run/kernel';
|
|
3
|
+
import type { Clock, PermissionChecker } from '@substrat-run/kernel';
|
|
4
4
|
export interface CheckerDeps {
|
|
5
5
|
directory: Database.Database;
|
|
6
6
|
/** Resolve an OPEN scope db; checks only run inside operations, so it is open. */
|
|
7
7
|
scopeDb(scopeId: string): Database.Database | undefined;
|
|
8
8
|
getRole(tenantId: string, key: string): RoleDefinition | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* What "now" means when a tuple's `expires_at` is judged (#956). The host's own
|
|
11
|
+
* `clock`, so a frozen or manual clock can actually expire a grant — before this
|
|
12
|
+
* the evaluator read the wall clock and a scripted clock could not reach it.
|
|
13
|
+
*
|
|
14
|
+
* Optional and defaulting to the wall clock: a checker built without one behaves
|
|
15
|
+
* exactly as it did.
|
|
16
|
+
*/
|
|
17
|
+
clock?: Clock;
|
|
9
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Build the evaluator described above over one host's directory, scope databases
|
|
21
|
+
* and role table. Stateless per call: everything it knows it reads at check time,
|
|
22
|
+
* which is what makes check-after-write consistent and what lets `deps.clock`
|
|
23
|
+
* decide expiry rather than the wall clock.
|
|
24
|
+
*/
|
|
10
25
|
export declare function createTupleChecker(deps: CheckerDeps): PermissionChecker;
|
|
11
26
|
//# sourceMappingURL=checker.d.ts.map
|
package/dist/checker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EASL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EASL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAiBrE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC7B,kFAAkF;IAClF,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;IACxD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IACnE;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAgBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAoKvE"}
|
package/dist/checker.js
CHANGED
|
@@ -17,7 +17,14 @@ const t = (subject, relation, object) => ({
|
|
|
17
17
|
relation,
|
|
18
18
|
object: objectRef.parse(object),
|
|
19
19
|
});
|
|
20
|
+
/**
|
|
21
|
+
* Build the evaluator described above over one host's directory, scope databases
|
|
22
|
+
* and role table. Stateless per call: everything it knows it reads at check time,
|
|
23
|
+
* which is what makes check-after-write consistent and what lets `deps.clock`
|
|
24
|
+
* decide expiry rather than the wall clock.
|
|
25
|
+
*/
|
|
20
26
|
export function createTupleChecker(deps) {
|
|
27
|
+
const readNow = deps.clock ?? (() => new Date().toISOString());
|
|
21
28
|
const tenantTuples = (tenantId, subject, relationPrefix) => deps.directory
|
|
22
29
|
.prepare(`SELECT subject, relation, object, expires_at, revoked_at FROM _substrat_tenant_tuples
|
|
23
30
|
WHERE tenant_id = ? AND subject = ? AND relation LIKE ?`)
|
|
@@ -33,7 +40,7 @@ export function createTupleChecker(deps) {
|
|
|
33
40
|
const live = (row, now) => (row.expires_at === null || row.expires_at > now) && row.revoked_at === null;
|
|
34
41
|
return {
|
|
35
42
|
async check(subject, permission, node, entity) {
|
|
36
|
-
const now =
|
|
43
|
+
const now = readNow();
|
|
37
44
|
const deny = { allowed: false, checked: permission, node };
|
|
38
45
|
const scopeDb = node.scopeId ? deps.scopeDb(node.scopeId) : undefined;
|
|
39
46
|
// Rule 4 — membership: the subject set is the caller plus its orgs.
|
package/dist/checker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checker.js","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,UAAU,GAQX,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;;GAWG;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"checker.js","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ export interface SqliteScopeHostOptions {
|
|
|
27
27
|
* absence window to lapse, a metering period to roll, or a booking hold to
|
|
28
28
|
* expire cannot get there by waiting. Hand in a frozen or scripted clock and
|
|
29
29
|
* the interesting case becomes assertable.
|
|
30
|
+
*
|
|
31
|
+
* It is also what the host itself judges elapsed time against (#956), not only
|
|
32
|
+
* what module code reads: tuple expiry in the built-in checker — so a grant with
|
|
33
|
+
* an `expiresAt` actually stops granting when the clock passes it — plus session
|
|
34
|
+
* expiry, entitlement expiry, schedule cadence and a migration's `applied_at`.
|
|
35
|
+
* Wall-clock writes that only stamp *when something happened* (an outbox row, an
|
|
36
|
+
* admin-log entry) are untouched and stay on the real clock.
|
|
30
37
|
*/
|
|
31
38
|
clock?: Clock;
|
|
32
39
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EASL,KAAK,eAAe,EAuDpB,KAAK,YAAY,EAGjB,KAAK,QAAQ,EASb,KAAK,WAAW,EAIhB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAI3B,KAAK,wBAAwB,EAW7B,KAAK,eAAe,EACpB,KAAK,WAAW,EAehB,KAAK,SAAS,EAEd,KAAK,OAAO,EAYZ,KAAK,sBAAsB,EAG3B,KAAK,QAAQ,EAGb,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import Database from 'better-sqlite3';
|
|
4
|
-
import { accessLogEntry, adminLogEntry, opsFailureEntry, modelUsageEntry, ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, createTenantInput, domainEvent, domainEventInput, entitlementGrant, entitlementGrantInput, eventId, meterReading, platformRequestInput, platformRequestId, platformRequest, MAX_PENDING_PLATFORM_REQUESTS, identityLink, identityPool, instant, connection, capabilityGrant, connectionGrant, connectionGrantRecord, connectionSecret, systemGrant, subjectRef, requestFingerprint, createConnectionInput, projectedConnectionGrant, projectedConnectionKey, moduleManifest, createOrgInput, promotionAcknowledgement, bindHostnameInput, channelHistoryEntry, hostnameBinding, publishVersionInput, AUTO_ADMISSION_NOTE, routeTarget, registerVerticalInput, vertical as verticalSchema, verticalChannel, verticalVersion, objectRef, grantRefFromProof, org as orgSchema, orgMembership, principalId, resolvedIdentity, roleDefinition, scope as scopeSchema, tenant as tenantSchema, tenantRole, subjectShredReceipt, SCOPE_TABLE_PAGE_DEFAULT, SCOPE_TABLE_PAGE_MAX, SCOPE_QUERY_ROW_MAX, verticalServingState, outboundOfManifestJson, listLimitOf, substratError, } from '@substrat-run/contracts';
|
|
4
|
+
import { accessLogEntry, adminLogEntry, opsFailureEntry, modelUsageEntry, ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, createTenantInput, domainEvent, domainEventInput, entitlementGrant, entitlementGrantInput, eventId, meterReading, platformRequestInput, platformRequestId, platformRequest, MAX_PENDING_PLATFORM_REQUESTS, identityLink, identityPool, instant, connection, capabilityGrant, connectionGrant, connectionGrantRecord, connectionSecret, systemGrant, subjectRef, requestFingerprint, createConnectionInput, projectedConnectionGrant, projectedConnectionKey, moduleManifest, createOrgInput, promotionAcknowledgement, bindHostnameInput, channelHistoryEntry, hostnameBinding, publishVersionInput, AUTO_ADMISSION_NOTE, routeTarget, registerVerticalInput, vertical as verticalSchema, verticalChannel, verticalVersion, objectRef, grantRefFromProof, org as orgSchema, orgMembership, principalId, resolvedIdentity, roleDefinition, scope as scopeSchema, tenant as tenantSchema, tenantRole, subjectShredReceipt, SCOPE_TABLE_PAGE_DEFAULT, SCOPE_TABLE_PAGE_MAX, SCOPE_QUERY_ROW_MAX, verticalServingState, outboundOfManifestJson, listLimitOf, substratError, assertReplayableDump, } from '@substrat-run/contracts';
|
|
5
5
|
import { asPrincipal, assertAllowed, assertReadOnlyQuery, attachmentBlobKey, entitlementDenial, foldMeterReading, guardSpine, parseValidationRecords, resolveScopeRecord, ulid, OPS_FAILURE_RETENTION_DAYS, MODEL_USAGE_RETENTION_DAYS, foldModelUsage, backoffAt, platformRequestHistoryQuery, PLATFORM_REQUEST_COLUMNS, denialListQuery, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialBucketRow, IMPERSONATION_COLUMNS, IMPERSONATION_DDL, ImpersonationRefused, assertImpersonationWrites, assertSessionUsable, impersonationByIdQuery, impersonationListQuery, impersonationRowValues, impersonationStampOf, mapImpersonationRow, newImpersonationSession, resolveRetryPolicy, isSecretBoxConfigured, unconfiguredSecretBox, createSubjectKeys, generateSealingKeyPair, noSealingKeyMessage, openSealed, sealTo, ConnectionSealingKeyUnavailableError, PermissionDenied, createAtomic, NotSearchable, NotListable, listIndexMigrations, listIndexPlans, listQuery, cursorOf, isSearchIndexTable, searchIndexDdl, searchIndexMigrations, searchIndexPlans, searchLimit, searchMatchExpression, searchQuery, entityVersionQuery, entityVersionOf, assertIfMatch, OUTBOX_ENTITY_INDEX, IDEMPOTENCY_DDL, assertIdempotencyKey, idempotencyLookupQuery, idempotencyPruneStatement, idempotencyRecordStatement, idempotencyOptedOutMessage, replayFor, } from '@substrat-run/kernel';
|
|
6
6
|
import { ScopeActor } from './actor.js';
|
|
7
7
|
import { createTupleChecker } from './checker.js';
|
|
@@ -353,6 +353,10 @@ export class SqliteScopeHost {
|
|
|
353
353
|
directory: this.directory,
|
|
354
354
|
scopeDb: (scopeId) => this.scopesById.get(scopeId)?.db,
|
|
355
355
|
getRole: (tenantId, key) => this.roles.get(`${tenantId}/${key}`),
|
|
356
|
+
// #956: the evaluator judges `expires_at` against the host's clock, so a
|
|
357
|
+
// scripted one can actually expire a grant. A caller-supplied `checker`
|
|
358
|
+
// keeps its own time source — this only binds the built-in one.
|
|
359
|
+
clock: () => this.clock(),
|
|
356
360
|
});
|
|
357
361
|
this.admin = this.buildAdmin();
|
|
358
362
|
}
|
|
@@ -402,6 +406,7 @@ export class SqliteScopeHost {
|
|
|
402
406
|
status TEXT NOT NULL DEFAULT 'active',
|
|
403
407
|
schema_version TEXT NOT NULL DEFAULT '0',
|
|
404
408
|
vertical_version_id TEXT,
|
|
409
|
+
provisioned_version_id TEXT,
|
|
405
410
|
-- Last FAILED migration attempt (§5.3). All null / 0 = healthy. Written on
|
|
406
411
|
-- the failure path so a scope that fails closed stops rendering as active;
|
|
407
412
|
-- cleared on the next success. See applyPendingMigrations.
|
|
@@ -1665,8 +1670,13 @@ export class SqliteScopeHost {
|
|
|
1665
1670
|
// A dump written before indexes were excluded may still carry them; skip those
|
|
1666
1671
|
// too rather than failing a restore over data that is about to be recomputed.
|
|
1667
1672
|
const replayable = dumped.filter((t) => !isSearchIndexTable(t.name));
|
|
1673
|
+
// The dump is untrusted input (#1143): its names reach SQL as identifiers, and
|
|
1674
|
+
// `db.exec` would run every statement its `ddl` contains, not just the CREATE
|
|
1675
|
+
// TABLE. Judged as a whole before any of it executes — a check interleaved with
|
|
1676
|
+
// the replay has already let the earlier tables happen.
|
|
1677
|
+
assertReplayableDump(replayable);
|
|
1668
1678
|
for (const t of replayable)
|
|
1669
|
-
db.
|
|
1679
|
+
db.prepare(t.ddl).run();
|
|
1670
1680
|
for (const t of replayable) {
|
|
1671
1681
|
if (t.rows.length === 0)
|
|
1672
1682
|
continue;
|
|
@@ -1966,7 +1976,7 @@ export class SqliteScopeHost {
|
|
|
1966
1976
|
// holds a live `system:<moduleId>` grant. This is what makes a foreign-vertical
|
|
1967
1977
|
// scope (one this module was never provisioned on) a quiet no-op, and what makes
|
|
1968
1978
|
// "disable scheduling for this tenant" a plain grant revoke — no error, no run.
|
|
1969
|
-
const nowIso =
|
|
1979
|
+
const nowIso = this.clock();
|
|
1970
1980
|
const hasGrant = rt.db
|
|
1971
1981
|
.prepare(`SELECT 1 FROM _substrat_tuples
|
|
1972
1982
|
WHERE subject = ? AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)
|
|
@@ -1981,7 +1991,7 @@ export class SqliteScopeHost {
|
|
|
1981
1991
|
last_run_at TEXT,
|
|
1982
1992
|
last_status TEXT
|
|
1983
1993
|
)`);
|
|
1984
|
-
const now = Date.
|
|
1994
|
+
const now = Date.parse(nowIso);
|
|
1985
1995
|
for (const schedule of mod.schedules) {
|
|
1986
1996
|
const row = rt.db
|
|
1987
1997
|
.prepare('SELECT last_run_at FROM _substrat_schedule_state WHERE schedule_op = ?')
|
|
@@ -2872,11 +2882,11 @@ export class SqliteScopeHost {
|
|
|
2872
2882
|
.prepare(`SELECT 1 FROM _substrat_entitlements
|
|
2873
2883
|
WHERE tenant_id = ? AND entitlement_key = ?
|
|
2874
2884
|
AND (expires_at IS NULL OR expires_at > ?)`)
|
|
2875
|
-
.get(tenantId, key,
|
|
2885
|
+
.get(tenantId, key, this.clock()) !== undefined);
|
|
2876
2886
|
}
|
|
2877
2887
|
/** Every key the tenant is granted, expiry flagged — the "held" half of a denial (#691). */
|
|
2878
2888
|
heldEntitlements(tenantId) {
|
|
2879
|
-
const now =
|
|
2889
|
+
const now = this.clock();
|
|
2880
2890
|
return this.directory
|
|
2881
2891
|
.prepare(`SELECT entitlement_key, expires_at FROM _substrat_entitlements
|
|
2882
2892
|
WHERE tenant_id = ? ORDER BY entitlement_key`)
|
|
@@ -3012,6 +3022,7 @@ export class SqliteScopeHost {
|
|
|
3012
3022
|
vertical: r.vertical,
|
|
3013
3023
|
schemaVersion: r.schema_version,
|
|
3014
3024
|
verticalVersionId: r.vertical_version_id,
|
|
3025
|
+
provisionedVersionId: r.provisioned_version_id ?? null,
|
|
3015
3026
|
migrationFailure: mapMigrationFailure(r),
|
|
3016
3027
|
forkedFrom: r.forked_from,
|
|
3017
3028
|
forkedAt: r.forked_at,
|
|
@@ -3823,6 +3834,22 @@ export class SqliteScopeHost {
|
|
|
3823
3834
|
version: v.version,
|
|
3824
3835
|
});
|
|
3825
3836
|
},
|
|
3837
|
+
/**
|
|
3838
|
+
* Record that this scope's provision has now run against `versionId` (#1172).
|
|
3839
|
+
* Written only after a provision or reconcile succeeded — a receipt, never a hope.
|
|
3840
|
+
*/
|
|
3841
|
+
markScopeProvisioned: async (actor, tenantId, scopeId, versionId) => {
|
|
3842
|
+
const scope = this.directory
|
|
3843
|
+
.prepare('SELECT tenant_id FROM scopes WHERE scope_id = ?')
|
|
3844
|
+
.get(scopeId);
|
|
3845
|
+
if (!scope || scope.tenant_id !== tenantId) {
|
|
3846
|
+
throw new Error(`unknown scope ${scopeId} in tenant ${tenantId}`);
|
|
3847
|
+
}
|
|
3848
|
+
this.directory
|
|
3849
|
+
.prepare('UPDATE scopes SET provisioned_version_id = ? WHERE scope_id = ?')
|
|
3850
|
+
.run(versionId, scopeId);
|
|
3851
|
+
this.recordAdmin(actor, 'markScopeProvisioned', { tenantId, scopeId }, null, { versionId });
|
|
3852
|
+
},
|
|
3826
3853
|
verticalServing: async (actor, verticalSlug) => {
|
|
3827
3854
|
const r = this.directory
|
|
3828
3855
|
.prepare('SELECT * FROM verticals WHERE slug = ?')
|
|
@@ -5262,6 +5289,9 @@ export class SqliteScopeHost {
|
|
|
5262
5289
|
// under several accounts. Existing data always satisfies the wider key.
|
|
5263
5290
|
this.directory.exec('DROP INDEX IF EXISTS _substrat_connections_live');
|
|
5264
5291
|
this.ensureColumn(this.directory, '_substrat_admin_log', 'caused_by', 'caused_by TEXT');
|
|
5292
|
+
// #1172: which version this scope's provision hook last ran against. Null on every
|
|
5293
|
+
// existing row, which reads as "unknown, reconcile once" rather than "up to date".
|
|
5294
|
+
this.ensureColumn(this.directory, 'scopes', 'provisioned_version_id', 'provisioned_version_id TEXT');
|
|
5265
5295
|
// §4.8's grace-window timestamp on tenants (mirrors scopes' archived_at).
|
|
5266
5296
|
this.ensureColumn(this.directory, 'tenants', 'deleting_at', 'deleting_at TEXT');
|
|
5267
5297
|
this.ensureColumn(this.directory, 'tenants', 'provisioned_by_tenant', 'provisioned_by_tenant TEXT REFERENCES tenants(tenant_id)');
|
|
@@ -5637,7 +5667,7 @@ export class SqliteScopeHost {
|
|
|
5637
5667
|
const row = this.directory
|
|
5638
5668
|
.prepare(`SELECT entitlement_key, plan, quota, expires_at FROM _substrat_entitlements
|
|
5639
5669
|
WHERE tenant_id = ? AND entitlement_key = ? AND (expires_at IS NULL OR expires_at > ?)`)
|
|
5640
|
-
.get(rt.tenantId, key,
|
|
5670
|
+
.get(rt.tenantId, key, this.clock());
|
|
5641
5671
|
return row
|
|
5642
5672
|
? { key: row.entitlement_key, plan: row.plan, quota: row.quota, expiresAt: row.expires_at }
|
|
5643
5673
|
: null;
|
|
@@ -5646,7 +5676,7 @@ export class SqliteScopeHost {
|
|
|
5646
5676
|
const rows = this.directory
|
|
5647
5677
|
.prepare(`SELECT entitlement_key, plan, quota, expires_at FROM _substrat_entitlements
|
|
5648
5678
|
WHERE tenant_id = ? AND (expires_at IS NULL OR expires_at > ?)`)
|
|
5649
|
-
.all(rt.tenantId,
|
|
5679
|
+
.all(rt.tenantId, this.clock());
|
|
5650
5680
|
return rows.map((r) => ({
|
|
5651
5681
|
key: r.entitlement_key,
|
|
5652
5682
|
plan: r.plan,
|
|
@@ -5709,7 +5739,7 @@ export class SqliteScopeHost {
|
|
|
5709
5739
|
rt.db.exec(migration.sql);
|
|
5710
5740
|
rt.db
|
|
5711
5741
|
.prepare('INSERT INTO _substrat_migrations (module_id, version, applied_at) VALUES (?, ?, ?)')
|
|
5712
|
-
.run(moduleId, migration.version,
|
|
5742
|
+
.run(moduleId, migration.version, this.clock());
|
|
5713
5743
|
}
|
|
5714
5744
|
rt.db.exec('COMMIT');
|
|
5715
5745
|
}
|