@straiffi/archon 1.8.19 → 1.8.21
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/client/assets/{ActivityView-BaoAJ8JM.js → ActivityView-BcguXTZ5.js} +1 -1
- package/dist/client/assets/GitHubActionsDialog-BGecTzoq.js +1 -0
- package/dist/client/assets/VerificationDialog-D4QkMLZr.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-8hDT9YFW.js → architectureDiagram-3BPJPVTR-DnC7Twj0.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-DrSgZhh1.js → blockDiagram-GPEHLZMM-D0VbjiKd.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-BjowoLmV.js → c4Diagram-AAUBKEIU-CzQ3l15K.js} +1 -1
- package/dist/client/assets/channel-BwRO4uiw.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-BwZDhXTf.js → chunk-2J33WTMH-B5UGiqLW.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-CVc43Ukf.js → chunk-3OPIFGDE-SCksTqtu.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-D5FDCGhy.js → chunk-5ZQYHXKU-IOkwLOtG.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-CJSR5Mh2.js → chunk-727SXJPM-Do60Xs9p.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-B6kTsClX.js → chunk-AQP2D5EJ-CuQT3imB.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-C5UH_dAR.js → chunk-CSCIHK7Q-BkxMIESX.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-D_rzcB2b.js → chunk-KSCS5N6A-uUU3sWgR.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-CztP7jdd.js → chunk-L5ZTLDWV-DLYccV6J.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-wTLCL7Pg.js → chunk-LZXEDZCA-CgJFfCRZ.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-B5AHIrUy.js → chunk-ND2GUHAM-D7IQSQfK.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-D3MtrIk4.js → chunk-NZK2D7GU-B4O6JWAo.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-iIPXNV3t.js → chunk-O5CBEL6O-DidlQEqb.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-Cwu-Oylq.js → chunk-WU5MYG2G-2-oq_Gue.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BIszcze-.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-D5dvxldS.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-D3wiIOnk.js → dagre-BM42HDAG-TubuN0hR.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-Bysb-ntU.js → diagram-2AECGRRQ-DNcUk6rV.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-CtS_bpE5.js → diagram-5GNKFQAL-B1sJn4w_.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-_PI56fZq.js → diagram-KO2AKTUF-CnW6ZuQe.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-BNgWnFoz.js → diagram-LMA3HP47-YHUmDzyS.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-BM-wG_lJ.js → diagram-OG6HWLK6-BkOQphxq.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-BPqNBsVc.js → erDiagram-TEJ5UH35-oNMxAdxN.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BgA6MiBD.js → flowDiagram-I6XJVG4X-ByuCV-Am.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-BMDzgC7L.js → ganttDiagram-6RSMTGT7-CRkNH8Ft.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-C0cZUYmG.js → gitGraphDiagram-PVQCEYII-DRXzXjd8.js} +1 -1
- package/dist/client/assets/index-CYPgEn1h.css +2 -0
- package/dist/client/assets/index-Ck2OKMsl.js +276 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-DelAWwhC.js → infoDiagram-5YYISTIA-CJ4-hWch.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-D62h0NJG.js → ishikawaDiagram-YF4QCWOH-CW1xqvim.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BXwYQf_j.js → journeyDiagram-JHISSGLW-BVVFg8_h.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-x5KfcIYo.js → kanban-definition-UN3LZRKU-AcLZ63tA.js} +1 -1
- package/dist/client/assets/{line-Blzshjst.js → line-CG_TG6Ci.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-Dnu-fpL9.js → mermaid-parser.core-UDLSm_c3.js} +1 -1
- package/dist/client/assets/{mermaid.core-BngDHztH.js → mermaid.core-IvBk22DF.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-BRB9WnNL.js → mindmap-definition-RKZ34NQL-BflWNtnl.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-Ddzhxmp2.js → pieDiagram-4H26LBE5-Dm1iGMm7.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CWKRt2y6.js → quadrantDiagram-W4KKPZXB-CM4zJd_R.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-D309qLEz.js → requirementDiagram-4Y6WPE33-miuP86cp.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-0Ukkluzd.js → sankeyDiagram-5OEKKPKP-zUcRagtr.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DkvDbOkQ.js → sequenceDiagram-3UESZ5HK-BRYqVpsT.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-LRTZRjK3.js → stateDiagram-AJRCARHV-DwcF0DJm.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DmICWsmn.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-CTwwDhpg.js → timeline-definition-PNZ67QCA-BzH929s_.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-BqldUpJn.js → vennDiagram-CIIHVFJN-BIq8rooy.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DPCPZAsx.js → wardleyDiagram-YWT4CUSO-CyV_gL5J.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-DWkIjgNu.js → xychartDiagram-2RQKCTM6-Dxo-U-qe.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +431 -1
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +77 -17
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent.js +8 -4
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/agentProvider.js +8 -1
- package/dist/server/lib/agentProvider.js.map +1 -1
- package/dist/server/lib/automationProgression.js +44 -14
- package/dist/server/lib/automationProgression.js.map +1 -1
- package/dist/server/lib/buildCompletionContinuation.js +14 -3
- package/dist/server/lib/buildCompletionContinuation.js.map +1 -1
- package/dist/server/lib/buildExecutionEnvironment.js +226 -59
- package/dist/server/lib/buildExecutionEnvironment.js.map +1 -1
- package/dist/server/lib/buildOpenQuestionOperations.js +47 -3
- package/dist/server/lib/buildOpenQuestionOperations.js.map +1 -1
- package/dist/server/lib/buildSequences.js +267 -18
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/buildSetupAuthority.js +138 -0
- package/dist/server/lib/buildSetupAuthority.js.map +1 -0
- package/dist/server/lib/bundleReviewOperations.js +15 -4
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/dockerSandboxCredentials.js +64 -10
- package/dist/server/lib/dockerSandboxCredentials.js.map +1 -1
- package/dist/server/lib/dockerSandboxExecutionProvider.js +11 -2
- package/dist/server/lib/dockerSandboxExecutionProvider.js.map +1 -1
- package/dist/server/lib/executionCredentialCapabilities.js +106 -0
- package/dist/server/lib/executionCredentialCapabilities.js.map +1 -0
- package/dist/server/lib/executionEnvironment.js.map +1 -1
- package/dist/server/lib/executionEnvironmentContexts.js +55 -1
- package/dist/server/lib/executionEnvironmentContexts.js.map +1 -1
- package/dist/server/lib/executionEnvironmentRoutes.js +76 -5
- package/dist/server/lib/executionEnvironmentRoutes.js.map +1 -1
- package/dist/server/lib/executionEnvironmentValidation.js +116 -44
- package/dist/server/lib/executionEnvironmentValidation.js.map +1 -1
- package/dist/server/lib/executionEnvironmentValidationOperations.js +48 -8
- package/dist/server/lib/executionEnvironmentValidationOperations.js.map +1 -1
- package/dist/server/lib/executionEnvironments.js +92 -9
- package/dist/server/lib/executionEnvironments.js.map +1 -1
- package/dist/server/lib/executionProfileRoutes.js +67 -0
- package/dist/server/lib/executionProfileRoutes.js.map +1 -0
- package/dist/server/lib/executionProfileStore.js +108 -0
- package/dist/server/lib/executionProfileStore.js.map +1 -0
- package/dist/server/lib/executionProfiles.js +201 -0
- package/dist/server/lib/executionProfiles.js.map +1 -0
- package/dist/server/lib/executionReconciliation.js +151 -66
- package/dist/server/lib/executionReconciliation.js.map +1 -1
- package/dist/server/lib/executionRetry.js +24 -5
- package/dist/server/lib/executionRetry.js.map +1 -1
- package/dist/server/lib/executionRunAuthority.js +299 -0
- package/dist/server/lib/executionRunAuthority.js.map +1 -0
- package/dist/server/lib/executionRuns.js +4 -0
- package/dist/server/lib/executionRuns.js.map +1 -1
- package/dist/server/lib/git.js +25 -0
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/hostExecutionEnvironment.js +7 -1
- package/dist/server/lib/hostExecutionEnvironment.js.map +1 -1
- package/dist/server/lib/integrations/github.js +44 -0
- package/dist/server/lib/integrations/github.js.map +1 -1
- package/dist/server/lib/projects.js +1 -0
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/run.js +58 -2
- package/dist/server/lib/run.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +32 -6
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/transcriptRuns.js +3 -0
- package/dist/server/lib/transcriptRuns.js.map +1 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/lib/workspaceProcessEnvironment.js +72 -1
- package/dist/server/lib/workspaceProcessEnvironment.js.map +1 -1
- package/dist/server/workers/build.js +214 -46
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/followUp.js +74 -1
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/review.js +15 -4
- package/dist/server/workers/review.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/GitHubActionsDialog-D7iT7xTt.js +0 -1
- package/dist/client/assets/VerificationDialog-ayyiyvGt.js +0 -4
- package/dist/client/assets/channel-CGc3oFdr.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-CBhybRSO.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C9ErMU7v.js +0 -1
- package/dist/client/assets/index-Ci2Or91O.js +0 -275
- package/dist/client/assets/index-CsZfTdMO.css +0 -2
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BDLRoPbQ.js +0 -1
package/dist/server/db.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createHash } from 'crypto';
|
|
|
3
3
|
import { parseCheckDefinitionsJsonStrict, parseLegacyTestCommandsJsonStrict, projectCheckDefinitionsToTestCommands, } from './lib/checkDefinitions.js';
|
|
4
4
|
import { ensureParentDirectory, resolveArchonDbPath } from './lib/runtimePaths.js';
|
|
5
5
|
import { TRANSCRIPT_RUN_TEXT_LIMIT_BYTES, truncateUtf8 } from './lib/transcriptRuns.js';
|
|
6
|
+
import { createExecutionProfile, fingerprintExecutionProfile, serializeExecutionProfile, } from './lib/executionProfiles.js';
|
|
6
7
|
const dbPath = ensureParentDirectory(resolveArchonDbPath());
|
|
7
8
|
const db = new Database(dbPath);
|
|
8
9
|
db.pragma('foreign_keys = ON');
|
|
@@ -55,6 +56,7 @@ db.exec(`
|
|
|
55
56
|
name TEXT NOT NULL,
|
|
56
57
|
repo_path TEXT NOT NULL,
|
|
57
58
|
build_execution_provider TEXT NOT NULL DEFAULT 'host' CHECK (build_execution_provider IN ('host', 'docker_sandbox')),
|
|
59
|
+
active_execution_profile_revision_id TEXT NOT NULL DEFAULT '',
|
|
58
60
|
active_target_kind TEXT NOT NULL DEFAULT 'repo_root',
|
|
59
61
|
active_target_bundle_id TEXT,
|
|
60
62
|
worktree_cmd TEXT,
|
|
@@ -148,6 +150,7 @@ db.exec('UPDATE worktree_bundles SET required_check_policy_override = NULL WHERE
|
|
|
148
150
|
ensureColumn('projects', 'worktree_sync', 'TEXT');
|
|
149
151
|
ensureColumn('projects', 'build_execution_provider', "TEXT NOT NULL DEFAULT 'host'");
|
|
150
152
|
db.exec("UPDATE projects SET build_execution_provider = 'host' WHERE build_execution_provider IS NULL OR build_execution_provider NOT IN ('host', 'docker_sandbox')");
|
|
153
|
+
ensureColumn('projects', 'active_execution_profile_revision_id', "TEXT NOT NULL DEFAULT ''");
|
|
151
154
|
ensureColumn('projects', 'active_target_kind', "TEXT NOT NULL DEFAULT 'repo_root'");
|
|
152
155
|
ensureColumn('projects', 'active_target_bundle_id', 'TEXT');
|
|
153
156
|
ensureColumn('projects', 'check_definitions', 'TEXT');
|
|
@@ -173,6 +176,175 @@ ensureColumn('projects', 'spec_aware_code_review_enabled', 'INTEGER NOT NULL DEF
|
|
|
173
176
|
ensureColumn('projects', 'deletion_started_at', 'DATETIME');
|
|
174
177
|
ensureColumn('projects', 'deletion_claim_id', 'TEXT');
|
|
175
178
|
ensureColumn('projects', 'deletion_cleanup_started_at', 'DATETIME');
|
|
179
|
+
db.exec(`
|
|
180
|
+
CREATE TABLE IF NOT EXISTS execution_profile_revisions (
|
|
181
|
+
id TEXT PRIMARY KEY,
|
|
182
|
+
project_id TEXT NOT NULL,
|
|
183
|
+
revision INTEGER NOT NULL CHECK (revision > 0),
|
|
184
|
+
schema_version INTEGER NOT NULL CHECK (schema_version = 1),
|
|
185
|
+
fingerprint TEXT NOT NULL CHECK (length(fingerprint) = 64),
|
|
186
|
+
profile_json TEXT NOT NULL CHECK (
|
|
187
|
+
json_valid(profile_json)
|
|
188
|
+
AND json_type(profile_json) = 'object'
|
|
189
|
+
AND length(CAST(profile_json AS BLOB)) BETWEEN 2 AND 16384
|
|
190
|
+
),
|
|
191
|
+
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
192
|
+
UNIQUE (project_id, revision),
|
|
193
|
+
UNIQUE (project_id, fingerprint),
|
|
194
|
+
UNIQUE (project_id, id),
|
|
195
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
CREATE TABLE IF NOT EXISTS execution_profile_audit_events (
|
|
199
|
+
id TEXT PRIMARY KEY,
|
|
200
|
+
project_id TEXT NOT NULL,
|
|
201
|
+
event_type TEXT NOT NULL CHECK (event_type IN ('revision_created', 'revision_activated')),
|
|
202
|
+
profile_revision_id TEXT NOT NULL,
|
|
203
|
+
previous_profile_revision_id TEXT,
|
|
204
|
+
metadata_json TEXT CHECK (
|
|
205
|
+
metadata_json IS NULL OR (
|
|
206
|
+
json_valid(metadata_json)
|
|
207
|
+
AND json_type(metadata_json) = 'object'
|
|
208
|
+
AND length(CAST(metadata_json AS BLOB)) BETWEEN 2 AND 16384
|
|
209
|
+
)
|
|
210
|
+
),
|
|
211
|
+
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
212
|
+
FOREIGN KEY (project_id, profile_revision_id)
|
|
213
|
+
REFERENCES execution_profile_revisions(project_id, id) ON DELETE CASCADE,
|
|
214
|
+
FOREIGN KEY (project_id, previous_profile_revision_id)
|
|
215
|
+
REFERENCES execution_profile_revisions(project_id, id) ON DELETE CASCADE
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
CREATE INDEX IF NOT EXISTS idx_execution_profile_revisions_project
|
|
219
|
+
ON execution_profile_revisions(project_id, revision DESC);
|
|
220
|
+
CREATE INDEX IF NOT EXISTS idx_execution_profile_audit_project
|
|
221
|
+
ON execution_profile_audit_events(project_id, created_at DESC, id DESC);
|
|
222
|
+
`);
|
|
223
|
+
const backfillExecutionProfiles = () => {
|
|
224
|
+
const projects = db.prepare(`
|
|
225
|
+
SELECT id, build_execution_provider, active_execution_profile_revision_id
|
|
226
|
+
FROM projects
|
|
227
|
+
`).all();
|
|
228
|
+
const findOwnedRevision = db.prepare(`
|
|
229
|
+
SELECT 1 FROM execution_profile_revisions WHERE project_id = ? AND id = ?
|
|
230
|
+
`);
|
|
231
|
+
const insertRevision = db.prepare(`
|
|
232
|
+
INSERT OR IGNORE INTO execution_profile_revisions (
|
|
233
|
+
id, project_id, revision, schema_version, fingerprint, profile_json
|
|
234
|
+
) VALUES (?, ?, 1, 1, ?, ?)
|
|
235
|
+
`);
|
|
236
|
+
const activateRevision = db.prepare(`
|
|
237
|
+
UPDATE projects SET active_execution_profile_revision_id = ? WHERE id = ?
|
|
238
|
+
`);
|
|
239
|
+
const insertEvent = db.prepare(`
|
|
240
|
+
INSERT OR IGNORE INTO execution_profile_audit_events (
|
|
241
|
+
id, project_id, event_type, profile_revision_id, previous_profile_revision_id
|
|
242
|
+
) VALUES (?, ?, 'revision_created', ?, NULL)
|
|
243
|
+
`);
|
|
244
|
+
db.transaction(() => {
|
|
245
|
+
for (const project of projects) {
|
|
246
|
+
if (project.active_execution_profile_revision_id
|
|
247
|
+
&& findOwnedRevision.get(project.id, project.active_execution_profile_revision_id)) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const profile = createExecutionProfile(project.build_execution_provider);
|
|
251
|
+
const profileJson = serializeExecutionProfile(profile);
|
|
252
|
+
const fingerprint = fingerprintExecutionProfile(profile);
|
|
253
|
+
const revisionId = `${project.id}:execution-profile:1`;
|
|
254
|
+
insertRevision.run(revisionId, project.id, fingerprint, profileJson);
|
|
255
|
+
activateRevision.run(revisionId, project.id);
|
|
256
|
+
insertEvent.run(`${revisionId}:created`, project.id, revisionId);
|
|
257
|
+
}
|
|
258
|
+
})();
|
|
259
|
+
};
|
|
260
|
+
backfillExecutionProfiles();
|
|
261
|
+
const hostCompatibilityProfile = createExecutionProfile('host');
|
|
262
|
+
const hostCompatibilityProfileJson = serializeExecutionProfile(hostCompatibilityProfile).replaceAll("'", "''");
|
|
263
|
+
const hostCompatibilityFingerprint = fingerprintExecutionProfile(hostCompatibilityProfile);
|
|
264
|
+
const dockerProfile = createExecutionProfile('docker_sandbox');
|
|
265
|
+
const dockerProfileJson = serializeExecutionProfile(dockerProfile).replaceAll("'", "''");
|
|
266
|
+
const dockerProfileFingerprint = fingerprintExecutionProfile(dockerProfile);
|
|
267
|
+
db.exec(`
|
|
268
|
+
CREATE TRIGGER IF NOT EXISTS create_project_execution_profile
|
|
269
|
+
AFTER INSERT ON projects
|
|
270
|
+
WHEN NEW.active_execution_profile_revision_id = ''
|
|
271
|
+
BEGIN
|
|
272
|
+
INSERT INTO execution_profile_revisions (
|
|
273
|
+
id, project_id, revision, schema_version, fingerprint, profile_json
|
|
274
|
+
) VALUES (
|
|
275
|
+
NEW.id || ':execution-profile:1', NEW.id, 1, 1,
|
|
276
|
+
CASE WHEN NEW.build_execution_provider = 'docker_sandbox'
|
|
277
|
+
THEN '${dockerProfileFingerprint}' ELSE '${hostCompatibilityFingerprint}' END,
|
|
278
|
+
CASE WHEN NEW.build_execution_provider = 'docker_sandbox'
|
|
279
|
+
THEN '${dockerProfileJson}' ELSE '${hostCompatibilityProfileJson}' END
|
|
280
|
+
);
|
|
281
|
+
UPDATE projects
|
|
282
|
+
SET active_execution_profile_revision_id = NEW.id || ':execution-profile:1'
|
|
283
|
+
WHERE id = NEW.id;
|
|
284
|
+
INSERT INTO execution_profile_audit_events (
|
|
285
|
+
id, project_id, event_type, profile_revision_id, previous_profile_revision_id
|
|
286
|
+
) VALUES (
|
|
287
|
+
NEW.id || ':execution-profile:1:created', NEW.id, 'revision_created',
|
|
288
|
+
NEW.id || ':execution-profile:1', NULL
|
|
289
|
+
);
|
|
290
|
+
END;
|
|
291
|
+
|
|
292
|
+
CREATE TRIGGER IF NOT EXISTS validate_project_execution_profile_owner_insert
|
|
293
|
+
BEFORE INSERT ON projects
|
|
294
|
+
WHEN NEW.active_execution_profile_revision_id <> '' AND NOT EXISTS (
|
|
295
|
+
SELECT 1 FROM execution_profile_revisions
|
|
296
|
+
WHERE project_id = NEW.id AND id = NEW.active_execution_profile_revision_id
|
|
297
|
+
)
|
|
298
|
+
BEGIN
|
|
299
|
+
SELECT RAISE(ABORT, 'Active execution profile revision is not owned by project');
|
|
300
|
+
END;
|
|
301
|
+
|
|
302
|
+
CREATE TRIGGER IF NOT EXISTS validate_project_execution_profile_owner_update
|
|
303
|
+
BEFORE UPDATE OF active_execution_profile_revision_id ON projects
|
|
304
|
+
WHEN NEW.active_execution_profile_revision_id = '' OR NOT EXISTS (
|
|
305
|
+
SELECT 1 FROM execution_profile_revisions
|
|
306
|
+
WHERE project_id = NEW.id AND id = NEW.active_execution_profile_revision_id
|
|
307
|
+
)
|
|
308
|
+
BEGIN
|
|
309
|
+
SELECT RAISE(ABORT, 'Active execution profile revision is not owned by project');
|
|
310
|
+
END;
|
|
311
|
+
|
|
312
|
+
CREATE TRIGGER IF NOT EXISTS validate_project_execution_profile_projection_insert
|
|
313
|
+
BEFORE INSERT ON projects
|
|
314
|
+
WHEN NEW.active_execution_profile_revision_id <> '' AND NOT EXISTS (
|
|
315
|
+
SELECT 1 FROM execution_profile_revisions
|
|
316
|
+
WHERE project_id = NEW.id
|
|
317
|
+
AND id = NEW.active_execution_profile_revision_id
|
|
318
|
+
AND json_extract(profile_json, '$.provider_preference') = NEW.build_execution_provider
|
|
319
|
+
)
|
|
320
|
+
BEGIN
|
|
321
|
+
SELECT RAISE(ABORT, 'Build execution provider must project the active execution profile');
|
|
322
|
+
END;
|
|
323
|
+
|
|
324
|
+
CREATE TRIGGER IF NOT EXISTS validate_project_execution_profile_projection_update
|
|
325
|
+
BEFORE UPDATE OF active_execution_profile_revision_id, build_execution_provider ON projects
|
|
326
|
+
WHEN NOT EXISTS (
|
|
327
|
+
SELECT 1 FROM execution_profile_revisions
|
|
328
|
+
WHERE project_id = NEW.id
|
|
329
|
+
AND id = NEW.active_execution_profile_revision_id
|
|
330
|
+
AND json_extract(profile_json, '$.provider_preference') = NEW.build_execution_provider
|
|
331
|
+
)
|
|
332
|
+
BEGIN
|
|
333
|
+
SELECT RAISE(ABORT, 'Build execution provider must project the active execution profile');
|
|
334
|
+
END;
|
|
335
|
+
|
|
336
|
+
CREATE TRIGGER IF NOT EXISTS preserve_execution_profile_revision
|
|
337
|
+
BEFORE UPDATE ON execution_profile_revisions
|
|
338
|
+
BEGIN
|
|
339
|
+
SELECT RAISE(ABORT, 'Execution profile revisions are immutable');
|
|
340
|
+
END;
|
|
341
|
+
|
|
342
|
+
CREATE TRIGGER IF NOT EXISTS preserve_execution_profile_audit_event
|
|
343
|
+
BEFORE UPDATE ON execution_profile_audit_events
|
|
344
|
+
BEGIN
|
|
345
|
+
SELECT RAISE(ABORT, 'Execution profile audit events are immutable');
|
|
346
|
+
END;
|
|
347
|
+
`);
|
|
176
348
|
const backfillProjectCheckDefinitions = () => {
|
|
177
349
|
const rows = db.prepare(`
|
|
178
350
|
SELECT id, check_definitions, test_commands
|
|
@@ -946,11 +1118,115 @@ db.exec(`
|
|
|
946
1118
|
entered_queue_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
947
1119
|
started_at DATETIME,
|
|
948
1120
|
finished_at DATETIME,
|
|
1121
|
+
execution_profile_revision_id TEXT,
|
|
1122
|
+
execution_profile_fingerprint TEXT,
|
|
1123
|
+
execution_profile_selection_reason TEXT,
|
|
1124
|
+
activation_execution_run_id TEXT,
|
|
949
1125
|
PRIMARY KEY (build_sequence_id, ticket_id),
|
|
950
1126
|
FOREIGN KEY (build_sequence_id) REFERENCES build_sequences(id) ON DELETE CASCADE,
|
|
951
1127
|
FOREIGN KEY (ticket_id) REFERENCES tickets(id) ON DELETE CASCADE
|
|
952
1128
|
)
|
|
953
1129
|
`);
|
|
1130
|
+
db.exec(`
|
|
1131
|
+
CREATE TABLE IF NOT EXISTS build_sequence_ticket_replacements (
|
|
1132
|
+
id TEXT PRIMARY KEY,
|
|
1133
|
+
build_sequence_id TEXT NOT NULL,
|
|
1134
|
+
ticket_id TEXT NOT NULL,
|
|
1135
|
+
position INTEGER NOT NULL,
|
|
1136
|
+
execution_profile_revision_id TEXT NOT NULL,
|
|
1137
|
+
execution_profile_fingerprint TEXT NOT NULL,
|
|
1138
|
+
execution_profile_selection_reason TEXT NOT NULL,
|
|
1139
|
+
replaced_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
1140
|
+
FOREIGN KEY (build_sequence_id) REFERENCES build_sequences(id) ON DELETE CASCADE,
|
|
1141
|
+
FOREIGN KEY (ticket_id) REFERENCES tickets(id) ON DELETE CASCADE
|
|
1142
|
+
)
|
|
1143
|
+
`);
|
|
1144
|
+
ensureColumn('build_sequence_tickets', 'execution_profile_revision_id', 'TEXT');
|
|
1145
|
+
ensureColumn('build_sequence_tickets', 'execution_profile_fingerprint', 'TEXT');
|
|
1146
|
+
ensureColumn('build_sequence_tickets', 'execution_profile_selection_reason', 'TEXT');
|
|
1147
|
+
ensureColumn('build_sequence_tickets', 'activation_execution_run_id', 'TEXT');
|
|
1148
|
+
db.transaction(() => {
|
|
1149
|
+
const incompleteSequenceIds = db.prepare(`
|
|
1150
|
+
SELECT DISTINCT build_sequence_id
|
|
1151
|
+
FROM build_sequence_tickets
|
|
1152
|
+
WHERE status IN ('active', 'queued')
|
|
1153
|
+
AND (
|
|
1154
|
+
execution_profile_revision_id IS NULL
|
|
1155
|
+
OR execution_profile_fingerprint IS NULL
|
|
1156
|
+
OR execution_profile_selection_reason IS NULL
|
|
1157
|
+
)
|
|
1158
|
+
`).all();
|
|
1159
|
+
const failActive = db.prepare(`
|
|
1160
|
+
UPDATE build_sequence_tickets
|
|
1161
|
+
SET status = 'failed', finished_at = COALESCE(finished_at, CURRENT_TIMESTAMP)
|
|
1162
|
+
WHERE build_sequence_id = ? AND status = 'active'
|
|
1163
|
+
`);
|
|
1164
|
+
const cancelQueued = db.prepare(`
|
|
1165
|
+
UPDATE build_sequence_tickets
|
|
1166
|
+
SET status = 'cancelled', finished_at = COALESCE(finished_at, CURRENT_TIMESTAMP)
|
|
1167
|
+
WHERE build_sequence_id = ? AND status = 'queued'
|
|
1168
|
+
`);
|
|
1169
|
+
const failSequence = db.prepare(`
|
|
1170
|
+
UPDATE build_sequences SET status = 'failed', updated_at = CURRENT_TIMESTAMP
|
|
1171
|
+
WHERE id = ? AND status = 'active'
|
|
1172
|
+
`);
|
|
1173
|
+
for (const row of incompleteSequenceIds) {
|
|
1174
|
+
failActive.run(row.build_sequence_id);
|
|
1175
|
+
cancelQueued.run(row.build_sequence_id);
|
|
1176
|
+
failSequence.run(row.build_sequence_id);
|
|
1177
|
+
}
|
|
1178
|
+
})();
|
|
1179
|
+
db.exec(`
|
|
1180
|
+
CREATE TRIGGER IF NOT EXISTS validate_build_sequence_ticket_profile_insert
|
|
1181
|
+
BEFORE INSERT ON build_sequence_tickets
|
|
1182
|
+
WHEN NEW.status IN ('active', 'queued')
|
|
1183
|
+
OR NEW.execution_profile_revision_id IS NOT NULL OR NEW.execution_profile_fingerprint IS NOT NULL
|
|
1184
|
+
OR NEW.execution_profile_selection_reason IS NOT NULL
|
|
1185
|
+
BEGIN
|
|
1186
|
+
SELECT CASE WHEN
|
|
1187
|
+
NEW.execution_profile_revision_id IS NULL
|
|
1188
|
+
OR NEW.execution_profile_fingerprint IS NULL
|
|
1189
|
+
OR NEW.execution_profile_selection_reason NOT IN ('project_active_at_acceptance', 'historical_lineage')
|
|
1190
|
+
OR NOT EXISTS (
|
|
1191
|
+
SELECT 1
|
|
1192
|
+
FROM execution_profile_revisions revision
|
|
1193
|
+
JOIN build_sequences sequence ON sequence.id = NEW.build_sequence_id
|
|
1194
|
+
WHERE revision.id = NEW.execution_profile_revision_id
|
|
1195
|
+
AND revision.project_id = sequence.project_id
|
|
1196
|
+
AND revision.fingerprint = NEW.execution_profile_fingerprint
|
|
1197
|
+
)
|
|
1198
|
+
THEN RAISE(ABORT, 'Invalid Build sequence execution profile selection') END;
|
|
1199
|
+
END;
|
|
1200
|
+
|
|
1201
|
+
CREATE TRIGGER IF NOT EXISTS validate_build_sequence_ticket_profile_activation
|
|
1202
|
+
BEFORE UPDATE OF status ON build_sequence_tickets
|
|
1203
|
+
WHEN NEW.status IN ('active', 'queued') AND (
|
|
1204
|
+
NEW.execution_profile_revision_id IS NULL
|
|
1205
|
+
OR NEW.execution_profile_fingerprint IS NULL
|
|
1206
|
+
OR NEW.execution_profile_selection_reason NOT IN ('project_active_at_acceptance', 'historical_lineage')
|
|
1207
|
+
OR NOT EXISTS (
|
|
1208
|
+
SELECT 1
|
|
1209
|
+
FROM execution_profile_revisions revision
|
|
1210
|
+
JOIN build_sequences sequence ON sequence.id = NEW.build_sequence_id
|
|
1211
|
+
WHERE revision.id = NEW.execution_profile_revision_id
|
|
1212
|
+
AND revision.project_id = sequence.project_id
|
|
1213
|
+
AND revision.fingerprint = NEW.execution_profile_fingerprint
|
|
1214
|
+
)
|
|
1215
|
+
)
|
|
1216
|
+
BEGIN
|
|
1217
|
+
SELECT RAISE(ABORT, 'Invalid Build sequence execution profile selection');
|
|
1218
|
+
END;
|
|
1219
|
+
|
|
1220
|
+
CREATE TRIGGER IF NOT EXISTS preserve_build_sequence_ticket_profile
|
|
1221
|
+
BEFORE UPDATE OF execution_profile_revision_id, execution_profile_fingerprint, execution_profile_selection_reason
|
|
1222
|
+
ON build_sequence_tickets
|
|
1223
|
+
WHEN NEW.execution_profile_revision_id IS NOT OLD.execution_profile_revision_id
|
|
1224
|
+
OR NEW.execution_profile_fingerprint IS NOT OLD.execution_profile_fingerprint
|
|
1225
|
+
OR NEW.execution_profile_selection_reason IS NOT OLD.execution_profile_selection_reason
|
|
1226
|
+
BEGIN
|
|
1227
|
+
SELECT RAISE(ABORT, 'Build sequence execution profile selection is immutable');
|
|
1228
|
+
END;
|
|
1229
|
+
`);
|
|
954
1230
|
db.exec(`
|
|
955
1231
|
CREATE TABLE IF NOT EXISTS ticket_dependencies (
|
|
956
1232
|
blocker_ticket_id TEXT NOT NULL,
|
|
@@ -2132,6 +2408,9 @@ db.exec(`
|
|
|
2132
2408
|
environment_revision INTEGER NOT NULL,
|
|
2133
2409
|
workspace_mode TEXT NOT NULL,
|
|
2134
2410
|
environment_validation_fingerprint TEXT NOT NULL,
|
|
2411
|
+
execution_profile_revision_id TEXT,
|
|
2412
|
+
execution_profile_fingerprint TEXT,
|
|
2413
|
+
credential_requirements_fingerprint TEXT,
|
|
2135
2414
|
template_identity TEXT,
|
|
2136
2415
|
template_digest TEXT,
|
|
2137
2416
|
agent_identity TEXT,
|
|
@@ -2151,6 +2430,7 @@ db.exec(`
|
|
|
2151
2430
|
last_used_at DATETIME,
|
|
2152
2431
|
stopped_at DATETIME,
|
|
2153
2432
|
retirement_started_at DATETIME,
|
|
2433
|
+
retirement_requested_at DATETIME,
|
|
2154
2434
|
cleanup_pending_at DATETIME,
|
|
2155
2435
|
retired_at DATETIME,
|
|
2156
2436
|
failed_at DATETIME,
|
|
@@ -2169,6 +2449,10 @@ db.exec(`
|
|
|
2169
2449
|
CHECK (environment_revision >= 1),
|
|
2170
2450
|
CHECK (workspace_mode = 'direct'),
|
|
2171
2451
|
CHECK (length(environment_validation_fingerprint) = 64 AND environment_validation_fingerprint NOT GLOB '*[^0-9a-f]*'),
|
|
2452
|
+
CHECK ((execution_profile_revision_id IS NULL) = (execution_profile_fingerprint IS NULL)),
|
|
2453
|
+
CHECK ((execution_profile_fingerprint IS NULL) = (credential_requirements_fingerprint IS NULL)),
|
|
2454
|
+
CHECK (execution_profile_fingerprint IS NULL OR (length(execution_profile_fingerprint) = 64 AND execution_profile_fingerprint NOT GLOB '*[^0-9a-f]*')),
|
|
2455
|
+
CHECK (credential_requirements_fingerprint IS NULL OR (length(credential_requirements_fingerprint) = 64 AND credential_requirements_fingerprint NOT GLOB '*[^0-9a-f]*')),
|
|
2172
2456
|
CHECK ((template_identity IS NULL) <> (template_digest IS NULL)),
|
|
2173
2457
|
CHECK (template_identity IS NULL OR length(CAST(template_identity AS BLOB)) BETWEEN 1 AND 500),
|
|
2174
2458
|
CHECK (template_digest IS NULL OR length(CAST(template_digest AS BLOB)) BETWEEN 1 AND 500),
|
|
@@ -2214,6 +2498,7 @@ db.exec(`
|
|
|
2214
2498
|
relationship TEXT NOT NULL,
|
|
2215
2499
|
environment_revision INTEGER NOT NULL,
|
|
2216
2500
|
environment_validation_fingerprint TEXT NOT NULL,
|
|
2501
|
+
execution_profile_fingerprint TEXT,
|
|
2217
2502
|
authority_json TEXT,
|
|
2218
2503
|
placement_json TEXT,
|
|
2219
2504
|
bound_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
@@ -2224,6 +2509,7 @@ db.exec(`
|
|
|
2224
2509
|
CHECK (relationship IN ('validation', 'execution')),
|
|
2225
2510
|
CHECK (environment_revision >= 1),
|
|
2226
2511
|
CHECK (length(environment_validation_fingerprint) = 64 AND environment_validation_fingerprint NOT GLOB '*[^0-9a-f]*'),
|
|
2512
|
+
CHECK (execution_profile_fingerprint IS NULL OR (length(execution_profile_fingerprint) = 64 AND execution_profile_fingerprint NOT GLOB '*[^0-9a-f]*')),
|
|
2227
2513
|
CHECK (relationship <> 'execution' OR length(CAST(authority_json AS BLOB)) BETWEEN 2 AND 16384),
|
|
2228
2514
|
CHECK (placement_json IS NULL OR (relationship = 'execution' AND length(CAST(placement_json AS BLOB)) BETWEEN 2 AND 16384))
|
|
2229
2515
|
);
|
|
@@ -2298,8 +2584,146 @@ db.exec(`
|
|
|
2298
2584
|
SELECT RAISE(ABORT, 'Execution environment run binding identity is immutable');
|
|
2299
2585
|
END;
|
|
2300
2586
|
`);
|
|
2587
|
+
ensureColumn('execution_environments', 'execution_profile_revision_id', 'TEXT');
|
|
2588
|
+
ensureColumn('execution_environments', 'execution_profile_fingerprint', 'TEXT');
|
|
2589
|
+
ensureColumn('execution_environments', 'credential_requirements_fingerprint', 'TEXT');
|
|
2590
|
+
ensureColumn('execution_environments', 'retirement_requested_at', 'DATETIME');
|
|
2591
|
+
ensureColumn('execution_environment_run_bindings', 'execution_profile_fingerprint', 'TEXT');
|
|
2301
2592
|
ensureColumn('execution_environment_run_bindings', 'authority_json', 'TEXT');
|
|
2302
2593
|
ensureColumn('execution_environment_run_bindings', 'placement_json', 'TEXT');
|
|
2594
|
+
db.exec(`
|
|
2595
|
+
CREATE TABLE IF NOT EXISTS execution_run_authorities (
|
|
2596
|
+
execution_run_id TEXT NOT NULL,
|
|
2597
|
+
project_id TEXT NOT NULL,
|
|
2598
|
+
execution_profile_revision_id TEXT NOT NULL,
|
|
2599
|
+
execution_profile_fingerprint TEXT NOT NULL,
|
|
2600
|
+
authority_json TEXT NOT NULL,
|
|
2601
|
+
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
2602
|
+
PRIMARY KEY (execution_run_id),
|
|
2603
|
+
FOREIGN KEY (execution_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE CASCADE,
|
|
2604
|
+
FOREIGN KEY (project_id, execution_profile_revision_id)
|
|
2605
|
+
REFERENCES execution_profile_revisions(project_id, id) ON DELETE RESTRICT,
|
|
2606
|
+
CHECK (length(execution_profile_fingerprint) = 64 AND execution_profile_fingerprint NOT GLOB '*[^0-9a-f]*'),
|
|
2607
|
+
CHECK (length(CAST(authority_json AS BLOB)) BETWEEN 2 AND 16384)
|
|
2608
|
+
);
|
|
2609
|
+
|
|
2610
|
+
CREATE TRIGGER IF NOT EXISTS preserve_execution_run_authority
|
|
2611
|
+
BEFORE UPDATE ON execution_run_authorities
|
|
2612
|
+
BEGIN
|
|
2613
|
+
SELECT RAISE(ABORT, 'Execution run authority is immutable');
|
|
2614
|
+
END;
|
|
2615
|
+
|
|
2616
|
+
`);
|
|
2617
|
+
db.exec(`
|
|
2618
|
+
CREATE TABLE IF NOT EXISTS build_setup_evidence (
|
|
2619
|
+
id TEXT PRIMARY KEY,
|
|
2620
|
+
project_id TEXT NOT NULL,
|
|
2621
|
+
execution_run_id TEXT NOT NULL,
|
|
2622
|
+
target_kind TEXT NOT NULL,
|
|
2623
|
+
target_key TEXT NOT NULL,
|
|
2624
|
+
target_workspace_path TEXT NOT NULL,
|
|
2625
|
+
workspace_evidence_state TEXT NOT NULL,
|
|
2626
|
+
workspace_evidence_fingerprint TEXT,
|
|
2627
|
+
setup_configuration_fingerprint TEXT NOT NULL,
|
|
2628
|
+
execution_profile_fingerprint TEXT NOT NULL,
|
|
2629
|
+
provider TEXT NOT NULL,
|
|
2630
|
+
environment_revision INTEGER,
|
|
2631
|
+
command_count INTEGER NOT NULL,
|
|
2632
|
+
outcome TEXT NOT NULL,
|
|
2633
|
+
reused_from_evidence_id TEXT,
|
|
2634
|
+
started_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
2635
|
+
completed_at DATETIME,
|
|
2636
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
|
2637
|
+
FOREIGN KEY (execution_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE CASCADE,
|
|
2638
|
+
FOREIGN KEY (reused_from_evidence_id) REFERENCES build_setup_evidence(id) ON DELETE CASCADE,
|
|
2639
|
+
CHECK (length(id) BETWEEN 1 AND 128),
|
|
2640
|
+
CHECK (length(target_kind) BETWEEN 1 AND 100),
|
|
2641
|
+
CHECK (length(CAST(target_key AS BLOB)) BETWEEN 1 AND 1000),
|
|
2642
|
+
CHECK (length(CAST(target_workspace_path AS BLOB)) BETWEEN 1 AND 4096),
|
|
2643
|
+
CHECK (workspace_evidence_state IN ('available', 'unavailable')),
|
|
2644
|
+
CHECK ((workspace_evidence_state = 'available') = (workspace_evidence_fingerprint IS NOT NULL)),
|
|
2645
|
+
CHECK (workspace_evidence_fingerprint IS NULL OR (length(workspace_evidence_fingerprint) = 64 AND workspace_evidence_fingerprint NOT GLOB '*[^0-9a-f]*')),
|
|
2646
|
+
CHECK (length(setup_configuration_fingerprint) = 64 AND setup_configuration_fingerprint NOT GLOB '*[^0-9a-f]*'),
|
|
2647
|
+
CHECK (length(execution_profile_fingerprint) = 64 AND execution_profile_fingerprint NOT GLOB '*[^0-9a-f]*'),
|
|
2648
|
+
CHECK (provider IN ('host', 'docker_sandbox')),
|
|
2649
|
+
CHECK ((provider = 'host') = (environment_revision IS NULL)),
|
|
2650
|
+
CHECK (environment_revision IS NULL OR environment_revision >= 1),
|
|
2651
|
+
CHECK (command_count >= 0),
|
|
2652
|
+
CHECK (outcome IN ('running', 'completed', 'noop', 'reused', 'failed')),
|
|
2653
|
+
CHECK ((outcome = 'reused') = (reused_from_evidence_id IS NOT NULL)),
|
|
2654
|
+
CHECK ((outcome = 'running') = (completed_at IS NULL))
|
|
2655
|
+
);
|
|
2656
|
+
|
|
2657
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_build_setup_evidence_active_target
|
|
2658
|
+
ON build_setup_evidence(project_id, target_key)
|
|
2659
|
+
WHERE outcome = 'running';
|
|
2660
|
+
|
|
2661
|
+
CREATE INDEX IF NOT EXISTS idx_build_setup_evidence_reuse
|
|
2662
|
+
ON build_setup_evidence(
|
|
2663
|
+
project_id, target_key, workspace_evidence_fingerprint,
|
|
2664
|
+
setup_configuration_fingerprint, execution_profile_fingerprint,
|
|
2665
|
+
provider, environment_revision, completed_at DESC
|
|
2666
|
+
)
|
|
2667
|
+
WHERE outcome IN ('completed', 'noop', 'reused');
|
|
2668
|
+
|
|
2669
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_build_setup_evidence_execution_run
|
|
2670
|
+
ON build_setup_evidence(execution_run_id);
|
|
2671
|
+
|
|
2672
|
+
CREATE TRIGGER IF NOT EXISTS preserve_build_setup_evidence_identity
|
|
2673
|
+
BEFORE UPDATE OF id, project_id, execution_run_id, target_kind, target_key,
|
|
2674
|
+
target_workspace_path, workspace_evidence_state, workspace_evidence_fingerprint,
|
|
2675
|
+
setup_configuration_fingerprint, execution_profile_fingerprint, provider,
|
|
2676
|
+
environment_revision, command_count, reused_from_evidence_id, started_at
|
|
2677
|
+
ON build_setup_evidence
|
|
2678
|
+
BEGIN
|
|
2679
|
+
SELECT RAISE(ABORT, 'Build setup evidence identity is immutable');
|
|
2680
|
+
END;
|
|
2681
|
+
`);
|
|
2682
|
+
db.exec('DROP TRIGGER IF EXISTS preserve_execution_environment_identity');
|
|
2683
|
+
db.exec('DROP TRIGGER IF EXISTS validate_execution_environment_binding_identity');
|
|
2684
|
+
db.exec('DROP TRIGGER IF EXISTS preserve_execution_environment_binding_identity');
|
|
2685
|
+
db.exec(`
|
|
2686
|
+
CREATE TRIGGER preserve_execution_environment_identity
|
|
2687
|
+
BEFORE UPDATE OF id, project_id, provider_kind, provider_version, target_kind, target_key,
|
|
2688
|
+
target_workspace_path, environment_revision, workspace_mode,
|
|
2689
|
+
environment_validation_fingerprint, execution_profile_revision_id, execution_profile_fingerprint,
|
|
2690
|
+
credential_requirements_fingerprint, template_identity, template_digest,
|
|
2691
|
+
agent_identity, compatible_agents_json, created_at ON execution_environments
|
|
2692
|
+
WHEN NEW.id <> OLD.id OR NEW.project_id <> OLD.project_id OR NEW.provider_kind <> OLD.provider_kind
|
|
2693
|
+
OR NEW.provider_version <> OLD.provider_version OR NEW.target_kind <> OLD.target_kind
|
|
2694
|
+
OR NEW.target_key <> OLD.target_key OR NEW.target_workspace_path <> OLD.target_workspace_path
|
|
2695
|
+
OR NEW.environment_revision <> OLD.environment_revision OR NEW.workspace_mode <> OLD.workspace_mode
|
|
2696
|
+
OR NEW.environment_validation_fingerprint <> OLD.environment_validation_fingerprint
|
|
2697
|
+
OR NEW.execution_profile_revision_id IS NOT OLD.execution_profile_revision_id
|
|
2698
|
+
OR NEW.execution_profile_fingerprint IS NOT OLD.execution_profile_fingerprint
|
|
2699
|
+
OR NEW.credential_requirements_fingerprint IS NOT OLD.credential_requirements_fingerprint
|
|
2700
|
+
OR NEW.template_identity IS NOT OLD.template_identity OR NEW.template_digest IS NOT OLD.template_digest
|
|
2701
|
+
OR NEW.agent_identity IS NOT OLD.agent_identity OR NEW.compatible_agents_json <> OLD.compatible_agents_json
|
|
2702
|
+
OR NEW.created_at <> OLD.created_at
|
|
2703
|
+
BEGIN SELECT RAISE(ABORT, 'Execution environment identity is immutable'); END;
|
|
2704
|
+
|
|
2705
|
+
CREATE TRIGGER validate_execution_environment_binding_identity
|
|
2706
|
+
BEFORE INSERT ON execution_environment_run_bindings
|
|
2707
|
+
WHEN NOT EXISTS (
|
|
2708
|
+
SELECT 1 FROM execution_environments WHERE id = NEW.environment_id AND project_id = NEW.project_id
|
|
2709
|
+
AND environment_revision = NEW.environment_revision
|
|
2710
|
+
AND environment_validation_fingerprint = NEW.environment_validation_fingerprint
|
|
2711
|
+
AND execution_profile_fingerprint IS NEW.execution_profile_fingerprint
|
|
2712
|
+
)
|
|
2713
|
+
BEGIN SELECT RAISE(ABORT, 'Execution environment binding identity does not match'); END;
|
|
2714
|
+
|
|
2715
|
+
CREATE TRIGGER preserve_execution_environment_binding_identity
|
|
2716
|
+
BEFORE UPDATE OF environment_id, execution_run_id, project_id, relationship,
|
|
2717
|
+
environment_revision, environment_validation_fingerprint, execution_profile_fingerprint, bound_at
|
|
2718
|
+
ON execution_environment_run_bindings
|
|
2719
|
+
WHEN NEW.environment_id <> OLD.environment_id OR NEW.execution_run_id <> OLD.execution_run_id
|
|
2720
|
+
OR NEW.project_id <> OLD.project_id OR NEW.relationship <> OLD.relationship
|
|
2721
|
+
OR NEW.environment_revision <> OLD.environment_revision
|
|
2722
|
+
OR NEW.environment_validation_fingerprint <> OLD.environment_validation_fingerprint
|
|
2723
|
+
OR NEW.execution_profile_fingerprint IS NOT OLD.execution_profile_fingerprint
|
|
2724
|
+
OR NEW.bound_at <> OLD.bound_at
|
|
2725
|
+
BEGIN SELECT RAISE(ABORT, 'Execution environment run binding identity is immutable'); END;
|
|
2726
|
+
`);
|
|
2303
2727
|
db.exec('DROP TRIGGER IF EXISTS validate_execution_environment_binding_authority');
|
|
2304
2728
|
db.exec(`
|
|
2305
2729
|
CREATE TRIGGER IF NOT EXISTS validate_project_build_execution_provider_insert
|
|
@@ -2344,7 +2768,8 @@ db.exec(`
|
|
|
2344
2768
|
SELECT RAISE(ABORT, 'Execution environment binding evidence is immutable');
|
|
2345
2769
|
END;
|
|
2346
2770
|
`);
|
|
2347
|
-
db.exec('
|
|
2771
|
+
db.exec('DROP INDEX IF EXISTS idx_execution_environments_reuse');
|
|
2772
|
+
db.exec('CREATE INDEX idx_execution_environments_reuse ON execution_environments(project_id, provider_kind, target_key, target_workspace_path, environment_revision, workspace_mode, environment_validation_fingerprint, execution_profile_fingerprint, credential_requirements_fingerprint, retirement_requested_at, lifecycle_state)');
|
|
2348
2773
|
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_execution_environments_external_id ON execution_environments(provider_kind, external_id) WHERE external_id IS NOT NULL');
|
|
2349
2774
|
db.exec('CREATE INDEX IF NOT EXISTS idx_execution_environments_cleanup ON execution_environments(lifecycle_state, cleanup_claim_id, updated_at, cleanup_attempts)');
|
|
2350
2775
|
db.exec('CREATE INDEX IF NOT EXISTS idx_execution_environment_events_sequence ON execution_environment_events(project_id, environment_id, sequence)');
|
|
@@ -4327,6 +4752,11 @@ db.exec('CREATE INDEX IF NOT EXISTS idx_project_links_linked_project_id ON proje
|
|
|
4327
4752
|
db.exec('CREATE INDEX IF NOT EXISTS idx_build_sequences_project_status ON build_sequences(project_id, status)');
|
|
4328
4753
|
db.exec('CREATE INDEX IF NOT EXISTS idx_build_sequences_bundle_status ON build_sequences(worktree_bundle_id, status)');
|
|
4329
4754
|
db.exec('CREATE INDEX IF NOT EXISTS idx_build_sequence_tickets_sequence_position ON build_sequence_tickets(build_sequence_id, position)');
|
|
4755
|
+
db.exec(`
|
|
4756
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_build_sequence_tickets_activation_run
|
|
4757
|
+
ON build_sequence_tickets(activation_execution_run_id)
|
|
4758
|
+
WHERE activation_execution_run_id IS NOT NULL
|
|
4759
|
+
`);
|
|
4330
4760
|
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_integration_connections_provider_project ON integration_connections(provider, project_id)');
|
|
4331
4761
|
db.exec('CREATE INDEX IF NOT EXISTS idx_tickets_external_key ON tickets(external_provider, external_key)');
|
|
4332
4762
|
db.exec('CREATE INDEX IF NOT EXISTS idx_bundle_automation_state_project_bundle ON bundle_automation_state(project_id, worktree_bundle_id)');
|