@kici-dev/shared 0.1.26 → 0.2.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/agent-platform.d.ts +32 -0
- package/dist/agent-platform.js +27 -0
- package/dist/agent-platform.test.d.ts +2 -0
- package/dist/ci-env.d.ts +2 -0
- package/dist/ci-env.js +3 -0
- package/dist/cold-store/bucket.d.ts +1 -1
- package/dist/cold-store/cold-store.d.ts +24 -1
- package/dist/cold-store/cold-store.js +17 -5
- package/dist/cold-store/index.js +1 -1
- package/dist/db-admin.d.ts +206 -65
- package/dist/db-admin.js +236 -122
- package/dist/db-collation.d.ts +49 -0
- package/dist/db-collation.js +68 -1
- package/dist/db.d.ts +34 -0
- package/dist/db.js +30 -1
- package/dist/diagnostics/bundle-archive.js +5 -5
- package/dist/env/allowlist.d.ts +5 -0
- package/dist/env/allowlist.js +6 -1
- package/dist/env/define-env.d.ts +19 -2
- package/dist/env/define-env.js +18 -3
- package/dist/env/logger-env.d.ts +11 -9
- package/dist/env/logger-env.js +25 -9
- package/dist/idempotency-files.d.ts +7 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -4
- package/dist/telemetry/init.d.ts +18 -7
- package/dist/telemetry/init.js +36 -11
- package/dist/tmp-dir.d.ts +14 -0
- package/dist/tmp-dir.js +13 -0
- package/dist/tmp-dir.test.d.ts +2 -0
- package/dist/tmp.d.ts +2 -0
- package/dist/tmp.js +3 -0
- package/package.json +26 -17
- package/sbom.spdx.json +1222 -1618
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Supported fresh-box agent target platforms (glibc-Linux bootstrap set). */
|
|
3
|
+
export declare const AgentPlatform: z.ZodEnum<{
|
|
4
|
+
"linux-arm64": "linux-arm64";
|
|
5
|
+
"linux-x64": "linux-x64";
|
|
6
|
+
}>;
|
|
7
|
+
export type AgentPlatform = z.infer<typeof AgentPlatform>;
|
|
8
|
+
/**
|
|
9
|
+
* How a fresh-box agent payload is delivered to the target during bring-up.
|
|
10
|
+
* `s3-direct`: the box pulls the payload from the orchestrator cache bucket via
|
|
11
|
+
* a presigned URL (no 50 MB through the ops agent). `ssh-push`: the ops agent
|
|
12
|
+
* fetches the payload and streams it to the box over a binary-safe scp (the
|
|
13
|
+
* fallback for a box that cannot reach object storage).
|
|
14
|
+
*/
|
|
15
|
+
export declare const AgentDeliveryMode: z.ZodEnum<{
|
|
16
|
+
"s3-direct": "s3-direct";
|
|
17
|
+
"ssh-push": "ssh-push";
|
|
18
|
+
}>;
|
|
19
|
+
export type AgentDeliveryMode = z.infer<typeof AgentDeliveryMode>;
|
|
20
|
+
export interface AgentPlatformParts {
|
|
21
|
+
/** nodejs.org os token. */
|
|
22
|
+
nodeOs: 'linux';
|
|
23
|
+
/** nodejs.org arch token. */
|
|
24
|
+
nodeArch: 'x64' | 'arm64';
|
|
25
|
+
/** npm `--os` token. */
|
|
26
|
+
npmOs: 'linux';
|
|
27
|
+
/** npm `--cpu` token. */
|
|
28
|
+
npmCpu: 'x64' | 'arm64';
|
|
29
|
+
}
|
|
30
|
+
/** Decompose an AgentPlatform into the os/arch tokens npm and nodejs.org expect. */
|
|
31
|
+
export declare function splitAgentPlatform(platform: AgentPlatform): AgentPlatformParts;
|
|
32
|
+
//# sourceMappingURL=agent-platform.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import "./rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/agent-platform.ts
|
|
4
|
+
/** Supported fresh-box agent target platforms (glibc-Linux bootstrap set). */
|
|
5
|
+
const AgentPlatform = z.enum(["linux-x64", "linux-arm64"]);
|
|
6
|
+
/**
|
|
7
|
+
* How a fresh-box agent payload is delivered to the target during bring-up.
|
|
8
|
+
* `s3-direct`: the box pulls the payload from the orchestrator cache bucket via
|
|
9
|
+
* a presigned URL (no 50 MB through the ops agent). `ssh-push`: the ops agent
|
|
10
|
+
* fetches the payload and streams it to the box over a binary-safe scp (the
|
|
11
|
+
* fallback for a box that cannot reach object storage).
|
|
12
|
+
*/
|
|
13
|
+
const AgentDeliveryMode = z.enum(["ssh-push", "s3-direct"]);
|
|
14
|
+
/** Decompose an AgentPlatform into the os/arch tokens npm and nodejs.org expect. */
|
|
15
|
+
function splitAgentPlatform(platform) {
|
|
16
|
+
const arch = platform === "linux-x64" ? "x64" : "arm64";
|
|
17
|
+
return {
|
|
18
|
+
nodeOs: "linux",
|
|
19
|
+
nodeArch: arch,
|
|
20
|
+
npmOs: "linux",
|
|
21
|
+
npmCpu: arch
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { AgentDeliveryMode, AgentPlatform, splitAgentPlatform };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=agent-platform.js.map
|
package/dist/ci-env.d.ts
ADDED
package/dist/ci-env.js
ADDED
|
@@ -21,6 +21,6 @@ export declare function coldDaysToBucket(days: ColdRetention): string;
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function isLongerColdRetention(a: ColdRetention, b: ColdRetention): boolean;
|
|
23
23
|
/** Stable, ordered set of bucket names emitted by `coldDaysToBucket`. */
|
|
24
|
-
export declare const COLD_BUCKET_NAMES: readonly [
|
|
24
|
+
export declare const COLD_BUCKET_NAMES: readonly ['30d', '180d', '1y', '2y', 'forever'];
|
|
25
25
|
export type ColdBucketName = (typeof COLD_BUCKET_NAMES)[number];
|
|
26
26
|
//# sourceMappingURL=bucket.d.ts.map
|
|
@@ -37,7 +37,12 @@ export interface ColdStoreFetchRangeArgs<TRow> {
|
|
|
37
37
|
table: string;
|
|
38
38
|
tenantId: string;
|
|
39
39
|
fromTs: Date;
|
|
40
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Upper bound (exclusive). Omit to use `warmCutoff(table)` — the table's
|
|
42
|
+
* resolved warm/cold boundary. Pass an explicit value only when the caller
|
|
43
|
+
* genuinely owns the range (e.g. a user-supplied time filter).
|
|
44
|
+
*/
|
|
45
|
+
toTs?: Date;
|
|
41
46
|
decode?: (line: string) => TRow;
|
|
42
47
|
}
|
|
43
48
|
export interface ColdStoreReplayChunkArgs {
|
|
@@ -125,6 +130,23 @@ export interface PurgeableChunk {
|
|
|
125
130
|
* flow.
|
|
126
131
|
*/
|
|
127
132
|
export interface ColdStore {
|
|
133
|
+
/**
|
|
134
|
+
* The table's warm/cold boundary: `now − warmTtlDays`, resolved from the
|
|
135
|
+
* SAME config the archival writer uses — the registered adapter's effective
|
|
136
|
+
* config (built-in defaults merged with any
|
|
137
|
+
* `KICI_COLD_STORE_<TABLE>_WARM_TTL_DAYS` env override). Rows older than
|
|
138
|
+
* this may live in cold storage; rows newer are guaranteed PG-only.
|
|
139
|
+
*
|
|
140
|
+
* Readers MUST derive their cold-read upper bound from this rather than
|
|
141
|
+
* restating a literal. A reader-side value LARGER than the writer's
|
|
142
|
+
* produces an EARLIER cutoff, which silently hides archived rows: a
|
|
143
|
+
* manifest whose `min` timestamp is newer than the bound is skipped
|
|
144
|
+
* entirely, so a read 404s on data that exists in S3.
|
|
145
|
+
*
|
|
146
|
+
* A `warmTtlDays` of zero or less yields a cutoff at or after `now` — the
|
|
147
|
+
* widest window, which is the safe direction.
|
|
148
|
+
*/
|
|
149
|
+
warmCutoff(table: string): Date;
|
|
128
150
|
/** Stream archived rows that overlap [fromTs, toTs). */
|
|
129
151
|
fetchRange<TRow>(args: ColdStoreFetchRangeArgs<TRow>): AsyncIterable<TRow>;
|
|
130
152
|
hasRange(args: Omit<ColdStoreFetchRangeArgs<unknown>, 'decode'>): Promise<boolean>;
|
|
@@ -268,6 +290,7 @@ export declare abstract class BaseColdStore implements ColdStore {
|
|
|
268
290
|
private putChunkData;
|
|
269
291
|
private verifyChunkData;
|
|
270
292
|
private putManifest;
|
|
293
|
+
warmCutoff(table: string): Date;
|
|
271
294
|
fetchRange<TRow>(args: ColdStoreFetchRangeArgs<TRow>): AsyncIterable<TRow>;
|
|
272
295
|
hasRange(args: Omit<ColdStoreFetchRangeArgs<unknown>, 'decode'>): Promise<boolean>;
|
|
273
296
|
countRange(args: Omit<ColdStoreFetchRangeArgs<unknown>, 'decode'>): Promise<number>;
|
|
@@ -6,6 +6,7 @@ import { computeChunkId } from "./chunk-id.js";
|
|
|
6
6
|
import { decodeChunk, encodeChunk } from "./chunk-encoder.js";
|
|
7
7
|
import { parseManifest, serializeManifest } from "./manifest.js";
|
|
8
8
|
import { coldStoreArchiveBytesTotal, coldStoreArchiveCyclesTotal, coldStoreArchiveDurationSeconds, coldStoreArchiveRowsTotal, coldStorePurgeBytesTotal, coldStorePurgeChunksTotal, coldStorePurgeDurationSeconds, coldStoreRehydrateBytesTotal, coldStoreRehydrateDurationSeconds, coldStoreRehydrateRequestsTotal, coldStoreReplayDurationSeconds, coldStoreReplayRowsTotal, coldStoreVerifyFailuresTotal } from "./metrics.js";
|
|
9
|
+
import { resolveTableConfig } from "./config.js";
|
|
9
10
|
import { sha256 } from "@kici-dev/core";
|
|
10
11
|
import { DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
11
12
|
//#region src/cold-store/cold-store.ts
|
|
@@ -195,7 +196,7 @@ var BaseColdStore = class {
|
|
|
195
196
|
summary.skipped.disabled += 1;
|
|
196
197
|
return;
|
|
197
198
|
}
|
|
198
|
-
const warmCutoff =
|
|
199
|
+
const warmCutoff = this.warmCutoff(adapter.table);
|
|
199
200
|
let rowsThisCycle = 0;
|
|
200
201
|
for await (const { tenantId, partitionDate } of adapter.listEligiblePartitions({ warmCutoff })) {
|
|
201
202
|
if (rowsThisCycle >= adapter.config.maxRowsPerCycle) {
|
|
@@ -561,17 +562,22 @@ var BaseColdStore = class {
|
|
|
561
562
|
ContentType: "application/json"
|
|
562
563
|
}));
|
|
563
564
|
}
|
|
565
|
+
warmCutoff(table) {
|
|
566
|
+
const cfg = this.adapters.get(table)?.config ?? resolveTableConfig(this.config.tables[table]);
|
|
567
|
+
return /* @__PURE__ */ new Date(Date.now() - cfg.warmTtlDays * 864e5);
|
|
568
|
+
}
|
|
564
569
|
async *fetchRange(args) {
|
|
565
570
|
if (!this.config.enabled) return;
|
|
566
571
|
const adapter = this.adapters.get(args.table);
|
|
567
572
|
const decodeLine = args.decode ?? (adapter ? (line) => adapter.decodeRow(line) : (line) => JSON.parse(line));
|
|
568
573
|
const rowTimestamp = adapter ? (row) => this.toDate(adapter.rowTimestamp(row)) : null;
|
|
574
|
+
const toTs = args.toTs ?? this.warmCutoff(args.table);
|
|
569
575
|
const manifests = await this.listRelevantManifests({
|
|
570
576
|
db: args.db,
|
|
571
577
|
table: args.table,
|
|
572
578
|
tenantId: args.tenantId,
|
|
573
579
|
fromTs: args.fromTs,
|
|
574
|
-
toTs
|
|
580
|
+
toTs
|
|
575
581
|
});
|
|
576
582
|
const label = {
|
|
577
583
|
db: args.db,
|
|
@@ -597,7 +603,7 @@ var BaseColdStore = class {
|
|
|
597
603
|
})) {
|
|
598
604
|
if (rowTimestamp) {
|
|
599
605
|
const ts = rowTimestamp(row);
|
|
600
|
-
if (ts < args.fromTs || ts >=
|
|
606
|
+
if (ts < args.fromTs || ts >= toTs) continue;
|
|
601
607
|
}
|
|
602
608
|
yield row;
|
|
603
609
|
}
|
|
@@ -605,11 +611,17 @@ var BaseColdStore = class {
|
|
|
605
611
|
}
|
|
606
612
|
async hasRange(args) {
|
|
607
613
|
if (!this.config.enabled) return false;
|
|
608
|
-
return (await this.listRelevantManifests(
|
|
614
|
+
return (await this.listRelevantManifests({
|
|
615
|
+
...args,
|
|
616
|
+
toTs: args.toTs ?? this.warmCutoff(args.table)
|
|
617
|
+
})).length > 0;
|
|
609
618
|
}
|
|
610
619
|
async countRange(args) {
|
|
611
620
|
if (!this.config.enabled) return 0;
|
|
612
|
-
const manifests = await this.listRelevantManifests(
|
|
621
|
+
const manifests = await this.listRelevantManifests({
|
|
622
|
+
...args,
|
|
623
|
+
toTs: args.toTs ?? this.warmCutoff(args.table)
|
|
624
|
+
});
|
|
613
625
|
let total = 0;
|
|
614
626
|
for (const m of manifests) total += m.rowCount;
|
|
615
627
|
return total;
|
package/dist/cold-store/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { computeChunkId } from "./chunk-id.js";
|
|
|
5
5
|
import { decodeChunk, encodeChunk } from "./chunk-encoder.js";
|
|
6
6
|
import { parseManifest, serializeManifest } from "./manifest.js";
|
|
7
7
|
import { coldStoreArchiveBytesTotal, coldStoreArchiveCyclesTotal, coldStoreArchiveDurationSeconds, coldStoreArchiveRowsTotal, coldStorePurgeBytesTotal, coldStorePurgeChunksTotal, coldStorePurgeDurationSeconds, coldStoreRehydrateBytesTotal, coldStoreRehydrateDurationSeconds, coldStoreRehydrateRequestsTotal, coldStoreReplayDurationSeconds, coldStoreReplayRowsTotal, coldStoreVerifyFailuresTotal } from "./metrics.js";
|
|
8
|
+
import { DEFAULT_TABLE_CONFIG, resolveTableConfig } from "./config.js";
|
|
8
9
|
import { BaseColdStore } from "./cold-store.js";
|
|
9
10
|
import { ChunkLru } from "./lru.js";
|
|
10
|
-
import { DEFAULT_TABLE_CONFIG, resolveTableConfig } from "./config.js";
|
|
11
11
|
export { BaseColdStore, COLD_BUCKET_NAMES, ChunkLru, DEFAULT_TABLE_CONFIG, chunkObjectKey, coldDaysToBucket, coldStoreArchiveBytesTotal, coldStoreArchiveCyclesTotal, coldStoreArchiveDurationSeconds, coldStoreArchiveRowsTotal, coldStorePurgeBytesTotal, coldStorePurgeChunksTotal, coldStorePurgeDurationSeconds, coldStoreRehydrateBytesTotal, coldStoreRehydrateDurationSeconds, coldStoreRehydrateRequestsTotal, coldStoreReplayDurationSeconds, coldStoreReplayRowsTotal, coldStoreVerifyFailuresTotal, computeChunkId, decodeChunk, encodeChunk, encodeKeySegment, isLongerColdRetention, parseManifest, resolveTableConfig, serializeManifest, tablePrefix, tenantDayBucketPrefix, tenantDayPrefix };
|
package/dist/db-admin.d.ts
CHANGED
|
@@ -178,22 +178,22 @@ export declare function purgeScopedSecretsDirect(databaseUrl: string, orgId?: st
|
|
|
178
178
|
deleted: number;
|
|
179
179
|
}>;
|
|
180
180
|
/**
|
|
181
|
-
* Bulk-delete `
|
|
182
|
-
* every org when `orgId` is omitted. `
|
|
183
|
-
* `
|
|
181
|
+
* Bulk-delete `contexts` (and their FK-dependent rows) for an org, or for
|
|
182
|
+
* every org when `orgId` is omitted. `context_bindings` /
|
|
183
|
+
* `context_variables` / `context_source_overrides` cascade
|
|
184
184
|
* automatically (ON DELETE CASCADE). `held_runs` and `execution_runs` reference
|
|
185
|
-
* `
|
|
186
|
-
* would leave orphaned `held_runs` rows carrying a null
|
|
185
|
+
* `contexts(id)` with ON DELETE SET NULL, so deleting contexts alone
|
|
186
|
+
* would leave orphaned `held_runs` rows carrying a null context reference;
|
|
187
187
|
* this helper deletes the org's `held_runs` too so a warm-start reset gets a
|
|
188
188
|
* clean slate. Runs in a transaction so both deletes commit atomically. Used by
|
|
189
|
-
* the E2E warm-start reset (so seeded
|
|
190
|
-
* categories) and exposed via `kici-admin
|
|
189
|
+
* the E2E warm-start reset (so seeded contexts don't leak between
|
|
190
|
+
* categories) and exposed via `kici-admin context purge`.
|
|
191
191
|
*/
|
|
192
|
-
export declare function
|
|
193
|
-
|
|
192
|
+
export declare function purgeContextsDirect(databaseUrl: string, orgId?: string): Promise<{
|
|
193
|
+
contextsDeleted: number;
|
|
194
194
|
heldRunsDeleted: number;
|
|
195
195
|
}>;
|
|
196
|
-
export interface
|
|
196
|
+
export interface SeedContextOpts {
|
|
197
197
|
orgId: string;
|
|
198
198
|
name: string;
|
|
199
199
|
type?: string;
|
|
@@ -205,52 +205,58 @@ export interface SeedEnvironmentOpts {
|
|
|
205
205
|
minimumTrust?: string | null;
|
|
206
206
|
globPattern?: string | null;
|
|
207
207
|
}
|
|
208
|
-
export interface
|
|
208
|
+
export interface SeedContextResult {
|
|
209
209
|
envId: string;
|
|
210
210
|
created: boolean;
|
|
211
211
|
}
|
|
212
212
|
/**
|
|
213
|
-
* Upsert
|
|
213
|
+
* Upsert a context row keyed by (org_id, name). Returns the env id and
|
|
214
214
|
* whether the row was newly inserted. `branchRestrictions` / `requiredReviewers`
|
|
215
215
|
* are JSON-serialised server-side; pass them as plain arrays or objects.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
*
|
|
217
|
+
* An omitted `holdExpirySeconds` is written as NULL rather than a literal
|
|
218
|
+
* window: the column carries no DDL default, so "never set" and "cleared" both
|
|
219
|
+
* land on NULL and resolve through the one `DEFAULT_HOLD_EXPIRY_SECONDS`
|
|
220
|
+
* fallback on read. Writing a literal here would give this path a second,
|
|
221
|
+
* longer default that no read-side code knows about.
|
|
222
|
+
*/
|
|
223
|
+
export declare function seedContextDirect(databaseUrl: string, opts: SeedContextOpts): Promise<SeedContextResult>;
|
|
224
|
+
export interface DeleteContextOpts {
|
|
219
225
|
orgId: string;
|
|
220
226
|
name: string;
|
|
221
227
|
}
|
|
222
228
|
/**
|
|
223
|
-
* Delete
|
|
224
|
-
* removed. The `
|
|
225
|
-
* `
|
|
226
|
-
* `FOREIGN KEY (
|
|
227
|
-
* so a single DELETE on `
|
|
229
|
+
* Delete a context keyed by (org_id, name). Returns whether a row was
|
|
230
|
+
* removed. The `context_bindings`, `context_variables`, and
|
|
231
|
+
* `context_source_overrides` children all carry
|
|
232
|
+
* `FOREIGN KEY (context_id) REFERENCES contexts(id) ON DELETE CASCADE`,
|
|
233
|
+
* so a single DELETE on `contexts` cascades to those children. The
|
|
228
234
|
* `held_runs` FK uses `ON DELETE SET NULL`, so terminal held-run history
|
|
229
|
-
* survives the delete with a null
|
|
230
|
-
* still reference the
|
|
235
|
+
* survives the delete with a null context reference. Pending held runs
|
|
236
|
+
* still reference the context, so this helper pre-checks their count and
|
|
231
237
|
* throws before issuing the DELETE — approve or reject them first.
|
|
232
238
|
*/
|
|
233
|
-
export declare function
|
|
239
|
+
export declare function deleteContextDirect(databaseUrl: string, opts: DeleteContextOpts): Promise<{
|
|
234
240
|
deleted: boolean;
|
|
235
241
|
}>;
|
|
236
|
-
export interface
|
|
242
|
+
export interface SeedContextBindingOpts {
|
|
237
243
|
orgId: string;
|
|
238
|
-
|
|
244
|
+
contextName: string;
|
|
239
245
|
scopePattern: string;
|
|
240
246
|
/** Host selector; defaults to `'**'` (all hosts). */
|
|
241
247
|
hostPattern?: string;
|
|
242
248
|
}
|
|
243
249
|
/**
|
|
244
|
-
* Upsert an `
|
|
245
|
-
* (scoped to `hostPattern`, default `'**'`). Throws if the
|
|
250
|
+
* Upsert an `context_bindings` row connecting `contextName` to `scopePattern`
|
|
251
|
+
* (scoped to `hostPattern`, default `'**'`). Throws if the context does
|
|
246
252
|
* not exist.
|
|
247
253
|
*/
|
|
248
|
-
export declare function
|
|
254
|
+
export declare function seedContextBindingDirect(databaseUrl: string, opts: SeedContextBindingOpts): Promise<{
|
|
249
255
|
created: boolean;
|
|
250
256
|
}>;
|
|
251
|
-
export interface
|
|
257
|
+
export interface SetContextPolicyOpts {
|
|
252
258
|
orgId: string;
|
|
253
|
-
|
|
259
|
+
contextName: string;
|
|
254
260
|
branchRestrictions?: unknown;
|
|
255
261
|
requiredReviewers?: unknown;
|
|
256
262
|
waitTimerSeconds?: number | null;
|
|
@@ -261,10 +267,10 @@ export interface SetEnvironmentPolicyOpts {
|
|
|
261
267
|
}
|
|
262
268
|
/**
|
|
263
269
|
* UPDATE only the policy fields that were explicitly provided. Columns that
|
|
264
|
-
* were NOT in `opts` are left untouched. Throws if the
|
|
270
|
+
* were NOT in `opts` are left untouched. Throws if the context is missing.
|
|
265
271
|
*/
|
|
266
|
-
export declare function
|
|
267
|
-
export interface
|
|
272
|
+
export declare function setContextPolicyDirect(databaseUrl: string, opts: SetContextPolicyOpts): Promise<void>;
|
|
273
|
+
export interface ContextRow {
|
|
268
274
|
id: string;
|
|
269
275
|
org_id: string;
|
|
270
276
|
name: string;
|
|
@@ -279,38 +285,38 @@ export interface EnvironmentRow {
|
|
|
279
285
|
updated_at: string;
|
|
280
286
|
}
|
|
281
287
|
/**
|
|
282
|
-
* SELECT * FROM
|
|
288
|
+
* SELECT * FROM contexts WHERE org_id = $1, ordered by name.
|
|
283
289
|
*/
|
|
284
|
-
export declare function
|
|
290
|
+
export declare function listContextsDirect(databaseUrl: string, opts: {
|
|
285
291
|
orgId: string;
|
|
286
292
|
}): Promise<{
|
|
287
|
-
|
|
293
|
+
contexts: ContextRow[];
|
|
288
294
|
}>;
|
|
289
|
-
export interface
|
|
295
|
+
export interface ContextVariableRow {
|
|
290
296
|
key: string;
|
|
291
297
|
value: string;
|
|
292
298
|
locked: boolean;
|
|
293
299
|
updated_at: string;
|
|
294
300
|
}
|
|
295
|
-
export interface
|
|
301
|
+
export interface ContextBindingRow {
|
|
296
302
|
scope_pattern: string;
|
|
297
303
|
host_pattern: string;
|
|
298
304
|
created_at: string;
|
|
299
305
|
}
|
|
300
|
-
export interface
|
|
301
|
-
|
|
302
|
-
variables:
|
|
303
|
-
bindings:
|
|
306
|
+
export interface ShowContextResult {
|
|
307
|
+
context: ContextRow;
|
|
308
|
+
variables: ContextVariableRow[];
|
|
309
|
+
bindings: ContextBindingRow[];
|
|
304
310
|
}
|
|
305
311
|
/**
|
|
306
|
-
* Fetch a single
|
|
307
|
-
* Throws if the
|
|
312
|
+
* Fetch a single context row joined with its variables and bindings.
|
|
313
|
+
* Throws if the context does not exist.
|
|
308
314
|
*/
|
|
309
|
-
export declare function
|
|
315
|
+
export declare function showContextDirect(databaseUrl: string, opts: {
|
|
310
316
|
orgId: string;
|
|
311
317
|
name: string;
|
|
312
|
-
}): Promise<
|
|
313
|
-
export interface
|
|
318
|
+
}): Promise<ShowContextResult>;
|
|
319
|
+
export interface CreateContextTemplateOpts {
|
|
314
320
|
orgId: string;
|
|
315
321
|
templateName: string;
|
|
316
322
|
type?: string;
|
|
@@ -322,27 +328,31 @@ export interface CreateEnvironmentTemplateOpts {
|
|
|
322
328
|
variables?: Record<string, string>;
|
|
323
329
|
}
|
|
324
330
|
/**
|
|
325
|
-
* Create (or update)
|
|
326
|
-
* transaction. Templates are represented as
|
|
331
|
+
* Create (or update) a context template + its seed variables in one
|
|
332
|
+
* transaction. Templates are represented as contexts with `type='template'`
|
|
327
333
|
* by convention. Returns `{ envId, variablesSet }`.
|
|
334
|
+
*
|
|
335
|
+
* An omitted `holdExpirySeconds` is written as NULL rather than a literal
|
|
336
|
+
* window, for the same reason as `seedContextDirect`: the column has no DDL
|
|
337
|
+
* default and every read resolves NULL through `DEFAULT_HOLD_EXPIRY_SECONDS`.
|
|
328
338
|
*/
|
|
329
|
-
export declare function
|
|
339
|
+
export declare function createContextTemplateDirect(databaseUrl: string, opts: CreateContextTemplateOpts): Promise<{
|
|
330
340
|
envId: string;
|
|
331
341
|
created: boolean;
|
|
332
342
|
variablesSet: number;
|
|
333
343
|
}>;
|
|
334
|
-
export interface
|
|
344
|
+
export interface SetContextSecretOpts {
|
|
335
345
|
orgId: string;
|
|
336
|
-
|
|
346
|
+
context: string;
|
|
337
347
|
key: string;
|
|
338
348
|
encryptedValue: string;
|
|
339
349
|
}
|
|
340
350
|
/**
|
|
341
|
-
* UPSERT a scoped_secrets row keyed by (org_id, scope=
|
|
351
|
+
* UPSERT a scoped_secrets row keyed by (org_id, scope=context, key).
|
|
342
352
|
* Writes the value verbatim — the caller is responsible for encryption
|
|
343
353
|
* (matches the stage-4 deferral noted in the plan).
|
|
344
354
|
*/
|
|
345
|
-
export declare function
|
|
355
|
+
export declare function setContextSecretDirect(databaseUrl: string, opts: SetContextSecretOpts): Promise<{
|
|
346
356
|
inserted: boolean;
|
|
347
357
|
}>;
|
|
348
358
|
export interface DispatchQueueRow {
|
|
@@ -400,7 +410,7 @@ export interface ExecutionRunRow {
|
|
|
400
410
|
ref: string;
|
|
401
411
|
sha: string;
|
|
402
412
|
routing_key: string | null;
|
|
403
|
-
|
|
413
|
+
context: string | null;
|
|
404
414
|
trust_tier: string | null;
|
|
405
415
|
created_at: string;
|
|
406
416
|
started_at: string;
|
|
@@ -419,8 +429,8 @@ export interface ExecutionJobRow {
|
|
|
419
429
|
duration_ms: number | null;
|
|
420
430
|
created_at: string;
|
|
421
431
|
error_message: string | null;
|
|
422
|
-
/** Ordered bound deployment-
|
|
423
|
-
|
|
432
|
+
/** Ordered bound deployment-context names (JSON-encoded `string[]`), or null. */
|
|
433
|
+
contexts: string | null;
|
|
424
434
|
}
|
|
425
435
|
export interface ListExecutionRunsOpts {
|
|
426
436
|
routingKey?: string;
|
|
@@ -435,6 +445,79 @@ export interface ListExecutionRunsOpts {
|
|
|
435
445
|
export declare function listExecutionRunsDirect(databaseUrl: string, opts?: ListExecutionRunsOpts): Promise<{
|
|
436
446
|
runs: ExecutionRunRow[];
|
|
437
447
|
}>;
|
|
448
|
+
/**
|
|
449
|
+
* One `check_run_tracking` row: the orchestrator's record of a check run it posted.
|
|
450
|
+
*
|
|
451
|
+
* Named `...DirectRow` rather than `CheckRunTrackingRow` because the
|
|
452
|
+
* orchestrator's own `db/types.ts` already exports that name for the Kysely
|
|
453
|
+
* `Selectable`, whose `check_run_id` is a `number`. Two same-named types with
|
|
454
|
+
* different field types, both in scope inside the orchestrator package, is a
|
|
455
|
+
* silent-comparison-bug waiting to happen.
|
|
456
|
+
*/
|
|
457
|
+
export interface CheckRunTrackingDirectRow {
|
|
458
|
+
provider: string;
|
|
459
|
+
owner: string;
|
|
460
|
+
repo: string;
|
|
461
|
+
sha: string;
|
|
462
|
+
check_name: string;
|
|
463
|
+
/**
|
|
464
|
+
* The id the provider returned when the check run was CREATED. It is written
|
|
465
|
+
* once, at create time, when the check run is still `queued` — the later
|
|
466
|
+
* terminal update is a PATCH that writes nothing here. So a non-null value
|
|
467
|
+
* proves creation, NOT that the check run reached a conclusion.
|
|
468
|
+
*
|
|
469
|
+
* Null does not prove the create failed either: the write is best-effort and
|
|
470
|
+
* falls back to cache-only on a DB error, so the check run can exist at the
|
|
471
|
+
* provider with no id recorded here.
|
|
472
|
+
*
|
|
473
|
+
* Selected as `::text` because the column is BIGINT and node-postgres maps
|
|
474
|
+
* int8 to a string to avoid precision loss. The cast makes that explicit in
|
|
475
|
+
* the query rather than depending on driver defaults, so adding a global
|
|
476
|
+
* int8 type parser later cannot silently change this field's type.
|
|
477
|
+
*/
|
|
478
|
+
check_run_id: string | null;
|
|
479
|
+
/**
|
|
480
|
+
* `'pending'` is stamped BEFORE the create call and `'completed'` after it
|
|
481
|
+
* returns an id. Nothing resets it when a create fails, so a row stuck on
|
|
482
|
+
* `'pending'` means the create never returned — still in flight or
|
|
483
|
+
* permanently failed, which this column alone cannot distinguish.
|
|
484
|
+
*/
|
|
485
|
+
build_creation_state: string | null;
|
|
486
|
+
run_id: string | null;
|
|
487
|
+
/**
|
|
488
|
+
* Written only for per-job check names (`kici/<workflow>/job/<job>`). The
|
|
489
|
+
* workflow-level `kici/<workflow>` row always has null here.
|
|
490
|
+
*/
|
|
491
|
+
in_progress_sent_at: Date | null;
|
|
492
|
+
/**
|
|
493
|
+
* When the terminal (`completed`) update was accepted by the provider. This
|
|
494
|
+
* is the column that answers "did we complete it?" — `check_run_id` only
|
|
495
|
+
* answers "did we create it?".
|
|
496
|
+
*
|
|
497
|
+
* Best-effort like every write on this table, so null means "we have no
|
|
498
|
+
* record of sending it", not "it was never sent".
|
|
499
|
+
*/
|
|
500
|
+
terminal_sent_at: Date | null;
|
|
501
|
+
}
|
|
502
|
+
export interface ListCheckRunTrackingOpts {
|
|
503
|
+
sha: string;
|
|
504
|
+
checkName?: string;
|
|
505
|
+
limit?: number;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* READ-ONLY: SELECT check_run_tracking rows for a commit. One row per
|
|
509
|
+
* `(provider, owner, repo, sha, check_name)`, ordered by check_name.
|
|
510
|
+
*
|
|
511
|
+
* Each column answers a different question. `check_run_id` is written once,
|
|
512
|
+
* when the check run is created in the `queued` state, so it answers "did we
|
|
513
|
+
* create it?". `terminal_sent_at` is stamped only after the provider accepts
|
|
514
|
+
* the terminal `completed` PATCH, so it answers "did we complete it?". Every
|
|
515
|
+
* write here is best-effort, so a null column is "no record", never proof of
|
|
516
|
+
* failure — see the per-field notes for what each one does and does not prove.
|
|
517
|
+
*/
|
|
518
|
+
export declare function listCheckRunTrackingDirect(databaseUrl: string, opts: ListCheckRunTrackingOpts): Promise<{
|
|
519
|
+
rows: CheckRunTrackingDirectRow[];
|
|
520
|
+
}>;
|
|
438
521
|
/**
|
|
439
522
|
* READ-ONLY: fetch a single run by run_id AND its jobs. Throws if no run
|
|
440
523
|
* matches the run_id. Jobs list may be empty for pending runs.
|
|
@@ -869,7 +952,7 @@ export interface SeedUniversalGitSourceOpts {
|
|
|
869
952
|
export declare function seedUniversalGitSourceDirect(databaseUrl: string, opts: SeedUniversalGitSourceOpts): Promise<void>;
|
|
870
953
|
/**
|
|
871
954
|
* Seed the ci-security orchestrator fixtures expected by the security
|
|
872
|
-
* pipeline e2e: sources row for dashboard orgId resolution,
|
|
955
|
+
* pipeline e2e: sources row for dashboard orgId resolution, context,
|
|
873
956
|
* two execution_runs (unknown + trusted), two execution_jobs, and a
|
|
874
957
|
* security held_run for the unknown contributor.
|
|
875
958
|
*
|
|
@@ -877,7 +960,7 @@ export declare function seedUniversalGitSourceDirect(databaseUrl: string, opts:
|
|
|
877
960
|
*/
|
|
878
961
|
export interface SeedCiSecurityFixturesOpts {
|
|
879
962
|
orgId: string;
|
|
880
|
-
|
|
963
|
+
contextName?: string;
|
|
881
964
|
sourceName?: string;
|
|
882
965
|
sourceRoutingKey?: string;
|
|
883
966
|
runsRoutingKey: string;
|
|
@@ -887,24 +970,80 @@ export interface SeedCiSecurityFixturesOpts {
|
|
|
887
970
|
trustedRunId: string;
|
|
888
971
|
trustedDeliveryId: string;
|
|
889
972
|
trustedJobId: string;
|
|
973
|
+
/**
|
|
974
|
+
* Second PR on the SAME repo (`repo_identifier='.'`, `pr_number=2`) with its
|
|
975
|
+
* own pending security hold. Seeded so PR-scoping tests can prove that a
|
|
976
|
+
* `/kici approve` on the first PR (pr_number=1) leaves this one held.
|
|
977
|
+
*/
|
|
978
|
+
secondPrRunId: string;
|
|
979
|
+
secondPrDeliveryId: string;
|
|
980
|
+
secondPrJobId: string;
|
|
981
|
+
/**
|
|
982
|
+
* Hold on a DIFFERENT repo (`repo_identifier='other/repo'`, `pr_number=1`) —
|
|
983
|
+
* same PR number as the first hold but a different repo, proving the scoping
|
|
984
|
+
* isolates on repo as well as PR number.
|
|
985
|
+
*/
|
|
986
|
+
otherRepoRunId: string;
|
|
987
|
+
otherRepoDeliveryId: string;
|
|
988
|
+
otherRepoJobId: string;
|
|
989
|
+
/**
|
|
990
|
+
* Workflow-modification hold (`repo_identifier='.'`, `pr_number=3`,
|
|
991
|
+
* `reason='workflow_modification'`) — the hold a non-trusted contributor's
|
|
992
|
+
* workflow-editing PR produces. Seeded so the PR-scoped `/kici approve`
|
|
993
|
+
* (which joins on `pr_number`) can find and resolve it.
|
|
994
|
+
*/
|
|
995
|
+
wfModRunId: string;
|
|
996
|
+
wfModDeliveryId: string;
|
|
997
|
+
wfModJobId: string;
|
|
998
|
+
/**
|
|
999
|
+
* Fork-PR hold (`repo_identifier='.'`, `pr_number=4`, `reason='fork_pr'`) —
|
|
1000
|
+
* the hold the org trust policy's fork arm produces. Reachable only since the
|
|
1001
|
+
* policy became enforced, so it is seeded to prove PR-scoped selection and
|
|
1002
|
+
* approval work for it exactly as they do for the workflow-modification hold.
|
|
1003
|
+
*/
|
|
1004
|
+
forkPrRunId: string;
|
|
1005
|
+
forkPrDeliveryId: string;
|
|
1006
|
+
forkPrJobId: string;
|
|
890
1007
|
}
|
|
891
1008
|
export interface SeedCiSecurityFixturesResult {
|
|
1009
|
+
/**
|
|
1010
|
+
* The context name the fixture seeded (the `contextName` option, or its
|
|
1011
|
+
* default). Assertions build the expected `held_runs.reason` from this rather
|
|
1012
|
+
* than re-deriving the name, so an override cannot desync them.
|
|
1013
|
+
*/
|
|
1014
|
+
contextName: string;
|
|
892
1015
|
envId: string;
|
|
1016
|
+
/** Held run for the unknown contributor (repo `.`, pr_number 1). */
|
|
893
1017
|
heldRunId: string;
|
|
1018
|
+
/** Held run for the same-repo second PR (repo `.`, pr_number 2). */
|
|
1019
|
+
secondHeldRunId: string;
|
|
1020
|
+
/** Held run for the different-repo run (repo `other/repo`, pr_number 1). */
|
|
1021
|
+
otherRepoHeldRunId: string;
|
|
1022
|
+
/** Held run for the workflow-modification PR (repo `.`, pr_number 3). */
|
|
1023
|
+
wfModHeldRunId: string;
|
|
1024
|
+
/** Held run for the fork PR (repo `.`, pr_number 4). */
|
|
1025
|
+
forkPrHeldRunId: string;
|
|
894
1026
|
}
|
|
1027
|
+
/** repo_identifier used for the different-repo isolation hold. */
|
|
1028
|
+
export declare const CI_SECURITY_OTHER_REPO = "other/repo";
|
|
895
1029
|
export declare function seedCiSecurityFixturesDirect(databaseUrl: string, opts: SeedCiSecurityFixturesOpts): Promise<SeedCiSecurityFixturesResult>;
|
|
896
1030
|
/**
|
|
897
|
-
* Poll `execution_runs` for
|
|
898
|
-
* `
|
|
899
|
-
*
|
|
1031
|
+
* Poll `execution_runs` for the newest run started since `since` whose status
|
|
1032
|
+
* is in `statuses`, returning that status. Resolves `{ status: null }` if the
|
|
1033
|
+
* deadline passes before any run reaches a target status.
|
|
1034
|
+
*
|
|
1035
|
+
* Callers wanting "did the run finish?" pass the terminal status set and read
|
|
1036
|
+
* the landed status — a terminal failure is reported immediately rather than
|
|
1037
|
+
* indistinguishable from a timeout. Used by the cluster reroute tests to gate
|
|
1038
|
+
* on a workflow reaching a terminal state after a webhook trigger.
|
|
900
1039
|
*/
|
|
901
|
-
export declare function
|
|
902
|
-
status: string;
|
|
1040
|
+
export declare function waitForExecutionRunReachesStatusSinceDirect(databaseUrl: string, opts: {
|
|
903
1041
|
since: Date;
|
|
1042
|
+
statuses: readonly string[];
|
|
904
1043
|
timeoutMs?: number;
|
|
905
1044
|
intervalMs?: number;
|
|
906
1045
|
}): Promise<{
|
|
907
|
-
|
|
1046
|
+
status: string | null;
|
|
908
1047
|
}>;
|
|
909
1048
|
/**
|
|
910
1049
|
* Fetch the most recent `execution_runs` row matching `status`, plus its
|
|
@@ -1250,6 +1389,7 @@ export declare function bumpRegistryVersionSimpleDirect(databaseUrl: string, opt
|
|
|
1250
1389
|
export declare function upsertCronLastFiredDirect(databaseUrl: string, opts: {
|
|
1251
1390
|
registrationId: string;
|
|
1252
1391
|
agoInterval: string;
|
|
1392
|
+
scheduleKey: string;
|
|
1253
1393
|
}): Promise<void>;
|
|
1254
1394
|
/**
|
|
1255
1395
|
* READ-ONLY: count cron_last_fired rows for a registration. Used by
|
|
@@ -1264,6 +1404,7 @@ export declare function countCronLastFiredDirect(databaseUrl: string, opts: {
|
|
|
1264
1404
|
*/
|
|
1265
1405
|
export declare function insertCronLastFiredNowDirect(databaseUrl: string, opts: {
|
|
1266
1406
|
registrationId: string;
|
|
1407
|
+
scheduleKey: string;
|
|
1267
1408
|
}): Promise<void>;
|
|
1268
1409
|
/**
|
|
1269
1410
|
* DELETE cron_last_fired rows for a registration. Teardown helper.
|