mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 18:08:20 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0001RunCoreMigration = defineLocalSqliteMigration({
|
||||
id: '0001-run-core',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3SchemaCapabilities" (
|
||||
contract_name TEXT PRIMARY KEY,
|
||||
contract_version INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_capabilities_version_check CHECK (contract_version >= 1),
|
||||
migration_id TEXT NOT NULL,
|
||||
capabilities TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_capabilities_json_check
|
||||
CHECK (json_valid(capabilities) AND json_type(capabilities) = 'object'),
|
||||
updated_at_ms INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_capabilities_updated_at_check CHECK (updated_at_ms >= 0),
|
||||
CONSTRAINT ql3_local_capabilities_migration_fk
|
||||
FOREIGN KEY (migration_id)
|
||||
REFERENCES "QingLong3SchemaMigrations" (migration_id)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "Runs" (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
task_revision TEXT NOT NULL,
|
||||
task_name TEXT,
|
||||
task_snapshot_ref TEXT,
|
||||
legacy_cron_id INTEGER,
|
||||
parent_run_id TEXT,
|
||||
retry_of_run_id TEXT,
|
||||
trigger_id TEXT,
|
||||
trigger_type TEXT NOT NULL,
|
||||
execution_origin TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_runs_execution_origin_check
|
||||
CHECK (execution_origin IN ('manual','scheduled_system','scheduled_node','once','boot','grpc','subscription','system','script','legacy_import')),
|
||||
execution_owner TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_runs_execution_owner_check
|
||||
CHECK (execution_owner IN ('legacy','runtime')),
|
||||
triggered_by TEXT,
|
||||
request_id TEXT,
|
||||
scheduled_for_ms INTEGER,
|
||||
status TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_runs_status_check
|
||||
CHECK (status IN ('created','queued','dispatching','running','waiting_approval','retry_wait','lost','succeeded','failed','cancelled','timed_out')),
|
||||
version INTEGER NOT NULL DEFAULT 0
|
||||
CONSTRAINT ql3_local_runs_version_check CHECK (version >= 0),
|
||||
event_sequence INTEGER NOT NULL DEFAULT 0
|
||||
CONSTRAINT ql3_local_runs_event_sequence_check CHECK (event_sequence >= 0),
|
||||
priority INTEGER NOT NULL DEFAULT 0,
|
||||
idempotency_key TEXT,
|
||||
input_ref TEXT,
|
||||
output_ref TEXT,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
queued_at_ms INTEGER,
|
||||
started_at_ms INTEGER,
|
||||
finished_at_ms INTEGER,
|
||||
cancel_requested_at_ms INTEGER,
|
||||
cancel_reason TEXT
|
||||
CONSTRAINT ql3_local_runs_cancel_reason_check
|
||||
CHECK (cancel_reason IS NULL OR cancel_reason IN ('user','policy','shutdown','reconcile','timeout')),
|
||||
error_code TEXT,
|
||||
error_summary TEXT,
|
||||
CONSTRAINT ql3_local_runs_time_check CHECK (
|
||||
created_at_ms >= 0 AND
|
||||
(scheduled_for_ms IS NULL OR scheduled_for_ms >= 0) AND
|
||||
(queued_at_ms IS NULL OR queued_at_ms >= 0) AND
|
||||
(started_at_ms IS NULL OR started_at_ms >= 0) AND
|
||||
(finished_at_ms IS NULL OR finished_at_ms >= 0) AND
|
||||
(cancel_requested_at_ms IS NULL OR cancel_requested_at_ms >= 0)
|
||||
),
|
||||
CONSTRAINT ql3_local_runs_parent_fk FOREIGN KEY (parent_run_id) REFERENCES "Runs" (id),
|
||||
CONSTRAINT ql3_local_runs_retry_fk FOREIGN KEY (retry_of_run_id) REFERENCES "Runs" (id)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_local_runs_project_idempotency_uidx ON "Runs" (project_id, idempotency_key) WHERE idempotency_key IS NOT NULL`,
|
||||
`CREATE INDEX ql3_local_runs_project_created_idx ON "Runs" (project_id, created_at_ms, id)`,
|
||||
`CREATE INDEX ql3_local_runs_task_created_idx ON "Runs" (task_id, created_at_ms, id)`,
|
||||
`CREATE INDEX ql3_local_runs_cancel_requested_idx ON "Runs" (status, cancel_requested_at_ms, id)`,
|
||||
`CREATE INDEX ql3_local_runs_lost_retry_idx ON "Runs" (execution_owner, status, id)`,
|
||||
`
|
||||
CREATE TABLE "RunAttempts" (
|
||||
id TEXT PRIMARY KEY,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT,
|
||||
attempt INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_attempts_attempt_check CHECK (attempt >= 1),
|
||||
status TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_attempts_status_check
|
||||
CHECK (status IN ('claimed','starting','running','succeeded','failed','cancelled','timed_out','lost')),
|
||||
executor_type TEXT NOT NULL,
|
||||
worker_id TEXT,
|
||||
worker_session_id TEXT,
|
||||
worker_generation INTEGER,
|
||||
executor_handle TEXT,
|
||||
pid INTEGER,
|
||||
log_artifact_id TEXT,
|
||||
lease_token TEXT,
|
||||
lease_token_digest TEXT,
|
||||
lease_generation INTEGER,
|
||||
lease_version INTEGER,
|
||||
lease_expires_at_ms INTEGER,
|
||||
offer_id TEXT,
|
||||
deadline_at_ms INTEGER,
|
||||
callback_token_hash TEXT,
|
||||
callback_sequence INTEGER NOT NULL DEFAULT 0
|
||||
CONSTRAINT ql3_local_attempts_callback_sequence_check CHECK (callback_sequence >= 0),
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
started_at_ms INTEGER,
|
||||
finished_at_ms INTEGER,
|
||||
exit_code INTEGER,
|
||||
error_code TEXT,
|
||||
error_summary TEXT,
|
||||
CONSTRAINT ql3_local_attempts_time_check CHECK (
|
||||
created_at_ms >= 0 AND
|
||||
(started_at_ms IS NULL OR started_at_ms >= 0) AND
|
||||
(finished_at_ms IS NULL OR finished_at_ms >= 0) AND
|
||||
(lease_expires_at_ms IS NULL OR lease_expires_at_ms >= 0) AND
|
||||
(deadline_at_ms IS NULL OR deadline_at_ms >= 0)
|
||||
),
|
||||
CONSTRAINT ql3_local_attempts_run_fk FOREIGN KEY (run_id) REFERENCES "Runs" (id) ON DELETE CASCADE
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_local_attempts_run_attempt_uidx ON "RunAttempts" (run_id, attempt)`,
|
||||
`CREATE INDEX ql3_local_attempts_run_status_idx ON "RunAttempts" (run_id, status, id)`,
|
||||
`CREATE INDEX ql3_local_attempts_lease_idx ON "RunAttempts" (lease_expires_at_ms, id)`,
|
||||
`CREATE INDEX ql3_local_attempts_deadline_idx ON "RunAttempts" (status, deadline_at_ms, id)`,
|
||||
`
|
||||
CREATE TABLE "RunEvents" (
|
||||
id TEXT PRIMARY KEY,
|
||||
run_id TEXT NOT NULL,
|
||||
sequence INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_events_sequence_check CHECK (sequence >= 1),
|
||||
type TEXT NOT NULL,
|
||||
dedupe_key TEXT,
|
||||
actor_type TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_events_actor_type_check
|
||||
CHECK (actor_type IN ('user','api_app','trigger','agent','mcp_client','worker','executor','system','legacy_shell','scheduler','reconciler','compatibility')),
|
||||
actor_id TEXT,
|
||||
attempt_id TEXT,
|
||||
step_run_id TEXT,
|
||||
payload TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_events_payload_check
|
||||
CHECK (json_valid(payload) AND json_type(payload) = 'object'),
|
||||
created_at_ms INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_events_created_at_check CHECK (created_at_ms >= 0),
|
||||
CONSTRAINT ql3_local_events_run_fk FOREIGN KEY (run_id) REFERENCES "Runs" (id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_local_events_attempt_fk FOREIGN KEY (attempt_id) REFERENCES "RunAttempts" (id) ON DELETE SET NULL
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_local_events_run_sequence_uidx ON "RunEvents" (run_id, sequence)`,
|
||||
`CREATE UNIQUE INDEX ql3_local_events_run_dedupe_uidx ON "RunEvents" (run_id, dedupe_key) WHERE dedupe_key IS NOT NULL`,
|
||||
`CREATE INDEX ql3_local_events_run_created_idx ON "RunEvents" (run_id, created_at_ms, id)`,
|
||||
`
|
||||
CREATE TABLE "RunRetryPolicies" (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
max_attempts INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_retry_max_attempts_check CHECK (max_attempts BETWEEN 1 AND 16),
|
||||
retry_on_lost INTEGER NOT NULL
|
||||
CONSTRAINT ql3_local_retry_on_lost_check CHECK (retry_on_lost IN (0, 1)),
|
||||
safety TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_retry_safety_check CHECK (safety IN ('unknown','idempotent','deduplicated')),
|
||||
backoff_base_ms INTEGER NOT NULL,
|
||||
backoff_max_ms INTEGER NOT NULL,
|
||||
next_attempt_at_ms INTEGER,
|
||||
version INTEGER NOT NULL DEFAULT 0
|
||||
CONSTRAINT ql3_local_retry_version_check CHECK (version >= 0),
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_local_retry_backoff_check CHECK (
|
||||
backoff_base_ms BETWEEN 0 AND 86400000 AND
|
||||
backoff_max_ms BETWEEN backoff_base_ms AND 86400000
|
||||
),
|
||||
CONSTRAINT ql3_local_retry_time_check CHECK (
|
||||
created_at_ms >= 0 AND updated_at_ms >= created_at_ms AND
|
||||
(next_attempt_at_ms IS NULL OR next_attempt_at_ms >= 0)
|
||||
),
|
||||
CONSTRAINT ql3_local_retry_run_fk FOREIGN KEY (run_id) REFERENCES "Runs" (id) ON DELETE CASCADE
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_local_retry_due_idx ON "RunRetryPolicies" (next_attempt_at_ms, run_id) WHERE next_attempt_at_ms IS NOT NULL`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0002CapabilityMigration = defineLocalSqliteMigration({
|
||||
id: '0002-capability',
|
||||
statements: [
|
||||
`
|
||||
INSERT INTO "QingLong3SchemaCapabilities" (
|
||||
contract_name, contract_version, migration_id, capabilities, updated_at_ms
|
||||
) VALUES (
|
||||
'local-control-core', 1, '0001-run-core', '{"run_core":1,"run_retry_policy":1}',
|
||||
CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0003CompletionReceiptJournalMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0003-completion-receipt-journal',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "LocalCompletionReceiptJournal" (
|
||||
attempt_id TEXT PRIMARY KEY,
|
||||
run_id TEXT NOT NULL,
|
||||
state TEXT NOT NULL
|
||||
CONSTRAINT ql3_local_receipt_journal_state_check
|
||||
CHECK (state IN ('pending','quarantined')),
|
||||
quarantine_ref TEXT,
|
||||
purge_after_ms INTEGER,
|
||||
registered_at_ms INTEGER NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_local_receipt_journal_time_check CHECK (
|
||||
registered_at_ms >= 0 AND updated_at_ms >= registered_at_ms AND
|
||||
(purge_after_ms IS NULL OR purge_after_ms >= updated_at_ms)
|
||||
),
|
||||
CONSTRAINT ql3_local_receipt_journal_shape_check CHECK (
|
||||
(state = 'pending' AND quarantine_ref IS NULL AND purge_after_ms IS NULL) OR
|
||||
(state = 'quarantined' AND quarantine_ref IS NOT NULL AND purge_after_ms IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT ql3_local_receipt_journal_attempt_fk
|
||||
FOREIGN KEY (attempt_id) REFERENCES "RunAttempts" (id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_local_receipt_journal_run_fk
|
||||
FOREIGN KEY (run_id) REFERENCES "Runs" (id) ON DELETE CASCADE
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_local_receipt_journal_scan_idx ON "LocalCompletionReceiptJournal" (state, updated_at_ms, attempt_id)`,
|
||||
`CREATE INDEX ql3_local_receipt_journal_purge_idx ON "LocalCompletionReceiptJournal" (purge_after_ms, attempt_id) WHERE state = 'quarantined'`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0004CapabilityV2Migration = defineLocalSqliteMigration({
|
||||
id: '0004-capability-v2',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 2,
|
||||
migration_id = '0003-completion-receipt-journal',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 1
|
||||
AND migration_id = '0001-run-core'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0005LocalDispatchPlanMigration = defineLocalSqliteMigration({
|
||||
id: '0005-local-dispatch-plan',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalExecutionContextRecipes" (
|
||||
"context_ref" TEXT PRIMARY KEY NOT NULL,
|
||||
"environment_json" TEXT NOT NULL,
|
||||
"content_digest" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_local_context_ref_check CHECK (
|
||||
length("context_ref") = 80
|
||||
AND "context_ref" GLOB 'localctx:sha256:[0-9a-f]*'
|
||||
AND length(replace("context_ref", 'localctx:sha256:', '')) = 64
|
||||
),
|
||||
CONSTRAINT ql3_local_context_environment_check CHECK (
|
||||
json_valid("environment_json")
|
||||
AND json_type("environment_json") = 'array'
|
||||
AND length("environment_json") <= 262144
|
||||
),
|
||||
CONSTRAINT ql3_local_context_digest_check CHECK (
|
||||
length("content_digest") = 64
|
||||
AND "content_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND "context_ref" = 'localctx:sha256:' || "content_digest"
|
||||
),
|
||||
CONSTRAINT ql3_local_context_created_check CHECK ("created_at_ms" >= 0)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalTaskExecutionRevisions" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"task_id" TEXT NOT NULL,
|
||||
"task_revision" TEXT NOT NULL,
|
||||
"executor_type" TEXT NOT NULL,
|
||||
"command_json" TEXT NOT NULL,
|
||||
"working_directory" TEXT,
|
||||
"timeout_ms" INTEGER,
|
||||
"context_ref" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "task_id", "task_revision"),
|
||||
CONSTRAINT ql3_local_revision_executor_check CHECK (
|
||||
"executor_type" = 'local_process'
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_command_check CHECK (
|
||||
json_valid("command_json")
|
||||
AND json_type("command_json") = 'object'
|
||||
AND length("command_json") BETWEEN 1 AND 131072
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_working_directory_check CHECK (
|
||||
"working_directory" IS NULL
|
||||
OR (length("working_directory") BETWEEN 1 AND 4096
|
||||
AND substr("working_directory", 1, 1) = '/')
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_timeout_check CHECK (
|
||||
"timeout_ms" IS NULL OR "timeout_ms" BETWEEN 1 AND 31536000000
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_created_check CHECK ("created_at_ms" >= 0),
|
||||
FOREIGN KEY ("context_ref")
|
||||
REFERENCES "QingLong3LocalExecutionContextRecipes" ("context_ref")
|
||||
ON DELETE RESTRICT
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_runs_dispatch_idx"
|
||||
ON "Runs" (
|
||||
"execution_owner", "status", "priority" DESC,
|
||||
"queued_at_ms", "id"
|
||||
)
|
||||
WHERE "execution_owner" = 'runtime'
|
||||
AND "status" = 'queued'
|
||||
AND "cancel_requested_at_ms" IS NULL
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0006CapabilityV3Migration = defineLocalSqliteMigration({
|
||||
id: '0006-capability-v3',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 3,
|
||||
migration_id = '0005-local-dispatch-plan',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 2
|
||||
AND migration_id = '0003-completion-receipt-journal'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0007LocalSecretEnvelopesMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0007-local-secret-envelopes',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalSecretEnvelopes" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"secret_name" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"mutation_id" TEXT NOT NULL,
|
||||
"key_id" TEXT NOT NULL,
|
||||
"algorithm" TEXT NOT NULL,
|
||||
"nonce" BLOB NOT NULL,
|
||||
"ciphertext" BLOB NOT NULL,
|
||||
"auth_tag" BLOB NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "secret_name", "version"),
|
||||
CONSTRAINT ql3_local_secret_project_check CHECK (
|
||||
length("project_id") BETWEEN 1 AND 128
|
||||
AND "project_id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_name_check CHECK (
|
||||
length("secret_name") BETWEEN 1 AND 128
|
||||
AND "secret_name" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_mutation_check CHECK (
|
||||
length("mutation_id") BETWEEN 1 AND 64
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_key_check CHECK (
|
||||
length("key_id") BETWEEN 1 AND 128
|
||||
AND "key_id" NOT GLOB '*[^A-Za-z0-9._-]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_algorithm_check CHECK (
|
||||
"algorithm" = 'aes-256-gcm'
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_crypto_shape_check CHECK (
|
||||
length("nonce") = 12
|
||||
AND length("ciphertext") <= 16384
|
||||
AND length("auth_tag") = 16
|
||||
),
|
||||
CONSTRAINT ql3_local_secret_created_check CHECK ("created_at_ms" >= 0)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_secret_mutation_uidx"
|
||||
ON "QingLong3LocalSecretEnvelopes" (
|
||||
"project_id", "secret_name", "mutation_id"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_secret_current_idx"
|
||||
ON "QingLong3LocalSecretEnvelopes" (
|
||||
"project_id", "secret_name", "version" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_secret_key_usage_idx"
|
||||
ON "QingLong3LocalSecretEnvelopes" (
|
||||
"key_id", "project_id", "secret_name", "version"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0008CapabilityV4Migration = defineLocalSqliteMigration({
|
||||
id: '0008-capability-v4',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 4,
|
||||
migration_id = '0007-local-secret-envelopes',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 3
|
||||
AND migration_id = '0005-local-dispatch-plan'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,166 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0009LocalProjectPolicyAuditMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0009-local-project-policy-audit',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3Projects" (
|
||||
"id" TEXT PRIMARY KEY NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
"updated_at_ms" INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_local_projects_id_check CHECK (
|
||||
length("id") BETWEEN 1 AND 128
|
||||
AND "id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
),
|
||||
CONSTRAINT ql3_local_projects_name_check CHECK (
|
||||
length("name") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_local_projects_slug_check CHECK (
|
||||
length("slug") BETWEEN 1 AND 128
|
||||
AND "slug" = lower("slug")
|
||||
AND "slug" NOT GLOB '*[^a-z0-9-]*'
|
||||
AND substr("slug", 1, 1) NOT GLOB '[^a-z0-9]'
|
||||
AND substr("slug", -1, 1) NOT GLOB '[^a-z0-9]'
|
||||
),
|
||||
CONSTRAINT ql3_local_projects_status_check CHECK (
|
||||
"status" IN ('active', 'archived')
|
||||
),
|
||||
CONSTRAINT ql3_local_projects_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_projects_time_check CHECK (
|
||||
"created_at_ms" >= 0 AND "updated_at_ms" >= "created_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_projects_slug_uidx"
|
||||
ON "QingLong3Projects" ("slug")
|
||||
`,
|
||||
`
|
||||
INSERT INTO "QingLong3Projects" (
|
||||
"id", "name", "slug", "status", "version", "created_at_ms", "updated_at_ms"
|
||||
) VALUES ('default', 'Default', 'default', 'active', 1, 0, 0)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ProjectRoleBindings" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"role" TEXT,
|
||||
"mutation_id" TEXT NOT NULL,
|
||||
"changed_by_type" TEXT NOT NULL,
|
||||
"changed_by_id" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "subject_type", "subject_id", "version"),
|
||||
FOREIGN KEY ("project_id") REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_bindings_subject_type_check CHECK (
|
||||
"subject_type" IN ('user','api_app','mcp_client','agent','system','worker')
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_subject_id_check CHECK (
|
||||
length("subject_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_state_role_check CHECK (
|
||||
("state" = 'active' AND "role" IN ('owner','admin','operator','viewer'))
|
||||
OR ("state" = 'revoked' AND "role" IS NULL)
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_mutation_check CHECK (
|
||||
length("mutation_id") BETWEEN 1 AND 64
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_changed_by_type_check CHECK (
|
||||
"changed_by_type" IN ('user','api_app','mcp_client','agent','system','worker')
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_changed_by_id_check CHECK (
|
||||
length("changed_by_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_local_bindings_created_check CHECK ("created_at_ms" >= 0)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_bindings_mutation_uidx"
|
||||
ON "QingLong3ProjectRoleBindings" (
|
||||
"project_id", "subject_type", "subject_id", "mutation_id"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_bindings_current_idx"
|
||||
ON "QingLong3ProjectRoleBindings" (
|
||||
"project_id", "subject_type", "subject_id", "version" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_bindings_project_idx"
|
||||
ON "QingLong3ProjectRoleBindings" ("project_id", "version" DESC)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3SecurityAuditEvents" (
|
||||
"event_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"request_id" TEXT NOT NULL,
|
||||
"operation_id" TEXT NOT NULL,
|
||||
"project_id" TEXT,
|
||||
"subject_type" TEXT,
|
||||
"subject_id" TEXT,
|
||||
"authentication_id" TEXT,
|
||||
"outcome" TEXT NOT NULL,
|
||||
"reasons_json" TEXT NOT NULL,
|
||||
"fence_project_version" INTEGER,
|
||||
"fence_binding_version" INTEGER,
|
||||
"occurred_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("project_id") REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_audit_event_check CHECK (length("event_id") = 36),
|
||||
CONSTRAINT ql3_local_audit_request_check CHECK (length("request_id") BETWEEN 1 AND 128),
|
||||
CONSTRAINT ql3_local_audit_operation_check CHECK (length("operation_id") BETWEEN 1 AND 128),
|
||||
CONSTRAINT ql3_local_audit_subject_check CHECK (
|
||||
("subject_type" IS NULL AND "subject_id" IS NULL AND "authentication_id" IS NULL)
|
||||
OR (
|
||||
"subject_type" IN ('user','api_app','mcp_client','agent','system','worker')
|
||||
AND length("subject_id") BETWEEN 1 AND 255
|
||||
AND length("authentication_id") BETWEEN 1 AND 128
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_local_audit_outcome_check CHECK (
|
||||
"outcome" IN (
|
||||
'authentication_rejected','authentication_unavailable',
|
||||
'authorization_unavailable','denied','approval_required','allowed'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_local_audit_reasons_check CHECK (
|
||||
json_valid("reasons_json")
|
||||
AND json_type("reasons_json") = 'array'
|
||||
AND json_array_length("reasons_json") BETWEEN 1 AND 8
|
||||
AND length("reasons_json") <= 2048
|
||||
),
|
||||
CONSTRAINT ql3_local_audit_fence_check CHECK (
|
||||
("fence_project_version" IS NULL AND "fence_binding_version" IS NULL)
|
||||
OR (
|
||||
"fence_project_version" BETWEEN 1 AND 2147483647
|
||||
AND ("fence_binding_version" IS NULL OR "fence_binding_version" BETWEEN 1 AND 2147483647)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_local_audit_time_check CHECK ("occurred_at_ms" >= 0)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_audit_project_time_idx"
|
||||
ON "QingLong3SecurityAuditEvents" (
|
||||
"project_id", "occurred_at_ms" DESC, "event_id" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_audit_subject_time_idx"
|
||||
ON "QingLong3SecurityAuditEvents" (
|
||||
"subject_type", "subject_id", "occurred_at_ms" DESC, "event_id" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0010CapabilityV5Migration = defineLocalSqliteMigration({
|
||||
id: '0010-capability-v5',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 5,
|
||||
migration_id = '0009-local-project-policy-audit',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 4
|
||||
AND migration_id = '0007-local-secret-envelopes'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0011LocalIdentityCredentialMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0011-local-identity-credential',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3IdentitySubjects" (
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
"updated_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("subject_type", "subject_id"),
|
||||
CONSTRAINT ql3_local_identity_type_check CHECK (
|
||||
"subject_type" IN ('user','api_app','mcp_client','agent','system','worker')
|
||||
),
|
||||
CONSTRAINT ql3_local_identity_id_check CHECK (
|
||||
length("subject_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_local_identity_status_check CHECK (
|
||||
"status" IN ('active','disabled')
|
||||
),
|
||||
CONSTRAINT ql3_local_identity_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_identity_time_check CHECK (
|
||||
"created_at_ms" >= 0 AND "updated_at_ms" >= "created_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_identity_status_idx"
|
||||
ON "QingLong3IdentitySubjects" (
|
||||
"status", "subject_type", "subject_id"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ApiCredentials" (
|
||||
"credential_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"secret_digest" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
"not_before_at_ms" INTEGER NOT NULL,
|
||||
"expires_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("credential_id", "version"),
|
||||
FOREIGN KEY ("subject_type", "subject_id")
|
||||
REFERENCES "QingLong3IdentitySubjects" ("subject_type", "subject_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_credentials_id_check CHECK (
|
||||
length("credential_id") BETWEEN 1 AND 64
|
||||
AND "credential_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_credentials_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_credentials_state_check CHECK (
|
||||
"state" IN ('active','revoked')
|
||||
),
|
||||
CONSTRAINT ql3_local_credentials_subject_type_check CHECK (
|
||||
"subject_type" IN ('user','api_app','mcp_client','agent')
|
||||
),
|
||||
CONSTRAINT ql3_local_credentials_subject_id_check CHECK (
|
||||
length("subject_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_local_credentials_digest_check CHECK (
|
||||
length("secret_digest") = 64
|
||||
AND "secret_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_credentials_lifetime_check CHECK (
|
||||
"created_at_ms" >= 0
|
||||
AND "not_before_at_ms" >= "created_at_ms"
|
||||
AND "expires_at_ms" > "not_before_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_credentials_current_idx"
|
||||
ON "QingLong3ApiCredentials" ("credential_id", "version" DESC)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_credentials_subject_idx"
|
||||
ON "QingLong3ApiCredentials" (
|
||||
"subject_type", "subject_id", "credential_id", "version" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0012CapabilityV6Migration = defineLocalSqliteMigration({
|
||||
id: '0012-capability-v6',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 6,
|
||||
migration_id = '0011-local-identity-credential',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 5
|
||||
AND migration_id = '0009-local-project-policy-audit'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0013LocalOwnerBootstrapMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0013-local-owner-bootstrap',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalIdentityProvisionings" (
|
||||
"slot" INTEGER PRIMARY KEY NOT NULL,
|
||||
"mutation_id" TEXT NOT NULL,
|
||||
"request_id" TEXT NOT NULL,
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"credential_id" TEXT NOT NULL,
|
||||
"credential_version" INTEGER NOT NULL,
|
||||
"issuer_authentication_id" TEXT NOT NULL,
|
||||
"issuer_authenticated_at_ms" INTEGER NOT NULL,
|
||||
"issuer_expires_at_ms" INTEGER NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("subject_type", "subject_id")
|
||||
REFERENCES "QingLong3IdentitySubjects" ("subject_type", "subject_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("credential_id", "credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_provisioning_singleton_check CHECK ("slot" = 1),
|
||||
CONSTRAINT ql3_local_provisioning_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
),
|
||||
CONSTRAINT ql3_local_provisioning_request_check CHECK (
|
||||
length("request_id") BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_local_provisioning_subject_check CHECK (
|
||||
"subject_type" = 'user' AND length("subject_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_local_provisioning_credential_check CHECK (
|
||||
length("credential_id") BETWEEN 1 AND 64 AND "credential_version" = 1
|
||||
),
|
||||
CONSTRAINT ql3_local_provisioning_issuer_check CHECK (
|
||||
length("issuer_authentication_id") BETWEEN 1 AND 128
|
||||
AND "issuer_authenticated_at_ms" <= "created_at_ms"
|
||||
AND "issuer_expires_at_ms" > "created_at_ms"
|
||||
),
|
||||
CONSTRAINT ql3_local_provisioning_audit_check CHECK (
|
||||
"audit_event_id" = "mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_local_provisioning_time_check CHECK ("created_at_ms" >= 0)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_provisioning_mutation_uidx"
|
||||
ON "QingLong3LocalIdentityProvisionings" ("mutation_id")
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_provisioning_subject_uidx"
|
||||
ON "QingLong3LocalIdentityProvisionings" ("subject_type", "subject_id")
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_provisioning_credential_uidx"
|
||||
ON "QingLong3LocalIdentityProvisionings" (
|
||||
"credential_id", "credential_version"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerBootstrapChallenges" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"issue_mutation_id" TEXT NOT NULL,
|
||||
"issue_request_id" TEXT NOT NULL,
|
||||
"challenge_id" TEXT NOT NULL,
|
||||
"token_digest" TEXT NOT NULL,
|
||||
"issuer_authentication_id" TEXT NOT NULL,
|
||||
"issuer_authenticated_at_ms" INTEGER NOT NULL,
|
||||
"issuer_expires_at_ms" INTEGER NOT NULL,
|
||||
"issued_at_ms" INTEGER NOT NULL,
|
||||
"expires_at_ms" INTEGER NOT NULL,
|
||||
"issue_audit_event_id" TEXT NOT NULL,
|
||||
"consumed_at_ms" INTEGER,
|
||||
"claim_mutation_id" TEXT,
|
||||
"claim_request_id" TEXT,
|
||||
"claimed_subject_type" TEXT,
|
||||
"claimed_subject_id" TEXT,
|
||||
"credential_id" TEXT,
|
||||
"credential_version" INTEGER,
|
||||
"claim_authentication_id" TEXT,
|
||||
"claim_authenticated_at_ms" INTEGER,
|
||||
"claim_expires_at_ms" INTEGER,
|
||||
"claim_assurance" TEXT,
|
||||
"claim_audit_event_id" TEXT,
|
||||
PRIMARY KEY ("project_id", "version"),
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("issue_audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("claimed_subject_type", "claimed_subject_id")
|
||||
REFERENCES "QingLong3IdentitySubjects" ("subject_type", "subject_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("credential_id", "credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("claim_audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id") ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_owner_challenge_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_challenge_issue_identity_check CHECK (
|
||||
length("issue_mutation_id") = 36
|
||||
AND length("issue_request_id") BETWEEN 1 AND 128
|
||||
AND "issue_audit_event_id" = "issue_mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_challenge_id_check CHECK (
|
||||
length("challenge_id") = 22
|
||||
AND "challenge_id" NOT GLOB '*[^A-Za-z0-9_-]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_challenge_digest_check CHECK (
|
||||
length("token_digest") = 64
|
||||
AND "token_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_challenge_issuer_check CHECK (
|
||||
length("issuer_authentication_id") BETWEEN 1 AND 128
|
||||
AND "issuer_authenticated_at_ms" <= "issued_at_ms"
|
||||
AND "issuer_expires_at_ms" > "issued_at_ms"
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_challenge_lifetime_check CHECK (
|
||||
"issued_at_ms" >= 0
|
||||
AND "expires_at_ms" > "issued_at_ms"
|
||||
AND "expires_at_ms" - "issued_at_ms" BETWEEN 60000 AND 1800000
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_challenge_claim_shape_check CHECK (
|
||||
(
|
||||
"consumed_at_ms" IS NULL
|
||||
AND "claim_mutation_id" IS NULL
|
||||
AND "claim_request_id" IS NULL
|
||||
AND "claimed_subject_type" IS NULL
|
||||
AND "claimed_subject_id" IS NULL
|
||||
AND "credential_id" IS NULL
|
||||
AND "credential_version" IS NULL
|
||||
AND "claim_authentication_id" IS NULL
|
||||
AND "claim_authenticated_at_ms" IS NULL
|
||||
AND "claim_expires_at_ms" IS NULL
|
||||
AND "claim_assurance" IS NULL
|
||||
AND "claim_audit_event_id" IS NULL
|
||||
)
|
||||
OR (
|
||||
"consumed_at_ms" >= "issued_at_ms"
|
||||
AND "consumed_at_ms" < "expires_at_ms"
|
||||
AND length("claim_mutation_id") = 36
|
||||
AND length("claim_request_id") BETWEEN 1 AND 128
|
||||
AND "claimed_subject_type" = 'user'
|
||||
AND length("claimed_subject_id") BETWEEN 1 AND 255
|
||||
AND length("credential_id") BETWEEN 1 AND 64
|
||||
AND "credential_version" BETWEEN 1 AND 2147483647
|
||||
AND length("claim_authentication_id") BETWEEN 1 AND 128
|
||||
AND "claim_authenticated_at_ms" <= "consumed_at_ms"
|
||||
AND "claim_expires_at_ms" > "consumed_at_ms"
|
||||
AND "claim_assurance" = 'single_factor'
|
||||
AND "claim_audit_event_id" = "claim_mutation_id"
|
||||
)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_challenge_issue_mutation_uidx"
|
||||
ON "QingLong3LocalOwnerBootstrapChallenges" ("issue_mutation_id")
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_challenge_id_uidx"
|
||||
ON "QingLong3LocalOwnerBootstrapChallenges" ("challenge_id")
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_challenge_claim_mutation_uidx"
|
||||
ON "QingLong3LocalOwnerBootstrapChallenges" ("claim_mutation_id")
|
||||
WHERE "claim_mutation_id" IS NOT NULL
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_challenge_current_idx"
|
||||
ON "QingLong3LocalOwnerBootstrapChallenges" (
|
||||
"project_id", "version" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_challenge_expiry_idx"
|
||||
ON "QingLong3LocalOwnerBootstrapChallenges" (
|
||||
"project_id", "expires_at_ms", "version" DESC
|
||||
)
|
||||
WHERE "consumed_at_ms" IS NULL
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0014CapabilityV7Migration = defineLocalSqliteMigration({
|
||||
id: '0014-capability-v7',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 7,
|
||||
migration_id = '0013-local-owner-bootstrap',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 6
|
||||
AND migration_id = '0011-local-identity-credential'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0015LocalOwnerDeliveryAcknowledgementsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0015-local-owner-delivery-acknowledgements',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerDeliveryAcknowledgements" (
|
||||
"mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"kind" TEXT NOT NULL,
|
||||
"request_id" TEXT NOT NULL,
|
||||
"project_id" TEXT,
|
||||
"subject_id" TEXT,
|
||||
"credential_id" TEXT,
|
||||
"challenge_id" TEXT,
|
||||
"fact_digest" TEXT NOT NULL,
|
||||
"delivery_digest" TEXT NOT NULL,
|
||||
"ttl_ms" INTEGER NOT NULL,
|
||||
"acknowledged_at_ms" INTEGER NOT NULL,
|
||||
"provisioning_mutation_id" TEXT,
|
||||
"challenge_mutation_id" TEXT,
|
||||
FOREIGN KEY ("provisioning_mutation_id")
|
||||
REFERENCES "QingLong3LocalIdentityProvisionings" ("mutation_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("challenge_mutation_id")
|
||||
REFERENCES "QingLong3LocalOwnerBootstrapChallenges" ("issue_mutation_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_request_check CHECK (
|
||||
length("request_id") BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_digest_check CHECK (
|
||||
length("fact_digest") = 64
|
||||
AND "fact_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("delivery_digest") = 64
|
||||
AND "delivery_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_time_check CHECK (
|
||||
"ttl_ms" > 0 AND "acknowledged_at_ms" >= 0
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_shape_check CHECK (
|
||||
(
|
||||
"kind" = 'credential'
|
||||
AND "project_id" IS NULL
|
||||
AND length("subject_id") = 26
|
||||
AND "subject_id" GLOB 'usr_*'
|
||||
AND "subject_id" NOT GLOB '*[^A-Za-z0-9_-]*'
|
||||
AND length("credential_id") = 26
|
||||
AND "credential_id" GLOB 'own_*'
|
||||
AND "credential_id" NOT GLOB '*[^A-Za-z0-9_-]*'
|
||||
AND "challenge_id" IS NULL
|
||||
AND "provisioning_mutation_id" = "mutation_id"
|
||||
AND "challenge_mutation_id" IS NULL
|
||||
AND "ttl_ms" BETWEEN 600000 AND 604800000
|
||||
)
|
||||
OR (
|
||||
"kind" = 'challenge'
|
||||
AND length("project_id") BETWEEN 1 AND 128
|
||||
AND "subject_id" IS NULL
|
||||
AND "credential_id" IS NULL
|
||||
AND length("challenge_id") = 22
|
||||
AND "challenge_id" NOT GLOB '*[^A-Za-z0-9_-]*'
|
||||
AND "provisioning_mutation_id" IS NULL
|
||||
AND "challenge_mutation_id" = "mutation_id"
|
||||
AND "ttl_ms" BETWEEN 60000 AND 1800000
|
||||
)
|
||||
)
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0016CapabilityV8Migration = defineLocalSqliteMigration({
|
||||
id: '0016-capability-v8',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 8,
|
||||
migration_id = '0015-local-owner-delivery-acknowledgements',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 7
|
||||
AND migration_id = '0013-local-owner-bootstrap'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0017ApiCredentialPepperBindingsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0017-api-credential-pepper-bindings',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3ApiCredentialPepperBindings" (
|
||||
"credential_id" TEXT NOT NULL,
|
||||
"credential_version" INTEGER NOT NULL,
|
||||
"pepper_key_id" TEXT NOT NULL,
|
||||
PRIMARY KEY ("credential_id", "credential_version"),
|
||||
FOREIGN KEY ("credential_id", "credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_credential_pepper_key_id_check CHECK (
|
||||
length("pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
INSERT INTO "QingLong3ApiCredentialPepperBindings" (
|
||||
"credential_id", "credential_version", "pepper_key_id"
|
||||
)
|
||||
SELECT "credential_id", "version", 'legacy-v1'
|
||||
FROM "QingLong3ApiCredentials"
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_credential_pepper_key_idx"
|
||||
ON "QingLong3ApiCredentialPepperBindings" (
|
||||
"pepper_key_id", "credential_id", "credential_version"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0018CapabilityV9Migration = defineLocalSqliteMigration({
|
||||
id: '0018-capability-v9',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 9,
|
||||
migration_id = '0017-api-credential-pepper-bindings',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 8
|
||||
AND migration_id = '0015-local-owner-delivery-acknowledgements'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0019LocalOwnerPepperCatalogMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0019-local-owner-pepper-catalog',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerPepperKeys" (
|
||||
"pepper_key_id" TEXT PRIMARY KEY,
|
||||
"material_digest" TEXT,
|
||||
"backup_digest" TEXT,
|
||||
"state" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"register_mutation_id" TEXT,
|
||||
"activate_mutation_id" TEXT,
|
||||
"retire_mutation_id" TEXT,
|
||||
"registered_at_ms" INTEGER NOT NULL,
|
||||
"activated_at_ms" INTEGER,
|
||||
"retired_at_ms" INTEGER,
|
||||
CONSTRAINT ql3_local_owner_pepper_key_id_check CHECK (
|
||||
length("pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_digest_check CHECK (
|
||||
("material_digest" IS NULL AND "backup_digest" IS NULL)
|
||||
OR (
|
||||
length("material_digest") = 64
|
||||
AND "material_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("backup_digest") = 64
|
||||
AND "backup_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_state_check CHECK (
|
||||
"state" IN ('recovery_required', 'staged', 'active', 'retired')
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_version_check CHECK (
|
||||
"version" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_mutation_check CHECK (
|
||||
("register_mutation_id" IS NULL OR length("register_mutation_id") = 36)
|
||||
AND ("activate_mutation_id" IS NULL OR length("activate_mutation_id") = 36)
|
||||
AND ("retire_mutation_id" IS NULL OR length("retire_mutation_id") = 36)
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_time_check CHECK (
|
||||
"registered_at_ms" >= 0
|
||||
AND ("activated_at_ms" IS NULL OR "activated_at_ms" >= "registered_at_ms")
|
||||
AND ("retired_at_ms" IS NULL OR "retired_at_ms" >= "activated_at_ms")
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_shape_check CHECK (
|
||||
("state" = 'recovery_required' AND "material_digest" IS NULL
|
||||
AND "backup_digest" IS NULL AND "register_mutation_id" IS NULL
|
||||
AND "activate_mutation_id" IS NULL AND "retire_mutation_id" IS NULL
|
||||
AND "activated_at_ms" IS NULL AND "retired_at_ms" IS NULL)
|
||||
OR ("state" = 'staged' AND "material_digest" IS NOT NULL
|
||||
AND "backup_digest" IS NOT NULL AND "register_mutation_id" IS NOT NULL
|
||||
AND "activate_mutation_id" IS NULL AND "retire_mutation_id" IS NULL
|
||||
AND "activated_at_ms" IS NULL AND "retired_at_ms" IS NULL)
|
||||
OR ("state" = 'active' AND "material_digest" IS NOT NULL
|
||||
AND "backup_digest" IS NOT NULL AND "register_mutation_id" IS NOT NULL
|
||||
AND "activate_mutation_id" IS NOT NULL AND "retire_mutation_id" IS NULL
|
||||
AND "activated_at_ms" IS NOT NULL AND "retired_at_ms" IS NULL)
|
||||
OR ("state" = 'retired' AND "material_digest" IS NOT NULL
|
||||
AND "backup_digest" IS NOT NULL AND "register_mutation_id" IS NOT NULL
|
||||
AND "activate_mutation_id" IS NOT NULL AND "retire_mutation_id" IS NOT NULL
|
||||
AND "activated_at_ms" IS NOT NULL AND "retired_at_ms" IS NOT NULL)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
INSERT INTO "QingLong3LocalOwnerPepperKeys" (
|
||||
"pepper_key_id", "state", "version", "registered_at_ms"
|
||||
)
|
||||
SELECT 'legacy-v1', 'recovery_required', 1, 0
|
||||
WHERE EXISTS (SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" LIMIT 1)
|
||||
`,
|
||||
`
|
||||
ALTER TABLE "QingLong3ApiCredentialPepperBindings"
|
||||
RENAME TO "QingLong3ApiCredentialPepperBindingsBeforeCatalog"
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ApiCredentialPepperBindings" (
|
||||
"credential_id" TEXT NOT NULL,
|
||||
"credential_version" INTEGER NOT NULL,
|
||||
"pepper_key_id" TEXT NOT NULL,
|
||||
PRIMARY KEY ("credential_id", "credential_version"),
|
||||
FOREIGN KEY ("credential_id", "credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("pepper_key_id")
|
||||
REFERENCES "QingLong3LocalOwnerPepperKeys" ("pepper_key_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_credential_pepper_key_id_check CHECK (
|
||||
length("pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
INSERT INTO "QingLong3ApiCredentialPepperBindings" (
|
||||
"credential_id", "credential_version", "pepper_key_id"
|
||||
)
|
||||
SELECT "credential_id", "credential_version", "pepper_key_id"
|
||||
FROM "QingLong3ApiCredentialPepperBindingsBeforeCatalog"
|
||||
`,
|
||||
`
|
||||
DROP TABLE "QingLong3ApiCredentialPepperBindingsBeforeCatalog"
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_credential_pepper_key_idx"
|
||||
ON "QingLong3ApiCredentialPepperBindings" (
|
||||
"pepper_key_id", "credential_id", "credential_version"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_pepper_register_mutation_uidx"
|
||||
ON "QingLong3LocalOwnerPepperKeys" ("register_mutation_id")
|
||||
WHERE "register_mutation_id" IS NOT NULL
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_pepper_single_active_uidx"
|
||||
ON "QingLong3LocalOwnerPepperKeys" ("state")
|
||||
WHERE "state" = 'active'
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_pepper_state_idx"
|
||||
ON "QingLong3LocalOwnerPepperKeys" ("state", "pepper_key_id")
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerPepperActivations" (
|
||||
"generation" INTEGER PRIMARY KEY,
|
||||
"mutation_id" TEXT NOT NULL,
|
||||
"expected_generation" INTEGER NOT NULL,
|
||||
"previous_pepper_key_id" TEXT,
|
||||
"active_pepper_key_id" TEXT NOT NULL,
|
||||
"material_digest" TEXT NOT NULL,
|
||||
"backup_digest" TEXT NOT NULL,
|
||||
"activated_at_ms" INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_local_owner_pepper_activation_generation_check CHECK (
|
||||
"generation" BETWEEN 1 AND 2147483647
|
||||
AND "expected_generation" = "generation" - 1
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_activation_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_activation_key_check CHECK (
|
||||
length("active_pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "active_pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND ("previous_pepper_key_id" IS NULL OR (
|
||||
length("previous_pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "previous_pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND "previous_pepper_key_id" <> "active_pepper_key_id"
|
||||
))
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_activation_digest_check CHECK (
|
||||
length("material_digest") = 64
|
||||
AND "material_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("backup_digest") = 64
|
||||
AND "backup_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_activation_time_check CHECK (
|
||||
"activated_at_ms" >= 0
|
||||
),
|
||||
FOREIGN KEY ("previous_pepper_key_id")
|
||||
REFERENCES "QingLong3LocalOwnerPepperKeys" ("pepper_key_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("active_pepper_key_id")
|
||||
REFERENCES "QingLong3LocalOwnerPepperKeys" ("pepper_key_id")
|
||||
ON DELETE RESTRICT
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_pepper_activation_mutation_uidx"
|
||||
ON "QingLong3LocalOwnerPepperActivations" ("mutation_id")
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_pepper_activation_key_idx"
|
||||
ON "QingLong3LocalOwnerPepperActivations" (
|
||||
"active_pepper_key_id", "generation" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0020CapabilityV10Migration = defineLocalSqliteMigration({
|
||||
id: '0020-capability-v10',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 10,
|
||||
migration_id = '0019-local-owner-pepper-catalog',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 9
|
||||
AND migration_id = '0017-api-credential-pepper-bindings'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0021LocalOwnerCredentialRecoveryMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0021-local-owner-credential-recovery',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerCredentialRecoveries" (
|
||||
"issue_mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"issue_request_id" TEXT NOT NULL,
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"previous_credential_id" TEXT NOT NULL,
|
||||
"previous_credential_version" INTEGER NOT NULL,
|
||||
"replacement_credential_id" TEXT NOT NULL,
|
||||
"replacement_credential_version" INTEGER NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"issued_at_ms" INTEGER NOT NULL,
|
||||
"issue_audit_event_id" TEXT NOT NULL,
|
||||
"delivery_digest" TEXT,
|
||||
"acknowledged_at_ms" INTEGER,
|
||||
"complete_mutation_id" TEXT,
|
||||
"complete_request_id" TEXT,
|
||||
"revoked_credential_version" INTEGER,
|
||||
"completed_at_ms" INTEGER,
|
||||
"complete_audit_event_id" TEXT,
|
||||
FOREIGN KEY ("subject_type", "subject_id")
|
||||
REFERENCES "QingLong3IdentitySubjects" ("subject_type", "subject_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("previous_credential_id", "previous_credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("replacement_credential_id", "replacement_credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("previous_credential_id", "revoked_credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("issue_audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("complete_audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_owner_recovery_mutation_check CHECK (
|
||||
length("issue_mutation_id") = 36
|
||||
AND "issue_audit_event_id" = "issue_mutation_id"
|
||||
AND ("complete_mutation_id" IS NULL OR (
|
||||
length("complete_mutation_id") = 36
|
||||
AND "complete_audit_event_id" = "complete_mutation_id"
|
||||
AND "complete_mutation_id" <> "issue_mutation_id"
|
||||
))
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_recovery_request_check CHECK (
|
||||
length("issue_request_id") BETWEEN 1 AND 128
|
||||
AND ("complete_request_id" IS NULL
|
||||
OR length("complete_request_id") BETWEEN 1 AND 128)
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_recovery_identity_check CHECK (
|
||||
"subject_type" = 'user'
|
||||
AND length("subject_id") = 26
|
||||
AND "subject_id" GLOB 'usr_*'
|
||||
AND "subject_id" NOT GLOB '*[^A-Za-z0-9_-]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_recovery_credential_check CHECK (
|
||||
length("previous_credential_id") BETWEEN 1 AND 64
|
||||
AND "previous_credential_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND "previous_credential_version" BETWEEN 1 AND 2147483646
|
||||
AND length("replacement_credential_id") BETWEEN 1 AND 64
|
||||
AND "replacement_credential_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND "replacement_credential_id" <> "previous_credential_id"
|
||||
AND "replacement_credential_version" = 1
|
||||
AND ("revoked_credential_version" IS NULL
|
||||
OR "revoked_credential_version" = "previous_credential_version" + 1)
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_recovery_digest_check CHECK (
|
||||
"delivery_digest" IS NULL OR (
|
||||
length("delivery_digest") = 64
|
||||
AND "delivery_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_recovery_time_check CHECK (
|
||||
"issued_at_ms" >= 0
|
||||
AND ("acknowledged_at_ms" IS NULL
|
||||
OR "acknowledged_at_ms" >= "issued_at_ms")
|
||||
AND ("completed_at_ms" IS NULL
|
||||
OR "completed_at_ms" >= "acknowledged_at_ms")
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_recovery_shape_check CHECK (
|
||||
("state" = 'issued'
|
||||
AND "delivery_digest" IS NULL
|
||||
AND "acknowledged_at_ms" IS NULL
|
||||
AND "complete_mutation_id" IS NULL
|
||||
AND "complete_request_id" IS NULL
|
||||
AND "revoked_credential_version" IS NULL
|
||||
AND "completed_at_ms" IS NULL
|
||||
AND "complete_audit_event_id" IS NULL)
|
||||
OR ("state" = 'acknowledged'
|
||||
AND "delivery_digest" IS NOT NULL
|
||||
AND "acknowledged_at_ms" IS NOT NULL
|
||||
AND "complete_mutation_id" IS NULL
|
||||
AND "complete_request_id" IS NULL
|
||||
AND "revoked_credential_version" IS NULL
|
||||
AND "completed_at_ms" IS NULL
|
||||
AND "complete_audit_event_id" IS NULL)
|
||||
OR ("state" = 'completed'
|
||||
AND "delivery_digest" IS NOT NULL
|
||||
AND "acknowledged_at_ms" IS NOT NULL
|
||||
AND "complete_mutation_id" IS NOT NULL
|
||||
AND "complete_request_id" IS NOT NULL
|
||||
AND "revoked_credential_version" IS NOT NULL
|
||||
AND "completed_at_ms" IS NOT NULL
|
||||
AND "complete_audit_event_id" IS NOT NULL)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_recovery_open_subject_uidx"
|
||||
ON "QingLong3LocalOwnerCredentialRecoveries" ("subject_id")
|
||||
WHERE "state" <> 'completed'
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_recovery_replacement_uidx"
|
||||
ON "QingLong3LocalOwnerCredentialRecoveries" (
|
||||
"replacement_credential_id", "replacement_credential_version"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_recovery_complete_mutation_uidx"
|
||||
ON "QingLong3LocalOwnerCredentialRecoveries" ("complete_mutation_id")
|
||||
WHERE "complete_mutation_id" IS NOT NULL
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_recovery_previous_idx"
|
||||
ON "QingLong3LocalOwnerCredentialRecoveries" (
|
||||
"previous_credential_id", "previous_credential_version", "state"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0022CapabilityV11Migration = defineLocalSqliteMigration({
|
||||
id: '0022-capability-v11',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 11,
|
||||
migration_id = '0021-local-owner-credential-recovery',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 10
|
||||
AND migration_id = '0019-local-owner-pepper-catalog'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,133 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0023LocalOwnerPepperMaterialGcMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0023-local-owner-pepper-material-gc',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerPepperMaterialGc" (
|
||||
"prepare_mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"prepare_request_id" TEXT NOT NULL,
|
||||
"pepper_key_id" TEXT NOT NULL,
|
||||
"material_digest" TEXT NOT NULL,
|
||||
"backup_material_digest" TEXT NOT NULL,
|
||||
"active_pepper_key_id" TEXT NOT NULL,
|
||||
"active_generation" INTEGER NOT NULL,
|
||||
"active_material_digest" TEXT NOT NULL,
|
||||
"retention_policy_version" INTEGER NOT NULL,
|
||||
"acknowledgement_retention_ms" INTEGER NOT NULL,
|
||||
"audit_retention_ms" INTEGER NOT NULL,
|
||||
"backup_retention_ms" INTEGER NOT NULL,
|
||||
"retention_policy_digest" TEXT NOT NULL,
|
||||
"references_inspected_at_ms" INTEGER NOT NULL,
|
||||
"retention_eligible_at_ms" INTEGER NOT NULL,
|
||||
"prepared_at_ms" INTEGER NOT NULL,
|
||||
"prepare_audit_event_id" TEXT NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"complete_mutation_id" TEXT,
|
||||
"complete_request_id" TEXT,
|
||||
"destruction_proof_digest" TEXT,
|
||||
"completed_at_ms" INTEGER,
|
||||
"complete_audit_event_id" TEXT,
|
||||
FOREIGN KEY ("pepper_key_id")
|
||||
REFERENCES "QingLong3LocalOwnerPepperKeys" ("pepper_key_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("active_pepper_key_id")
|
||||
REFERENCES "QingLong3LocalOwnerPepperKeys" ("pepper_key_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("active_generation")
|
||||
REFERENCES "QingLong3LocalOwnerPepperActivations" ("generation")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("prepare_audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("complete_audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_mutation_check CHECK (
|
||||
length("prepare_mutation_id") = 36
|
||||
AND "prepare_audit_event_id" = "prepare_mutation_id"
|
||||
AND ("complete_mutation_id" IS NULL OR (
|
||||
length("complete_mutation_id") = 36
|
||||
AND "complete_mutation_id" <> "prepare_mutation_id"
|
||||
AND "complete_audit_event_id" = "complete_mutation_id"
|
||||
))
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_request_check CHECK (
|
||||
length("prepare_request_id") BETWEEN 1 AND 128
|
||||
AND ("complete_request_id" IS NULL
|
||||
OR length("complete_request_id") BETWEEN 1 AND 128)
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_key_check CHECK (
|
||||
length("pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND length("active_pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "active_pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND "pepper_key_id" <> "active_pepper_key_id"
|
||||
AND "active_generation" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_digest_check CHECK (
|
||||
length("material_digest") = 64
|
||||
AND "material_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("backup_material_digest") = 64
|
||||
AND "backup_material_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("active_material_digest") = 64
|
||||
AND "active_material_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("retention_policy_digest") = 64
|
||||
AND "retention_policy_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND ("destruction_proof_digest" IS NULL OR (
|
||||
length("destruction_proof_digest") = 64
|
||||
AND "destruction_proof_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
))
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_retention_check CHECK (
|
||||
"retention_policy_version" = 1
|
||||
AND "acknowledgement_retention_ms" BETWEEN 604800000 AND 315360000000
|
||||
AND "audit_retention_ms" BETWEEN 2592000000 AND 315360000000
|
||||
AND "backup_retention_ms" BETWEEN 2592000000 AND 315360000000
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_time_check CHECK (
|
||||
"references_inspected_at_ms" = "prepared_at_ms"
|
||||
AND "retention_eligible_at_ms" <= "prepared_at_ms"
|
||||
AND "prepared_at_ms" >= 0
|
||||
AND ("completed_at_ms" IS NULL
|
||||
OR "completed_at_ms" >= "prepared_at_ms")
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_pepper_gc_shape_check CHECK (
|
||||
("state" = 'prepared'
|
||||
AND "complete_mutation_id" IS NULL
|
||||
AND "complete_request_id" IS NULL
|
||||
AND "destruction_proof_digest" IS NULL
|
||||
AND "completed_at_ms" IS NULL
|
||||
AND "complete_audit_event_id" IS NULL)
|
||||
OR ("state" = 'completed'
|
||||
AND "complete_mutation_id" IS NOT NULL
|
||||
AND "complete_request_id" IS NOT NULL
|
||||
AND "destruction_proof_digest" IS NOT NULL
|
||||
AND "completed_at_ms" IS NOT NULL
|
||||
AND "complete_audit_event_id" IS NOT NULL)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_pepper_gc_key_uidx"
|
||||
ON "QingLong3LocalOwnerPepperMaterialGc" ("pepper_key_id")
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_pepper_gc_open_uidx"
|
||||
ON "QingLong3LocalOwnerPepperMaterialGc" ("state")
|
||||
WHERE "state" = 'prepared'
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_pepper_gc_complete_mutation_uidx"
|
||||
ON "QingLong3LocalOwnerPepperMaterialGc" ("complete_mutation_id")
|
||||
WHERE "complete_mutation_id" IS NOT NULL
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_pepper_gc_state_idx"
|
||||
ON "QingLong3LocalOwnerPepperMaterialGc" (
|
||||
"state", "retention_eligible_at_ms", "pepper_key_id"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0024CapabilityV12Migration = defineLocalSqliteMigration({
|
||||
id: '0024-capability-v12',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 12,
|
||||
migration_id = '0023-local-owner-pepper-material-gc',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 11
|
||||
AND migration_id = '0021-local-owner-credential-recovery'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0025LocalOwnerDeliveryAcknowledgementGcMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0025-local-owner-delivery-acknowledgement-gc',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalOwnerDeliveryAcknowledgementGc" (
|
||||
"gc_mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"gc_request_id" TEXT NOT NULL,
|
||||
"acknowledgement_mutation_id" TEXT NOT NULL,
|
||||
"acknowledgement_kind" TEXT NOT NULL,
|
||||
"delivery_digest" TEXT NOT NULL,
|
||||
"acknowledged_at_ms" INTEGER NOT NULL,
|
||||
"acknowledgement_semantic_digest" TEXT NOT NULL,
|
||||
"bridge_clear_evidence_digest" TEXT NOT NULL,
|
||||
"retention_policy_version" INTEGER NOT NULL,
|
||||
"replay_retention_ms" INTEGER NOT NULL,
|
||||
"audit_retention_ms" INTEGER NOT NULL,
|
||||
"retention_policy_digest" TEXT NOT NULL,
|
||||
"retention_eligible_at_ms" INTEGER NOT NULL,
|
||||
"compacted_at_ms" INTEGER NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL,
|
||||
"provisioning_mutation_id" TEXT,
|
||||
"challenge_mutation_id" TEXT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("provisioning_mutation_id")
|
||||
REFERENCES "QingLong3LocalIdentityProvisionings" ("mutation_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("challenge_mutation_id")
|
||||
REFERENCES "QingLong3LocalOwnerBootstrapChallenges" ("issue_mutation_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_gc_mutation_check CHECK (
|
||||
length("gc_mutation_id") = 36
|
||||
AND "audit_event_id" = "gc_mutation_id"
|
||||
AND length("acknowledgement_mutation_id") = 36
|
||||
AND "acknowledgement_mutation_id" <> "gc_mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_gc_request_check CHECK (
|
||||
length("gc_request_id") BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_gc_digest_check CHECK (
|
||||
length("delivery_digest") = 64
|
||||
AND "delivery_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("acknowledgement_semantic_digest") = 64
|
||||
AND "acknowledgement_semantic_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("bridge_clear_evidence_digest") = 64
|
||||
AND "bridge_clear_evidence_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("retention_policy_digest") = 64
|
||||
AND "retention_policy_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_gc_retention_check CHECK (
|
||||
"retention_policy_version" = 1
|
||||
AND "replay_retention_ms" BETWEEN 2592000000 AND 315360000000
|
||||
AND "audit_retention_ms" BETWEEN 2592000000 AND 315360000000
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_gc_time_check CHECK (
|
||||
"acknowledged_at_ms" >= 0
|
||||
AND "retention_eligible_at_ms" <= "compacted_at_ms"
|
||||
AND "compacted_at_ms" >= "acknowledged_at_ms"
|
||||
),
|
||||
CONSTRAINT ql3_local_owner_delivery_ack_gc_shape_check CHECK (
|
||||
(
|
||||
"acknowledgement_kind" = 'credential'
|
||||
AND "provisioning_mutation_id" = "acknowledgement_mutation_id"
|
||||
AND "challenge_mutation_id" IS NULL
|
||||
)
|
||||
OR (
|
||||
"acknowledgement_kind" = 'challenge'
|
||||
AND "provisioning_mutation_id" IS NULL
|
||||
AND "challenge_mutation_id" = "acknowledgement_mutation_id"
|
||||
)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_owner_delivery_ack_gc_ack_uidx"
|
||||
ON "QingLong3LocalOwnerDeliveryAcknowledgementGc" (
|
||||
"acknowledgement_mutation_id"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_local_owner_delivery_ack_gc_compacted_idx"
|
||||
ON "QingLong3LocalOwnerDeliveryAcknowledgementGc" (
|
||||
"acknowledgement_kind", "compacted_at_ms", "acknowledgement_mutation_id"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0026CapabilityV13Migration = defineLocalSqliteMigration({
|
||||
id: '0026-capability-v13',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 13,
|
||||
migration_id = '0025-local-owner-delivery-acknowledgement-gc',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 12
|
||||
AND migration_id = '0023-local-owner-pepper-material-gc'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0027TaskDefinitionsMigration = defineLocalSqliteMigration({
|
||||
id: '0027-task-definitions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3TaskDefinitions" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"task_id" TEXT NOT NULL,
|
||||
"current_revision" INTEGER NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
"updated_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "task_id"),
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_task_definitions_id_check CHECK (
|
||||
length("project_id") BETWEEN 1 AND 128
|
||||
AND length("task_id") BETWEEN 1 AND 128
|
||||
AND "project_id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
AND "task_id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
),
|
||||
CONSTRAINT ql3_task_definitions_revision_check CHECK (
|
||||
"current_revision" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_task_definitions_time_check CHECK (
|
||||
"created_at_ms" >= 0 AND "updated_at_ms" >= "created_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3TaskDefinitionRevisions" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"task_id" TEXT NOT NULL,
|
||||
"revision" INTEGER NOT NULL,
|
||||
"mutation_id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"kind" TEXT NOT NULL,
|
||||
"spec_json" TEXT NOT NULL,
|
||||
"labels_json" TEXT NOT NULL,
|
||||
"enabled" INTEGER NOT NULL,
|
||||
"content_digest" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "task_id", "revision"),
|
||||
FOREIGN KEY ("project_id", "task_id")
|
||||
REFERENCES "QingLong3TaskDefinitions" ("project_id", "task_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_task_definition_revisions_revision_check CHECK (
|
||||
"revision" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
AND substr("mutation_id", 9, 1) = '-'
|
||||
AND substr("mutation_id", 14, 1) = '-'
|
||||
AND substr("mutation_id", 19, 1) = '-'
|
||||
AND substr("mutation_id", 24, 1) = '-'
|
||||
AND replace("mutation_id", '-', '') NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_name_check CHECK (
|
||||
length("name") BETWEEN 1 AND 255
|
||||
AND ("description" IS NULL OR length("description") BETWEEN 1 AND 4096)
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_kind_check CHECK (
|
||||
"kind" IN ('script','command','workflow','agent','tool')
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_spec_check CHECK (
|
||||
json_valid("spec_json")
|
||||
AND json_type("spec_json") = 'object'
|
||||
AND length("spec_json") BETWEEN 1 AND 65536
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_labels_check CHECK (
|
||||
json_valid("labels_json")
|
||||
AND json_type("labels_json") = 'object'
|
||||
AND length("labels_json") BETWEEN 2 AND 16384
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_enabled_check CHECK (
|
||||
"enabled" IN (0, 1)
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_digest_check CHECK (
|
||||
length("content_digest") = 64
|
||||
AND "content_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_task_definition_revisions_created_check CHECK (
|
||||
"created_at_ms" >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_task_definition_revisions_mutation_uidx"
|
||||
ON "QingLong3TaskDefinitionRevisions" ("mutation_id")
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_task_definition_revisions_project_kind_idx"
|
||||
ON "QingLong3TaskDefinitionRevisions" (
|
||||
"project_id", "kind", "enabled", "task_id", "revision"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0028CapabilityV14Migration = defineLocalSqliteMigration({
|
||||
id: '0028-capability-v14',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 14,
|
||||
migration_id = '0027-task-definitions',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 13
|
||||
AND migration_id = '0025-local-owner-delivery-acknowledgement-gc'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,261 @@
|
||||
import {
|
||||
createLocalTaskExecutionRevision,
|
||||
type LocalDispatchCommand,
|
||||
} from '@qinglong/runtime-core/local-dispatch';
|
||||
import {
|
||||
normalizeTaskDefinitionRecord,
|
||||
type TaskDefinitionRecord,
|
||||
} from '@qinglong/runtime-core/task-definition';
|
||||
import { compileLocalCommandTaskDefinition } from '@qinglong/runtime-core/task-definition-execution-compiler';
|
||||
import {
|
||||
BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
|
||||
createBuiltInTaskSpecSemanticRegistry,
|
||||
} from '@qinglong/runtime-core/task-spec-semantic';
|
||||
import { LocalSqliteDispatchDefinitionStore } from '../task-definition/dispatchDefinitionStore';
|
||||
import { defineLocalSqliteProgrammaticMigration } from './sqlMigration';
|
||||
|
||||
const REPLACEMENT_TABLE = `
|
||||
CREATE TABLE "QingLong3LocalTaskExecutionRevisions_v15" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"task_id" TEXT NOT NULL,
|
||||
"task_revision" TEXT NOT NULL,
|
||||
"executor_type" TEXT NOT NULL,
|
||||
"command_json" TEXT NOT NULL,
|
||||
"working_directory" TEXT,
|
||||
"timeout_ms" INTEGER,
|
||||
"context_ref" TEXT NOT NULL,
|
||||
"content_digest" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "task_id", "task_revision"),
|
||||
CONSTRAINT ql3_local_revision_executor_check CHECK (
|
||||
"executor_type" = 'local_process'
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_command_check CHECK (
|
||||
json_valid("command_json")
|
||||
AND json_type("command_json") = 'object'
|
||||
AND length("command_json") BETWEEN 1 AND 131072
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_working_directory_check CHECK (
|
||||
"working_directory" IS NULL
|
||||
OR (length("working_directory") BETWEEN 1 AND 4096
|
||||
AND substr("working_directory", 1, 1) = '/')
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_timeout_check CHECK (
|
||||
"timeout_ms" IS NULL OR "timeout_ms" BETWEEN 1 AND 31536000000
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_digest_check CHECK (
|
||||
length("content_digest") = 64
|
||||
AND "content_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_local_revision_created_check CHECK ("created_at_ms" >= 0),
|
||||
FOREIGN KEY ("context_ref")
|
||||
REFERENCES "QingLong3LocalExecutionContextRecipes" ("context_ref")
|
||||
ON DELETE RESTRICT
|
||||
)
|
||||
`;
|
||||
|
||||
type RevisionRow = Record<string, unknown>;
|
||||
|
||||
function requiredText(row: RevisionRow, key: string): string {
|
||||
const value = row[key];
|
||||
if (typeof value !== 'string') {
|
||||
throw new TypeError(`Local execution revision ${key} is invalid`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function optionalText(row: RevisionRow, key: string): string | undefined {
|
||||
const value = row[key];
|
||||
if (value === null) return undefined;
|
||||
return requiredText(row, key);
|
||||
}
|
||||
|
||||
function requiredInteger(row: RevisionRow, key: string): number {
|
||||
const value = row[key];
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new TypeError(`Local execution revision ${key} is invalid`);
|
||||
}
|
||||
return value as number;
|
||||
}
|
||||
|
||||
function optionalInteger(row: RevisionRow, key: string): number | undefined {
|
||||
const value = row[key];
|
||||
if (value === null) return undefined;
|
||||
return requiredInteger(row, key);
|
||||
}
|
||||
|
||||
function command(row: RevisionRow): LocalDispatchCommand {
|
||||
try {
|
||||
return JSON.parse(requiredText(row, 'commandJson')) as LocalDispatchCommand;
|
||||
} catch {
|
||||
throw new TypeError('Local execution revision commandJson is invalid');
|
||||
}
|
||||
}
|
||||
|
||||
function requiredJson(row: RevisionRow, key: string): unknown {
|
||||
try {
|
||||
return JSON.parse(requiredText(row, key)) as unknown;
|
||||
} catch {
|
||||
throw new TypeError(`TaskDefinition ${key} is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
function taskDefinition(row: RevisionRow): TaskDefinitionRecord {
|
||||
const description = optionalText(row, 'description');
|
||||
const enabled = requiredInteger(row, 'enabled');
|
||||
if (enabled !== 0 && enabled !== 1) {
|
||||
throw new TypeError('TaskDefinition enabled is invalid');
|
||||
}
|
||||
return normalizeTaskDefinitionRecord({
|
||||
projectId: requiredText(row, 'projectId'),
|
||||
taskId: requiredText(row, 'taskId'),
|
||||
revision: requiredInteger(row, 'revision'),
|
||||
mutationId: requiredText(row, 'mutationId'),
|
||||
name: requiredText(row, 'name'),
|
||||
...(description === undefined ? {} : { description }),
|
||||
kind: requiredText(row, 'kind') as TaskDefinitionRecord['kind'],
|
||||
spec: requiredJson(row, 'specJson') as TaskDefinitionRecord['spec'],
|
||||
labels: requiredJson(row, 'labelsJson') as TaskDefinitionRecord['labels'],
|
||||
enabled: enabled === 1,
|
||||
contentDigest: requiredText(row, 'taskContentDigest'),
|
||||
createdAtMs: requiredInteger(row, 'taskCreatedAtMs'),
|
||||
updatedAtMs: requiredInteger(row, 'taskUpdatedAtMs'),
|
||||
});
|
||||
}
|
||||
|
||||
export const local0029LocalExecutionRevisionDigestMigration =
|
||||
defineLocalSqliteProgrammaticMigration({
|
||||
id: '0029-local-execution-revision-digest',
|
||||
program: [
|
||||
REPLACEMENT_TABLE,
|
||||
`Read every legacy revision in primary-key order without buffering.
|
||||
Parse and normalize command_json through
|
||||
createLocalTaskExecutionRevision using digest domain
|
||||
qinglong.local-task-execution-revision.v1 NUL. The digest covers
|
||||
project, task, revision, executor, canonical command, optional working
|
||||
directory, optional timeout and context ref; created_at_ms is excluded
|
||||
so an exact semantic replay preserves the first observed timestamp.`,
|
||||
`Insert every normalized row and computed lowercase SHA-256 digest into
|
||||
QingLong3LocalTaskExecutionRevisions_v15. Reject malformed legacy rows,
|
||||
count drift, constraint failures or digest failures so the enclosing
|
||||
BEGIN IMMEDIATE transaction rolls the entire migration back.`,
|
||||
`After the digest table replacement, read every historical enabled
|
||||
qinglong/command@v1 TaskDefinition revision in primary-key order,
|
||||
revalidate its stored TaskDefinition content digest and built-in
|
||||
semantics, compile the deterministic local plan, and append its context
|
||||
recipe and execution revision through exact-content replay. Skip
|
||||
disabled and non-built-in revisions; reject missing Projects, corrupt
|
||||
built-in records or pre-existing derived identity conflicts.`,
|
||||
'DROP TABLE "QingLong3LocalTaskExecutionRevisions"',
|
||||
`ALTER TABLE "QingLong3LocalTaskExecutionRevisions_v15"
|
||||
RENAME TO "QingLong3LocalTaskExecutionRevisions"`,
|
||||
],
|
||||
up({ client }) {
|
||||
client.exec(REPLACEMENT_TABLE);
|
||||
const rows = client.prepare(
|
||||
`SELECT "project_id" AS "projectId", "task_id" AS "taskId",
|
||||
"task_revision" AS "taskRevision",
|
||||
"executor_type" AS "executorType",
|
||||
"command_json" AS "commandJson",
|
||||
"working_directory" AS "workingDirectory",
|
||||
"timeout_ms" AS "timeoutMs", "context_ref" AS "contextRef",
|
||||
"created_at_ms" AS "createdAtMs"
|
||||
FROM "QingLong3LocalTaskExecutionRevisions"
|
||||
ORDER BY "project_id", "task_id", "task_revision"`,
|
||||
);
|
||||
const insert = client.prepare(
|
||||
`INSERT INTO "QingLong3LocalTaskExecutionRevisions_v15" (
|
||||
"project_id", "task_id", "task_revision", "executor_type",
|
||||
"command_json", "working_directory", "timeout_ms", "context_ref",
|
||||
"content_digest", "created_at_ms"
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
);
|
||||
let backfilled = 0;
|
||||
for (const value of rows.iterate() as Iterable<RevisionRow>) {
|
||||
const executorType = requiredText(value, 'executorType');
|
||||
if (executorType !== 'local_process') {
|
||||
throw new TypeError('Local execution revision executorType is invalid');
|
||||
}
|
||||
const workingDirectory = optionalText(value, 'workingDirectory');
|
||||
const timeoutMs = optionalInteger(value, 'timeoutMs');
|
||||
const revision = createLocalTaskExecutionRevision({
|
||||
projectId: requiredText(value, 'projectId'),
|
||||
taskId: requiredText(value, 'taskId'),
|
||||
taskRevision: requiredText(value, 'taskRevision'),
|
||||
executorType,
|
||||
command: command(value),
|
||||
...(workingDirectory === undefined ? {} : { workingDirectory }),
|
||||
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
||||
contextRef: requiredText(value, 'contextRef'),
|
||||
createdAtMs: requiredInteger(value, 'createdAtMs'),
|
||||
});
|
||||
insert.run(
|
||||
revision.projectId,
|
||||
revision.taskId,
|
||||
revision.taskRevision,
|
||||
revision.executorType,
|
||||
JSON.stringify(revision.command),
|
||||
revision.workingDirectory ?? null,
|
||||
revision.timeoutMs ?? null,
|
||||
revision.contextRef,
|
||||
revision.contentDigest,
|
||||
revision.createdAtMs,
|
||||
);
|
||||
backfilled += 1;
|
||||
}
|
||||
const sourceCount = client
|
||||
.prepare(
|
||||
'SELECT COUNT(*) AS "count" FROM "QingLong3LocalTaskExecutionRevisions"',
|
||||
)
|
||||
.get() as { count?: unknown } | undefined;
|
||||
if (
|
||||
!sourceCount ||
|
||||
!Number.isSafeInteger(sourceCount.count) ||
|
||||
sourceCount.count !== backfilled
|
||||
) {
|
||||
throw new TypeError('Local execution revision backfill count drifted');
|
||||
}
|
||||
client.exec('DROP TABLE "QingLong3LocalTaskExecutionRevisions"');
|
||||
client.exec(
|
||||
`ALTER TABLE "QingLong3LocalTaskExecutionRevisions_v15"
|
||||
RENAME TO "QingLong3LocalTaskExecutionRevisions"`,
|
||||
);
|
||||
|
||||
const semanticRegistry = createBuiltInTaskSpecSemanticRegistry();
|
||||
const definitions = client.prepare(
|
||||
`SELECT revision."project_id" AS "projectId",
|
||||
revision."task_id" AS "taskId",
|
||||
revision."revision" AS "revision",
|
||||
revision."mutation_id" AS "mutationId",
|
||||
revision."name" AS "name",
|
||||
revision."description" AS "description",
|
||||
revision."kind" AS "kind",
|
||||
revision."spec_json" AS "specJson",
|
||||
revision."labels_json" AS "labelsJson",
|
||||
revision."enabled" AS "enabled",
|
||||
revision."content_digest" AS "taskContentDigest",
|
||||
head."created_at_ms" AS "taskCreatedAtMs",
|
||||
revision."created_at_ms" AS "taskUpdatedAtMs"
|
||||
FROM "QingLong3TaskDefinitionRevisions" AS revision
|
||||
JOIN "QingLong3TaskDefinitions" AS head
|
||||
ON head."project_id" = revision."project_id"
|
||||
AND head."task_id" = revision."task_id"
|
||||
ORDER BY revision."project_id", revision."task_id",
|
||||
revision."revision"`,
|
||||
);
|
||||
const dispatchDefinitions = new LocalSqliteDispatchDefinitionStore(client);
|
||||
for (const value of definitions.iterate() as Iterable<RevisionRow>) {
|
||||
const definition = taskDefinition(value);
|
||||
if (
|
||||
!definition.enabled ||
|
||||
definition.kind !== 'command' ||
|
||||
definition.spec.schema !== BUILT_IN_COMMAND_TASK_SPEC_SCHEMA
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
dispatchDefinitions.appendPlan(
|
||||
compileLocalCommandTaskDefinition(definition, semanticRegistry),
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0030CapabilityV15Migration = defineLocalSqliteMigration({
|
||||
id: '0030-capability-v15',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 15,
|
||||
migration_id = '0029-local-execution-revision-digest',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 14
|
||||
AND migration_id = '0027-task-definitions'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,111 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0031TriggerDefinitionsMigration = defineLocalSqliteMigration({
|
||||
id: '0031-trigger-definitions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3Triggers" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"trigger_id" TEXT NOT NULL,
|
||||
"task_id" TEXT NOT NULL,
|
||||
"current_revision" INTEGER NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
"updated_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "trigger_id"),
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("project_id", "task_id")
|
||||
REFERENCES "QingLong3TaskDefinitions" ("project_id", "task_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_triggers_id_check CHECK (
|
||||
length("project_id") BETWEEN 1 AND 128
|
||||
AND length("trigger_id") BETWEEN 1 AND 128
|
||||
AND length("task_id") BETWEEN 1 AND 128
|
||||
AND "project_id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
AND "trigger_id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
AND "task_id" NOT GLOB '*[' || char(0) || '-' || char(31) || char(127) || ']*'
|
||||
),
|
||||
CONSTRAINT ql3_triggers_revision_check CHECK (
|
||||
"current_revision" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_triggers_time_check CHECK (
|
||||
"created_at_ms" >= 0 AND "updated_at_ms" >= "created_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_triggers_task_uidx"
|
||||
ON "QingLong3Triggers" ("project_id", "trigger_id", "task_id")
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3TriggerRevisions" (
|
||||
"project_id" TEXT NOT NULL,
|
||||
"trigger_id" TEXT NOT NULL,
|
||||
"revision" INTEGER NOT NULL,
|
||||
"mutation_id" TEXT NOT NULL,
|
||||
"task_id" TEXT NOT NULL,
|
||||
"task_revision" INTEGER NOT NULL,
|
||||
"task_content_digest" TEXT NOT NULL,
|
||||
"spec_json" TEXT NOT NULL,
|
||||
"enabled" INTEGER NOT NULL,
|
||||
"content_digest" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("project_id", "trigger_id", "revision"),
|
||||
FOREIGN KEY ("project_id", "trigger_id", "task_id")
|
||||
REFERENCES "QingLong3Triggers" ("project_id", "trigger_id", "task_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("project_id", "task_id", "task_revision")
|
||||
REFERENCES "QingLong3TaskDefinitionRevisions" ("project_id", "task_id", "revision")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_trigger_revisions_revision_check CHECK (
|
||||
"revision" BETWEEN 1 AND 2147483647
|
||||
AND "task_revision" BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_trigger_revisions_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
AND substr("mutation_id", 9, 1) = '-'
|
||||
AND substr("mutation_id", 14, 1) = '-'
|
||||
AND substr("mutation_id", 19, 1) = '-'
|
||||
AND substr("mutation_id", 24, 1) = '-'
|
||||
AND replace("mutation_id", '-', '') NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_trigger_revisions_task_digest_check CHECK (
|
||||
length("task_content_digest") = 64
|
||||
AND "task_content_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_trigger_revisions_spec_check CHECK (
|
||||
json_valid("spec_json")
|
||||
AND json_type("spec_json") = 'object'
|
||||
AND length("spec_json") BETWEEN 1 AND 16384
|
||||
),
|
||||
CONSTRAINT ql3_trigger_revisions_enabled_check CHECK (
|
||||
"enabled" IN (0, 1)
|
||||
),
|
||||
CONSTRAINT ql3_trigger_revisions_digest_check CHECK (
|
||||
length("content_digest") = 64
|
||||
AND "content_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_trigger_revisions_created_check CHECK (
|
||||
"created_at_ms" >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_trigger_revisions_mutation_uidx"
|
||||
ON "QingLong3TriggerRevisions" ("mutation_id")
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_trigger_revisions_project_enabled_idx"
|
||||
ON "QingLong3TriggerRevisions" (
|
||||
"project_id", "enabled", "trigger_id", "revision"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_trigger_revisions_task_idx"
|
||||
ON "QingLong3TriggerRevisions" (
|
||||
"project_id", "task_id", "task_revision", "trigger_id", "revision"
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0032CapabilityV16Migration = defineLocalSqliteMigration({
|
||||
id: '0032-capability-v16',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 16,
|
||||
migration_id = '0031-trigger-definitions',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 15
|
||||
AND migration_id = '0029-local-execution-revision-digest'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0033LegacyAdoptionLedgerMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0033-legacy-adoption-ledger',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LegacyAdoptions" (
|
||||
"mutation_id" TEXT PRIMARY KEY,
|
||||
"decision_id" TEXT NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"profile" TEXT NOT NULL,
|
||||
"plan_digest" TEXT NOT NULL,
|
||||
"inventory_digest" TEXT NOT NULL,
|
||||
"decision_digest" TEXT NOT NULL,
|
||||
"receipt_digest" TEXT NOT NULL,
|
||||
"authorization_file_digest" TEXT NOT NULL,
|
||||
"publication_digest" TEXT NOT NULL,
|
||||
"row_count" INTEGER NOT NULL,
|
||||
"adopted_task_count" INTEGER NOT NULL,
|
||||
"adopted_trigger_count" INTEGER NOT NULL,
|
||||
"skipped_count" INTEGER NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_legacy_adoptions_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
AND "audit_event_id" = "mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_legacy_adoptions_decision_check CHECK (
|
||||
length("decision_id") = 36
|
||||
AND substr("decision_id", 15, 1) = '7'
|
||||
AND replace("decision_id", '-', '') NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_legacy_adoptions_profile_check CHECK (
|
||||
"profile" IN ('edge', 'standalone')
|
||||
),
|
||||
CONSTRAINT ql3_legacy_adoptions_digest_check CHECK (
|
||||
length("plan_digest") = 64
|
||||
AND "plan_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("inventory_digest") = 64
|
||||
AND "inventory_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("decision_digest") = 64
|
||||
AND "decision_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("receipt_digest") = 64
|
||||
AND "receipt_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("authorization_file_digest") = 64
|
||||
AND "authorization_file_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND length("publication_digest") = 64
|
||||
AND "publication_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_legacy_adoptions_count_check CHECK (
|
||||
"row_count" BETWEEN 0 AND 100000
|
||||
AND "adopted_task_count" BETWEEN 0 AND "row_count"
|
||||
AND "skipped_count" BETWEEN 0 AND "row_count"
|
||||
AND "adopted_task_count" + "skipped_count" = "row_count"
|
||||
AND "adopted_trigger_count" BETWEEN 0 AND 500000
|
||||
),
|
||||
CONSTRAINT ql3_legacy_adoptions_created_check CHECK (
|
||||
"created_at_ms" >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_legacy_adoptions_decision_uidx"
|
||||
ON "QingLong3LegacyAdoptions" ("decision_id")
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_legacy_adoptions_project_time_idx"
|
||||
ON "QingLong3LegacyAdoptions" (
|
||||
"project_id", "created_at_ms" DESC, "mutation_id" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0034CapabilityV17Migration = defineLocalSqliteMigration({
|
||||
id: '0034-capability-v17',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 17,
|
||||
migration_id = '0033-legacy-adoption-ledger',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 16
|
||||
AND migration_id = '0031-trigger-definitions'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0035LocalSchedulerMigration = defineLocalSqliteMigration({
|
||||
id: '0035-local-scheduler',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3LocalTriggerSchedules" (
|
||||
project_id TEXT NOT NULL,
|
||||
trigger_id TEXT NOT NULL,
|
||||
trigger_revision INTEGER NOT NULL,
|
||||
next_fire_at_ms INTEGER,
|
||||
last_scheduled_at_ms INTEGER,
|
||||
state_version INTEGER NOT NULL DEFAULT 0,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
PRIMARY KEY (project_id, trigger_id),
|
||||
CONSTRAINT ql3_local_trigger_schedules_trigger_fk
|
||||
FOREIGN KEY (project_id, trigger_id)
|
||||
REFERENCES "QingLong3Triggers" (project_id, trigger_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_local_trigger_schedules_revision_check
|
||||
CHECK (trigger_revision BETWEEN 1 AND 2147483647),
|
||||
CONSTRAINT ql3_local_trigger_schedules_state_check
|
||||
CHECK (state_version >= 0),
|
||||
CONSTRAINT ql3_local_trigger_schedules_time_check CHECK (
|
||||
updated_at_ms >= 0 AND
|
||||
(next_fire_at_ms IS NULL OR next_fire_at_ms >= 0) AND
|
||||
(last_scheduled_at_ms IS NULL OR last_scheduled_at_ms >= 0)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_local_trigger_schedules_due_idx ON "QingLong3LocalTriggerSchedules" (next_fire_at_ms, project_id, trigger_id) WHERE next_fire_at_ms IS NOT NULL`,
|
||||
`CREATE INDEX ql3_local_trigger_schedules_initialize_idx ON "QingLong3LocalTriggerSchedules" (project_id, trigger_id) WHERE next_fire_at_ms IS NULL`,
|
||||
`
|
||||
INSERT INTO "QingLong3LocalTriggerSchedules" (
|
||||
project_id, trigger_id, trigger_revision, next_fire_at_ms,
|
||||
last_scheduled_at_ms, state_version, updated_at_ms
|
||||
)
|
||||
SELECT project_id, trigger_id, current_revision, NULL, NULL, 0, updated_at_ms
|
||||
FROM "QingLong3Triggers"
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0036CapabilityV18Migration = defineLocalSqliteMigration({
|
||||
id: '0036-capability-v18',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 18,
|
||||
migration_id = '0035-local-scheduler',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 17
|
||||
AND migration_id = '0033-legacy-adoption-ledger'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0037PluginPackageInstallsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0037-plugin-package-installs',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageInstalls" (
|
||||
installation_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
package_version TEXT NOT NULL,
|
||||
operation TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
target_generation INTEGER NOT NULL,
|
||||
previous_active_lock_digest TEXT,
|
||||
active_lock_digest TEXT,
|
||||
state TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
last_mutation_id TEXT NOT NULL,
|
||||
last_mutation_digest TEXT NOT NULL,
|
||||
lock_json TEXT NOT NULL,
|
||||
record_json TEXT NOT NULL,
|
||||
record_digest TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_installs_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_installs_identity_check CHECK (
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 253 AND
|
||||
length(package_version) BETWEEN 1 AND 128 AND
|
||||
length(last_mutation_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_installs_operation_check
|
||||
CHECK (operation IN ('install','reinstall','upgrade','rollback')),
|
||||
CONSTRAINT ql3_plugin_package_installs_state_check
|
||||
CHECK (state IN ('queued','staged','activating','active','failed')),
|
||||
CONSTRAINT ql3_plugin_package_installs_version_check CHECK (
|
||||
target_generation BETWEEN 1 AND 2147483647 AND
|
||||
version BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_installs_digest_check CHECK (
|
||||
length(lock_digest) = 64 AND lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(previous_active_lock_digest IS NULL OR
|
||||
(length(previous_active_lock_digest) = 64 AND
|
||||
previous_active_lock_digest NOT GLOB '*[^0-9a-f]*')) AND
|
||||
(active_lock_digest IS NULL OR
|
||||
(length(active_lock_digest) = 64 AND
|
||||
active_lock_digest NOT GLOB '*[^0-9a-f]*')) AND
|
||||
length(last_mutation_digest) = 64 AND
|
||||
last_mutation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(record_digest) = 64 AND record_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_installs_record_check CHECK (
|
||||
length(lock_json) BETWEEN 2 AND 262144 AND
|
||||
json_valid(lock_json) AND json_type(lock_json) = 'object' AND
|
||||
json_extract(lock_json, '$.lockDigest') = lock_digest AND
|
||||
json_extract(lock_json, '$.projectId') = project_id AND
|
||||
json_extract(lock_json, '$.packageName') = package_name AND
|
||||
length(record_json) BETWEEN 2 AND 262144 AND
|
||||
json_valid(record_json) AND json_type(record_json) = 'object' AND
|
||||
json_extract(record_json, '$.installationId') = installation_id AND
|
||||
json_extract(record_json, '$.projectId') = project_id AND
|
||||
json_extract(record_json, '$.packageName') = package_name AND
|
||||
json_extract(record_json, '$.lockDigest') = lock_digest AND
|
||||
json_extract(record_json, '$.state') = state AND
|
||||
json_extract(record_json, '$.version') = version AND
|
||||
json_extract(record_json, '$.recordDigest') = record_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_installs_time_check CHECK (
|
||||
created_at_ms >= 0 AND updated_at_ms >= created_at_ms
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageInstallHeads" (
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
PRIMARY KEY (project_id, package_name),
|
||||
CONSTRAINT ql3_plugin_package_install_heads_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_install_heads_install_fk
|
||||
FOREIGN KEY (installation_id)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (installation_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_install_heads_identity_check CHECK (
|
||||
length(package_name) BETWEEN 1 AND 253 AND
|
||||
length(installation_id) BETWEEN 1 AND 128
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_install_heads_install_uidx ON "QingLong3PluginPackageInstallHeads" (installation_id)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageInstallMutations" (
|
||||
installation_id TEXT NOT NULL,
|
||||
mutation_id TEXT NOT NULL,
|
||||
mutation_digest TEXT NOT NULL,
|
||||
resulting_record_digest TEXT NOT NULL,
|
||||
occurred_at_ms INTEGER NOT NULL,
|
||||
PRIMARY KEY (installation_id, mutation_id),
|
||||
CONSTRAINT ql3_plugin_package_install_mutations_install_fk
|
||||
FOREIGN KEY (installation_id)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (installation_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_install_mutations_identity_check
|
||||
CHECK (length(mutation_id) BETWEEN 1 AND 128),
|
||||
CONSTRAINT ql3_plugin_package_install_mutations_digest_check CHECK (
|
||||
length(mutation_digest) = 64 AND
|
||||
mutation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(resulting_record_digest) = 64 AND
|
||||
resulting_record_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_install_mutations_time_check
|
||||
CHECK (occurred_at_ms >= 0)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_plugin_package_installs_recovery_idx ON "QingLong3PluginPackageInstalls" (state, package_name, installation_id) WHERE state IN ('queued','staged','activating')`,
|
||||
`CREATE INDEX ql3_plugin_package_installs_project_history_idx ON "QingLong3PluginPackageInstalls" (project_id, package_name, created_at_ms, installation_id)`,
|
||||
`CREATE INDEX ql3_plugin_package_install_mutations_result_idx ON "QingLong3PluginPackageInstallMutations" (installation_id, resulting_record_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0038CapabilityV19Migration = defineLocalSqliteMigration({
|
||||
id: '0038-capability-v19',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 19,
|
||||
migration_id = '0037-plugin-package-installs',
|
||||
capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 18
|
||||
AND migration_id = '0035-local-scheduler'
|
||||
AND capabilities = '{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0039ApprovedActionsMigration = defineLocalSqliteMigration({
|
||||
id: '0039-approved-actions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3ApprovalRequests" (
|
||||
request_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
action_type TEXT NOT NULL,
|
||||
action_ref TEXT NOT NULL,
|
||||
action_digest TEXT NOT NULL,
|
||||
preview_digest TEXT NOT NULL,
|
||||
requested_by_type TEXT NOT NULL,
|
||||
requested_by_id TEXT NOT NULL,
|
||||
decision_id TEXT,
|
||||
consumption_id TEXT,
|
||||
dispatch_id TEXT,
|
||||
expires_at_ms INTEGER NOT NULL,
|
||||
request_json TEXT NOT NULL,
|
||||
request_digest TEXT NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_approval_requests_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_approval_requests_identity_check CHECK (
|
||||
length(request_id) BETWEEN 1 AND 128 AND
|
||||
length(action_type) BETWEEN 1 AND 128 AND
|
||||
length(action_ref) BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_approval_requests_state_version_check CHECK (
|
||||
(state = 'pending' AND version = 1) OR
|
||||
(state IN ('approved','rejected') AND version = 2) OR
|
||||
(state = 'consumed' AND version = 3)
|
||||
),
|
||||
CONSTRAINT ql3_approval_requests_digest_check CHECK (
|
||||
length(action_digest) = 64 AND action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(preview_digest) = 64 AND preview_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(request_digest) = 64 AND request_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_approval_requests_subject_check CHECK (
|
||||
requested_by_type IN
|
||||
('user','api_app','mcp_client','agent','system','worker') AND
|
||||
length(requested_by_id) BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_approval_requests_mutation_tuple_check CHECK (
|
||||
(version = 1 AND decision_id IS NULL AND consumption_id IS NULL AND
|
||||
dispatch_id IS NULL) OR
|
||||
(version = 2 AND decision_id IS NOT NULL AND consumption_id IS NULL AND
|
||||
dispatch_id IS NULL) OR
|
||||
(version = 3 AND decision_id IS NOT NULL AND consumption_id IS NOT NULL AND
|
||||
dispatch_id IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT ql3_approval_requests_json_check CHECK (
|
||||
length(request_json) BETWEEN 2 AND 65536 AND
|
||||
json_valid(request_json) AND json_type(request_json) = 'object' AND
|
||||
json_extract(request_json, '$.id') = request_id AND
|
||||
json_extract(request_json, '$.projectId') = project_id AND
|
||||
json_extract(request_json, '$.version') = version AND
|
||||
json_extract(request_json, '$.state') = state AND
|
||||
json_extract(request_json, '$.action.actionType') = action_type AND
|
||||
json_extract(request_json, '$.action.actionRef') = action_ref AND
|
||||
json_extract(request_json, '$.action.actionDigest') = action_digest AND
|
||||
json_extract(request_json, '$.action.previewDigest') = preview_digest
|
||||
),
|
||||
CONSTRAINT ql3_approval_requests_time_check
|
||||
CHECK (expires_at_ms > 0 AND updated_at_ms >= 0)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_approval_requests_decision_uidx ON "QingLong3ApprovalRequests" (decision_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_approval_requests_consumption_uidx ON "QingLong3ApprovalRequests" (consumption_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_approval_requests_dispatch_uidx ON "QingLong3ApprovalRequests" (dispatch_id)`,
|
||||
`CREATE INDEX ql3_approval_requests_pending_idx ON "QingLong3ApprovalRequests" (expires_at_ms, request_id) WHERE state = 'pending'`,
|
||||
`CREATE INDEX ql3_approval_requests_project_idx ON "QingLong3ApprovalRequests" (project_id, updated_at_ms, request_id)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ApprovedActionDispatches" (
|
||||
dispatch_id TEXT PRIMARY KEY,
|
||||
approval_request_id TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
action_type TEXT NOT NULL,
|
||||
action_ref TEXT NOT NULL,
|
||||
action_digest TEXT NOT NULL,
|
||||
preview_digest TEXT NOT NULL,
|
||||
dispatch_json TEXT NOT NULL,
|
||||
dispatch_digest TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_approved_action_dispatch_request_fk
|
||||
FOREIGN KEY (approval_request_id)
|
||||
REFERENCES "QingLong3ApprovalRequests" (request_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_approved_action_dispatch_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_approved_action_dispatch_identity_check CHECK (
|
||||
length(dispatch_id) BETWEEN 1 AND 128 AND
|
||||
length(action_type) BETWEEN 1 AND 128 AND
|
||||
length(action_ref) BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_dispatch_digest_check CHECK (
|
||||
length(action_digest) = 64 AND action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(preview_digest) = 64 AND preview_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(dispatch_digest) = 64 AND dispatch_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_dispatch_json_check CHECK (
|
||||
length(dispatch_json) BETWEEN 2 AND 65536 AND
|
||||
json_valid(dispatch_json) AND json_type(dispatch_json) = 'object' AND
|
||||
json_extract(dispatch_json, '$.id') = dispatch_id AND
|
||||
json_extract(dispatch_json, '$.approvalRequestId') = approval_request_id AND
|
||||
json_extract(dispatch_json, '$.projectId') = project_id AND
|
||||
json_extract(dispatch_json, '$.action.actionType') = action_type AND
|
||||
json_extract(dispatch_json, '$.action.actionRef') = action_ref AND
|
||||
json_extract(dispatch_json, '$.action.actionDigest') = action_digest AND
|
||||
json_extract(dispatch_json, '$.action.previewDigest') = preview_digest
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_dispatch_time_check
|
||||
CHECK (created_at_ms >= 0)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_approved_action_dispatch_request_uidx ON "QingLong3ApprovedActionDispatches" (approval_request_id)`,
|
||||
`CREATE INDEX ql3_approved_action_dispatch_project_idx ON "QingLong3ApprovedActionDispatches" (project_id, created_at_ms, dispatch_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1}';
|
||||
|
||||
export const local0040CapabilityV20Migration = defineLocalSqliteMigration({
|
||||
id: '0040-capability-v20',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 20,
|
||||
migration_id = '0039-approved-actions',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 19
|
||||
AND migration_id = '0037-plugin-package-installs'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0041PluginPackageAdmissionReceiptsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0041-plugin-package-admission-receipts',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageAdmissionReceipts" (
|
||||
dispatch_id TEXT PRIMARY KEY,
|
||||
dispatch_digest TEXT NOT NULL,
|
||||
approval_request_id TEXT NOT NULL,
|
||||
action_ref TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
record_digest TEXT NOT NULL,
|
||||
mutation_id TEXT NOT NULL,
|
||||
mutation_digest TEXT NOT NULL,
|
||||
audit_event_id TEXT NOT NULL,
|
||||
admitted_at_ms INTEGER NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
receipt_digest TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_admission_dispatch_fk
|
||||
FOREIGN KEY (dispatch_id)
|
||||
REFERENCES "QingLong3ApprovedActionDispatches" (dispatch_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_admission_request_fk
|
||||
FOREIGN KEY (approval_request_id)
|
||||
REFERENCES "QingLong3ApprovalRequests" (request_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_admission_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_admission_install_fk
|
||||
FOREIGN KEY (installation_id)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (installation_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_admission_audit_fk
|
||||
FOREIGN KEY (audit_event_id)
|
||||
REFERENCES "QingLong3SecurityAuditEvents" (event_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_admission_identity_check CHECK (
|
||||
length(dispatch_id) BETWEEN 1 AND 128 AND
|
||||
length(approval_request_id) BETWEEN 1 AND 128 AND
|
||||
length(action_ref) BETWEEN 1 AND 255 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 64 AND
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(audit_event_id) = 36
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_admission_digest_check CHECK (
|
||||
length(dispatch_digest) = 64 AND
|
||||
dispatch_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(record_digest) = 64 AND record_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(mutation_digest) = 64 AND
|
||||
mutation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(receipt_digest) = 64 AND receipt_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_admission_json_check CHECK (
|
||||
length(receipt_json) BETWEEN 2 AND 65536 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/plugin-package-admission-receipt@v1' AND
|
||||
json_extract(receipt_json, '$.dispatchId') = dispatch_id AND
|
||||
json_extract(receipt_json, '$.dispatchDigest') = dispatch_digest AND
|
||||
json_extract(receipt_json, '$.approvalRequestId') = approval_request_id AND
|
||||
json_extract(receipt_json, '$.actionRef') = action_ref AND
|
||||
json_extract(receipt_json, '$.projectId') = project_id AND
|
||||
json_extract(receipt_json, '$.packageName') = package_name AND
|
||||
json_extract(receipt_json, '$.installationId') = installation_id AND
|
||||
json_extract(receipt_json, '$.lockDigest') = lock_digest AND
|
||||
json_extract(receipt_json, '$.recordDigest') = record_digest AND
|
||||
json_extract(receipt_json, '$.mutationId') = mutation_id AND
|
||||
json_extract(receipt_json, '$.mutationDigest') = mutation_digest AND
|
||||
json_extract(receipt_json, '$.auditEventId') = audit_event_id AND
|
||||
json_extract(receipt_json, '$.admittedAtMs') = admitted_at_ms AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_admission_time_check
|
||||
CHECK (admitted_at_ms >= 0)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_admission_install_uidx ON "QingLong3PluginPackageAdmissionReceipts" (installation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_admission_audit_uidx ON "QingLong3PluginPackageAdmissionReceipts" (audit_event_id)`,
|
||||
`CREATE INDEX ql3_plugin_package_admission_project_idx ON "QingLong3PluginPackageAdmissionReceipts" (project_id, admitted_at_ms, dispatch_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1}';
|
||||
|
||||
export const local0042CapabilityV21Migration = defineLocalSqliteMigration({
|
||||
id: '0042-capability-v21',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 21,
|
||||
migration_id = '0041-plugin-package-admission-receipts',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 20
|
||||
AND migration_id = '0039-approved-actions'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0043ApprovedActionExecutionsAndPackageProposalsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0043-approved-action-executions-and-package-proposals',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageInstallProposals" (
|
||||
action_ref TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
action_type TEXT NOT NULL,
|
||||
permission TEXT NOT NULL,
|
||||
action_digest TEXT NOT NULL,
|
||||
preview_digest TEXT NOT NULL,
|
||||
proposed_by_type TEXT NOT NULL,
|
||||
proposed_by_id TEXT NOT NULL,
|
||||
fence_project_version INTEGER NOT NULL,
|
||||
fence_binding_version INTEGER,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
proposal_json TEXT NOT NULL,
|
||||
proposal_digest TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_proposal_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_proposal_identity_check CHECK (
|
||||
length(action_ref) BETWEEN 1 AND 255 AND
|
||||
action_type = 'plugin_package.install' AND
|
||||
permission = 'package.manage' AND
|
||||
proposed_by_type IN
|
||||
('user','api_app','mcp_client','agent','system','worker') AND
|
||||
length(proposed_by_id) BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_proposal_digest_check CHECK (
|
||||
length(action_digest) = 64 AND action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(preview_digest) = 64 AND preview_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(proposal_digest) = 64 AND
|
||||
proposal_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_proposal_json_check CHECK (
|
||||
length(proposal_json) BETWEEN 2 AND 262144 AND
|
||||
json_valid(proposal_json) AND json_type(proposal_json) = 'object' AND
|
||||
json_extract(proposal_json, '$.schema') =
|
||||
'qinglong/plugin-package-install-proposal@v1' AND
|
||||
json_extract(proposal_json, '$.actionRef') = action_ref AND
|
||||
json_extract(proposal_json, '$.projectId') = project_id AND
|
||||
json_extract(proposal_json, '$.actionType') = action_type AND
|
||||
json_extract(proposal_json, '$.permission') = permission AND
|
||||
json_extract(proposal_json, '$.actionDigest') = action_digest AND
|
||||
json_extract(proposal_json, '$.previewDigest') = preview_digest AND
|
||||
json_extract(proposal_json, '$.proposedBy.type') = proposed_by_type AND
|
||||
json_extract(proposal_json, '$.proposedBy.id') = proposed_by_id AND
|
||||
json_extract(proposal_json, '$.proposalFence.projectVersion') =
|
||||
fence_project_version AND
|
||||
json_extract(proposal_json, '$.proposalFence.bindingVersion')
|
||||
IS fence_binding_version AND
|
||||
json_extract(proposal_json, '$.createdAtMs') = created_at_ms AND
|
||||
json_extract(proposal_json, '$.proposalDigest') = proposal_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_proposal_time_check CHECK (
|
||||
fence_project_version > 0 AND
|
||||
(fence_binding_version IS NULL OR fence_binding_version > 0) AND
|
||||
created_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_plugin_package_proposal_project_idx ON "QingLong3PluginPackageInstallProposals" (project_id, created_at_ms, action_ref)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ApprovedActionExecutions" (
|
||||
dispatch_id TEXT PRIMARY KEY,
|
||||
dispatch_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
attempt_count INTEGER NOT NULL,
|
||||
max_attempts INTEGER NOT NULL,
|
||||
eligible_at_ms INTEGER,
|
||||
next_attempt_at_ms INTEGER,
|
||||
lease_owner TEXT,
|
||||
lease_token TEXT,
|
||||
lease_expires_at_ms INTEGER,
|
||||
started_at_ms INTEGER,
|
||||
result_mutation_id TEXT,
|
||||
result_code TEXT,
|
||||
result_digest TEXT,
|
||||
completed_at_ms INTEGER,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
execution_json TEXT NOT NULL,
|
||||
execution_digest TEXT NOT NULL,
|
||||
CONSTRAINT ql3_approved_action_execution_dispatch_fk
|
||||
FOREIGN KEY (dispatch_id)
|
||||
REFERENCES "QingLong3ApprovedActionDispatches" (dispatch_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_approved_action_execution_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_approved_action_execution_state_check CHECK (
|
||||
status IN
|
||||
('pending','leased','executing','retry_wait','succeeded','failed','blocked')
|
||||
AND version BETWEEN 0 AND 2147483647
|
||||
AND attempt_count BETWEEN 0 AND 16
|
||||
AND max_attempts BETWEEN 1 AND 16
|
||||
AND attempt_count <= max_attempts
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_execution_lease_check CHECK (
|
||||
(lease_owner IS NULL AND lease_token IS NULL AND
|
||||
lease_expires_at_ms IS NULL) OR
|
||||
(length(lease_owner) BETWEEN 1 AND 128 AND
|
||||
length(lease_token) BETWEEN 1 AND 128 AND
|
||||
lease_expires_at_ms > updated_at_ms)
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_execution_result_check CHECK (
|
||||
(result_mutation_id IS NULL AND result_code IS NULL) OR
|
||||
(length(result_mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(result_code) BETWEEN 1 AND 64)
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_execution_digest_check CHECK (
|
||||
length(dispatch_digest) = 64 AND
|
||||
dispatch_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(result_digest IS NULL OR
|
||||
(length(result_digest) = 64 AND
|
||||
result_digest NOT GLOB '*[^0-9a-f]*')) AND
|
||||
length(execution_digest) = 64 AND
|
||||
execution_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_execution_json_check CHECK (
|
||||
length(execution_json) BETWEEN 2 AND 65536 AND
|
||||
json_valid(execution_json) AND json_type(execution_json) = 'object' AND
|
||||
json_extract(execution_json, '$.schema') =
|
||||
'qinglong/approved-action-execution@v1' AND
|
||||
json_extract(execution_json, '$.dispatchId') = dispatch_id AND
|
||||
json_extract(execution_json, '$.dispatchDigest') = dispatch_digest AND
|
||||
json_extract(execution_json, '$.projectId') = project_id AND
|
||||
json_extract(execution_json, '$.status') = status AND
|
||||
json_extract(execution_json, '$.version') = version AND
|
||||
json_extract(execution_json, '$.attemptCount') = attempt_count AND
|
||||
json_extract(execution_json, '$.maxAttempts') = max_attempts AND
|
||||
json_extract(execution_json, '$.executionDigest') = execution_digest
|
||||
),
|
||||
CONSTRAINT ql3_approved_action_execution_time_check CHECK (
|
||||
created_at_ms >= 0 AND updated_at_ms >= created_at_ms
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_approved_action_execution_due_idx ON "QingLong3ApprovedActionExecutions" (eligible_at_ms, dispatch_id) WHERE status IN ('pending','leased','retry_wait')`,
|
||||
`CREATE INDEX ql3_approved_action_execution_recovery_idx ON "QingLong3ApprovedActionExecutions" (lease_expires_at_ms, dispatch_id) WHERE status = 'executing'`,
|
||||
`CREATE INDEX ql3_approved_action_execution_project_idx ON "QingLong3ApprovedActionExecutions" (project_id, updated_at_ms, dispatch_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1}';
|
||||
|
||||
export const local0044CapabilityV22Migration = defineLocalSqliteMigration({
|
||||
id: '0044-capability-v22',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 22,
|
||||
migration_id =
|
||||
'0043-approved-action-executions-and-package-proposals',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 21
|
||||
AND migration_id = '0041-plugin-package-admission-receipts'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0045PluginPackageMaterializedRevisionsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0045-plugin-package-materialized-revisions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageMaterializedRevisions" (
|
||||
generation_digest TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
generation INTEGER NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
manifest_digest TEXT NOT NULL,
|
||||
revision_digest TEXT NOT NULL,
|
||||
revision_json TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_materialized_revision_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_materialized_revision_identity_check CHECK (
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
generation BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_materialized_revision_digest_check CHECK (
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(manifest_digest) = 64 AND
|
||||
manifest_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(revision_digest) = 64 AND
|
||||
revision_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_materialized_revision_json_check CHECK (
|
||||
length(revision_json) BETWEEN 2 AND 25165824 AND
|
||||
json_valid(revision_json) AND json_type(revision_json) = 'object' AND
|
||||
json_extract(revision_json, '$.schema') =
|
||||
'qinglong/plugin-package-materialized-revision@v1' AND
|
||||
json_extract(revision_json, '$.generation.generationDigest') =
|
||||
generation_digest AND
|
||||
json_extract(revision_json, '$.generation.projectId') = project_id AND
|
||||
json_extract(revision_json, '$.generation.packageName') = package_name AND
|
||||
json_extract(revision_json, '$.generation.generation') = generation AND
|
||||
json_extract(revision_json, '$.generation.lockDigest') = lock_digest AND
|
||||
json_extract(revision_json, '$.manifestDigest') = manifest_digest AND
|
||||
json_extract(revision_json, '$.revisionDigest') = revision_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_materialized_revision_time_check CHECK (
|
||||
created_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_materialized_revision_generation_uidx ON "QingLong3PluginPackageMaterializedRevisions" (project_id, package_name, generation)`,
|
||||
`CREATE INDEX ql3_plugin_package_materialized_revision_lock_idx ON "QingLong3PluginPackageMaterializedRevisions" (lock_digest, generation_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1}';
|
||||
|
||||
export const local0046CapabilityV23Migration = defineLocalSqliteMigration({
|
||||
id: '0046-capability-v23',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 23,
|
||||
migration_id = '0045-plugin-package-materialized-revisions',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 22
|
||||
AND migration_id =
|
||||
'0043-approved-action-executions-and-package-proposals'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,118 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0047PluginPackageTaskReconciliationsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0047-plugin-package-task-reconciliations',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageTaskOwnerships" (
|
||||
project_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
claimed_generation_digest TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
PRIMARY KEY (project_id, task_id),
|
||||
CONSTRAINT ql3_plugin_package_task_ownership_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_task_ownership_task_fk
|
||||
FOREIGN KEY (project_id, task_id)
|
||||
REFERENCES "QingLong3TaskDefinitions" (project_id, task_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_task_ownership_identity_check CHECK (
|
||||
length(task_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 63
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_ownership_digest_check CHECK (
|
||||
length(claimed_generation_digest) = 64 AND
|
||||
claimed_generation_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_ownership_namespace_check CHECK (
|
||||
task_id LIKE 'pkg:' || package_name || ':%'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_ownership_time_check CHECK (
|
||||
created_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_plugin_package_task_ownership_package_idx ON "QingLong3PluginPackageTaskOwnerships" (project_id, package_name, task_id)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageTaskReconciliations" (
|
||||
generation_digest TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
generation INTEGER NOT NULL,
|
||||
materialized_revision_digest TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
previous_lock_digest TEXT,
|
||||
receipt_digest TEXT NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
committed_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_materialized_fk
|
||||
FOREIGN KEY (generation_digest)
|
||||
REFERENCES "QingLong3PluginPackageMaterializedRevisions" (generation_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_identity_check CHECK (
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
generation BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_digest_check CHECK (
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(materialized_revision_digest) = 64 AND
|
||||
materialized_revision_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(previous_lock_digest IS NULL OR
|
||||
(length(previous_lock_digest) = 64 AND
|
||||
previous_lock_digest NOT GLOB '*[^0-9a-f]*')) AND
|
||||
length(receipt_digest) = 64 AND receipt_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_json_check CHECK (
|
||||
length(receipt_json) BETWEEN 2 AND 8388608 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/plugin-package-task-reconciliation@v1' AND
|
||||
json_extract(receipt_json, '$.generationDigest') = generation_digest AND
|
||||
json_extract(receipt_json, '$.projectId') = project_id AND
|
||||
json_extract(receipt_json, '$.packageName') = package_name AND
|
||||
json_extract(receipt_json, '$.generation') = generation AND
|
||||
json_extract(receipt_json, '$.materializedRevisionDigest') =
|
||||
materialized_revision_digest AND
|
||||
json_extract(receipt_json, '$.lockDigest') = lock_digest AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_time_check CHECK (
|
||||
committed_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_task_reconciliation_generation_uidx ON "QingLong3PluginPackageTaskReconciliations" (project_id, package_name, generation)`,
|
||||
`CREATE INDEX ql3_plugin_package_task_reconciliation_lock_idx ON "QingLong3PluginPackageTaskReconciliations" (lock_digest, generation_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageTaskReconciliationItems" (
|
||||
generation_digest TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
revision INTEGER NOT NULL,
|
||||
disposition TEXT NOT NULL,
|
||||
content_digest TEXT NOT NULL,
|
||||
PRIMARY KEY (generation_digest, task_id),
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_item_reconciliation_fk
|
||||
FOREIGN KEY (generation_digest)
|
||||
REFERENCES "QingLong3PluginPackageTaskReconciliations" (generation_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_item_identity_check CHECK (
|
||||
length(task_id) BETWEEN 1 AND 128 AND
|
||||
revision BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_item_disposition_check
|
||||
CHECK (disposition IN (
|
||||
'already_disabled','created','disabled','retained','updated'
|
||||
)),
|
||||
CONSTRAINT ql3_plugin_package_task_reconciliation_item_digest_check CHECK (
|
||||
length(content_digest) = 64 AND content_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_plugin_package_task_reconciliation_item_task_idx ON "QingLong3PluginPackageTaskReconciliationItems" (task_id, generation_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1}';
|
||||
|
||||
export const local0048CapabilityV24Migration = defineLocalSqliteMigration({
|
||||
id: '0048-capability-v24',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 24,
|
||||
migration_id = '0047-plugin-package-task-reconciliations',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 23
|
||||
AND migration_id = '0045-plugin-package-materialized-revisions'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,118 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0049ProjectToolDefinitionSnapshotsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0049-project-tool-definition-snapshots',
|
||||
statements: [
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_plugin_package_installs_snapshot_source_uidx
|
||||
ON "QingLong3PluginPackageInstalls" (
|
||||
project_id, package_name, installation_id, target_generation, lock_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_plugin_package_materialized_revision_snapshot_source_uidx
|
||||
ON "QingLong3PluginPackageMaterializedRevisions" (
|
||||
project_id, package_name, generation, generation_digest,
|
||||
lock_digest, revision_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ProjectToolDefinitionSnapshots" (
|
||||
project_id TEXT NOT NULL,
|
||||
active_vector_digest TEXT NOT NULL,
|
||||
definitions_digest TEXT NOT NULL,
|
||||
snapshot_digest TEXT NOT NULL,
|
||||
snapshot_json TEXT NOT NULL,
|
||||
committed_at_ms INTEGER NOT NULL,
|
||||
PRIMARY KEY (project_id, active_vector_digest),
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_project_fk
|
||||
FOREIGN KEY (project_id) REFERENCES "QingLong3Projects" (id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_identity_check CHECK (
|
||||
length(project_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_digest_check CHECK (
|
||||
length(active_vector_digest) = 64 AND
|
||||
active_vector_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(definitions_digest) = 64 AND
|
||||
definitions_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(snapshot_digest) = 64 AND
|
||||
snapshot_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_json_check CHECK (
|
||||
length(snapshot_json) BETWEEN 2 AND 8388608 AND
|
||||
json_valid(snapshot_json) AND json_type(snapshot_json) = 'object' AND
|
||||
json_extract(snapshot_json, '$.schema') =
|
||||
'qinglong/project-tool-definition-snapshot@v1' AND
|
||||
json_extract(snapshot_json, '$.projectId') = project_id AND
|
||||
json_extract(snapshot_json, '$.activeVectorDigest') =
|
||||
active_vector_digest AND
|
||||
json_extract(snapshot_json, '$.definitionsDigest') =
|
||||
definitions_digest AND
|
||||
json_extract(snapshot_json, '$.snapshotDigest') = snapshot_digest
|
||||
),
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_time_check CHECK (
|
||||
committed_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_project_tool_definition_snapshot_digest_uidx ON "QingLong3ProjectToolDefinitionSnapshots" (snapshot_digest)`,
|
||||
`CREATE INDEX ql3_project_tool_definition_snapshot_current_idx ON "QingLong3ProjectToolDefinitionSnapshots" (project_id, committed_at_ms DESC, active_vector_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ProjectToolDefinitionSnapshotSources" (
|
||||
project_id TEXT NOT NULL,
|
||||
active_vector_digest TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
generation INTEGER NOT NULL,
|
||||
generation_digest TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
revision_digest TEXT NOT NULL,
|
||||
PRIMARY KEY (project_id, active_vector_digest, package_name),
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_source_snapshot_fk
|
||||
FOREIGN KEY (project_id, active_vector_digest)
|
||||
REFERENCES "QingLong3ProjectToolDefinitionSnapshots" (
|
||||
project_id, active_vector_digest
|
||||
)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_source_install_fk
|
||||
FOREIGN KEY (
|
||||
project_id, package_name, installation_id, generation, lock_digest
|
||||
)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (
|
||||
project_id, package_name, installation_id, target_generation, lock_digest
|
||||
)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_source_revision_fk
|
||||
FOREIGN KEY (
|
||||
project_id, package_name, generation, generation_digest,
|
||||
lock_digest, revision_digest
|
||||
)
|
||||
REFERENCES "QingLong3PluginPackageMaterializedRevisions" (
|
||||
project_id, package_name, generation, generation_digest,
|
||||
lock_digest, revision_digest
|
||||
)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_source_identity_check
|
||||
CHECK (
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
generation BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_project_tool_definition_snapshot_source_digest_check CHECK (
|
||||
length(active_vector_digest) = 64 AND
|
||||
active_vector_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(revision_digest) = 64 AND
|
||||
revision_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_project_tool_definition_snapshot_source_generation_idx ON "QingLong3ProjectToolDefinitionSnapshotSources" (generation_digest, project_id, package_name)`,
|
||||
`CREATE INDEX ql3_project_tool_definition_snapshot_source_install_idx ON "QingLong3ProjectToolDefinitionSnapshotSources" (installation_id, active_vector_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1}';
|
||||
|
||||
export const local0050CapabilityV25Migration = defineLocalSqliteMigration({
|
||||
id: '0050-capability-v25',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 25,
|
||||
migration_id = '0049-project-tool-definition-snapshots',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 24
|
||||
AND migration_id = '0047-plugin-package-task-reconciliations'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,222 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
import { LOCAL_STEP_RUN_REFERENCE_TRIGGERS } from '../run/stepRunSchemaContract';
|
||||
|
||||
export const local0051StepRunsMigration = defineLocalSqliteMigration({
|
||||
id: '0051-step-runs',
|
||||
statements: [
|
||||
`
|
||||
CREATE TEMP TABLE "QingLong3StepRunReferenceUpgradeGuard" (
|
||||
valid INTEGER NOT NULL CHECK (valid = 1)
|
||||
)
|
||||
`,
|
||||
`
|
||||
INSERT INTO "QingLong3StepRunReferenceUpgradeGuard" (valid)
|
||||
SELECT CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM "RunAttempts" WHERE step_run_id IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT 1 FROM "RunEvents" WHERE step_run_id IS NOT NULL
|
||||
) THEN 0
|
||||
ELSE 1
|
||||
END
|
||||
`,
|
||||
`DROP TABLE "QingLong3StepRunReferenceUpgradeGuard"`,
|
||||
`
|
||||
CREATE TABLE "StepRuns" (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
parent_step_run_id TEXT,
|
||||
step_key TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
definition_ref TEXT NOT NULL,
|
||||
definition_digest TEXT NOT NULL,
|
||||
required INTEGER NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
attempt_count INTEGER NOT NULL,
|
||||
input_ref TEXT,
|
||||
output_ref TEXT,
|
||||
approval_request_id TEXT,
|
||||
ready_at_ms INTEGER,
|
||||
started_at_ms INTEGER,
|
||||
finished_at_ms INTEGER,
|
||||
result_code TEXT,
|
||||
error_summary TEXT,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
last_mutation_id TEXT NOT NULL,
|
||||
step_run_digest TEXT NOT NULL,
|
||||
step_run_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_step_runs_run_fk
|
||||
FOREIGN KEY (run_id) REFERENCES "Runs" (id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_step_runs_parent_fk
|
||||
FOREIGN KEY (run_id, parent_step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_step_runs_identity_check CHECK (
|
||||
length(id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
(parent_step_run_id IS NULL OR
|
||||
(length(parent_step_run_id) BETWEEN 1 AND 128 AND
|
||||
parent_step_run_id <> id)) AND
|
||||
length(step_key) BETWEEN 1 AND 128 AND
|
||||
length(CAST(definition_ref AS BLOB)) BETWEEN 1 AND 512
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_kind_check CHECK (
|
||||
kind IN (
|
||||
'task', 'tool', 'model', 'agent', 'condition', 'approval',
|
||||
'subworkflow'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_status_check CHECK (
|
||||
status IN (
|
||||
'pending', 'ready', 'waiting_approval', 'running', 'lost',
|
||||
'succeeded', 'failed', 'skipped', 'cancelled', 'timed_out'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_digest_check CHECK (
|
||||
length(definition_digest) = 64 AND
|
||||
definition_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(step_run_digest) = 64 AND
|
||||
step_run_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_counter_check CHECK (
|
||||
required IN (0, 1) AND
|
||||
version BETWEEN 1 AND 2147483647 AND
|
||||
attempt_count BETWEEN 0 AND 64
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_reference_check CHECK (
|
||||
(input_ref IS NULL OR
|
||||
length(CAST(input_ref AS BLOB)) BETWEEN 1 AND 512) AND
|
||||
(output_ref IS NULL OR
|
||||
length(CAST(output_ref AS BLOB)) BETWEEN 1 AND 512) AND
|
||||
(approval_request_id IS NULL OR
|
||||
length(approval_request_id) BETWEEN 1 AND 128)
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_time_check CHECK (
|
||||
created_at_ms >= 0 AND updated_at_ms >= created_at_ms AND
|
||||
(ready_at_ms IS NULL OR
|
||||
ready_at_ms BETWEEN created_at_ms AND updated_at_ms) AND
|
||||
(started_at_ms IS NULL OR
|
||||
(ready_at_ms IS NOT NULL AND
|
||||
started_at_ms BETWEEN ready_at_ms AND updated_at_ms)) AND
|
||||
(finished_at_ms IS NULL OR
|
||||
(finished_at_ms BETWEEN created_at_ms AND updated_at_ms AND
|
||||
(ready_at_ms IS NULL OR finished_at_ms >= ready_at_ms) AND
|
||||
(started_at_ms IS NULL OR finished_at_ms >= started_at_ms)))
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_state_shape_check CHECK (
|
||||
(status = 'pending' AND ready_at_ms IS NULL AND
|
||||
started_at_ms IS NULL AND finished_at_ms IS NULL) OR
|
||||
(status IN ('ready', 'waiting_approval') AND ready_at_ms IS NOT NULL AND
|
||||
started_at_ms IS NULL AND finished_at_ms IS NULL) OR
|
||||
(status IN ('running', 'lost') AND ready_at_ms IS NOT NULL AND
|
||||
started_at_ms IS NOT NULL AND finished_at_ms IS NULL) OR
|
||||
(status IN ('succeeded', 'failed', 'skipped', 'cancelled', 'timed_out')
|
||||
AND finished_at_ms IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_result_shape_check CHECK (
|
||||
(status = 'waiting_approval' AND approval_request_id IS NOT NULL) OR
|
||||
status <> 'waiting_approval'
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_result_value_check CHECK (
|
||||
(output_ref IS NULL OR status = 'succeeded') AND
|
||||
(status = 'succeeded' AND result_code IS NULL AND error_summary IS NULL OR
|
||||
status IN ('failed', 'skipped', 'cancelled', 'timed_out', 'lost') AND
|
||||
result_code IS NOT NULL OR
|
||||
status IN ('pending', 'ready', 'waiting_approval', 'running') AND
|
||||
result_code IS NULL AND error_summary IS NULL) AND
|
||||
(result_code IS NULL OR
|
||||
(length(result_code) BETWEEN 1 AND 64 AND
|
||||
result_code NOT GLOB '*[^a-z0-9_]*' AND
|
||||
substr(result_code, 1, 1) GLOB '[a-z]')) AND
|
||||
(error_summary IS NULL OR
|
||||
length(CAST(error_summary AS BLOB)) BETWEEN 1 AND 2048)
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_mutation_identity_check CHECK (
|
||||
length(last_mutation_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_step_runs_json_check CHECK (
|
||||
length(CAST(step_run_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(step_run_json) AND json_type(step_run_json) = 'object' AND
|
||||
json_extract(step_run_json, '$.schema') = 'qinglong/step-run@v1' AND
|
||||
json_extract(step_run_json, '$.id') = id AND
|
||||
json_extract(step_run_json, '$.runId') = run_id AND
|
||||
json_extract(step_run_json, '$.parentStepRunId') IS parent_step_run_id AND
|
||||
json_extract(step_run_json, '$.stepKey') = step_key AND
|
||||
json_extract(step_run_json, '$.kind') = kind AND
|
||||
json_extract(step_run_json, '$.definitionRef') = definition_ref AND
|
||||
json_extract(step_run_json, '$.definitionDigest') = definition_digest AND
|
||||
json_extract(step_run_json, '$.required') IS required AND
|
||||
json_extract(step_run_json, '$.status') = status AND
|
||||
json_extract(step_run_json, '$.version') = version AND
|
||||
json_extract(step_run_json, '$.attemptCount') IS attempt_count AND
|
||||
json_extract(step_run_json, '$.inputRef') IS input_ref AND
|
||||
json_extract(step_run_json, '$.outputRef') IS output_ref AND
|
||||
json_extract(step_run_json, '$.approvalRequestId') IS
|
||||
approval_request_id AND
|
||||
json_extract(step_run_json, '$.readyAtMs') IS ready_at_ms AND
|
||||
json_extract(step_run_json, '$.startedAtMs') IS started_at_ms AND
|
||||
json_extract(step_run_json, '$.finishedAtMs') IS finished_at_ms AND
|
||||
json_extract(step_run_json, '$.resultCode') IS result_code AND
|
||||
json_extract(step_run_json, '$.errorSummary') IS error_summary AND
|
||||
json_extract(step_run_json, '$.createdAtMs') IS created_at_ms AND
|
||||
json_extract(step_run_json, '$.updatedAtMs') IS updated_at_ms AND
|
||||
json_extract(step_run_json, '$.lastMutationId') = last_mutation_id AND
|
||||
json_extract(step_run_json, '$.stepRunDigest') = step_run_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_step_runs_run_id_uidx ON "StepRuns" (run_id, id)`,
|
||||
`CREATE UNIQUE INDEX ql3_step_runs_run_step_uidx ON "StepRuns" (run_id, step_key)`,
|
||||
`CREATE INDEX ql3_step_runs_run_status_idx ON "StepRuns" (run_id, status, id)`,
|
||||
`CREATE INDEX ql3_step_runs_recovery_idx ON "StepRuns" (status, updated_at_ms, id) WHERE status IN ('waiting_approval', 'running', 'lost')`,
|
||||
`
|
||||
CREATE TABLE "StepRunMutations" (
|
||||
mutation_id TEXT PRIMARY KEY NOT NULL,
|
||||
mutation_digest TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
step_run_digest TEXT NOT NULL,
|
||||
event_id TEXT NOT NULL,
|
||||
event_sequence INTEGER NOT NULL,
|
||||
run_version INTEGER NOT NULL,
|
||||
step_run_json TEXT NOT NULL,
|
||||
committed_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_step_run_mutations_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_step_run_mutations_event_fk
|
||||
FOREIGN KEY (event_id) REFERENCES "RunEvents" (id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_step_run_mutations_identity_check CHECK (
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(event_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_step_run_mutations_digest_check CHECK (
|
||||
length(mutation_digest) = 64 AND
|
||||
mutation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(step_run_digest) = 64 AND
|
||||
step_run_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_step_run_mutations_counter_check CHECK (
|
||||
event_sequence BETWEEN 1 AND 2147483647 AND
|
||||
run_version BETWEEN 1 AND 2147483647 AND
|
||||
committed_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_step_run_mutations_json_check CHECK (
|
||||
length(CAST(step_run_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(step_run_json) AND json_type(step_run_json) = 'object' AND
|
||||
json_extract(step_run_json, '$.schema') = 'qinglong/step-run@v1' AND
|
||||
json_extract(step_run_json, '$.id') = step_run_id AND
|
||||
json_extract(step_run_json, '$.runId') = run_id AND
|
||||
json_extract(step_run_json, '$.lastMutationId') = mutation_id AND
|
||||
json_extract(step_run_json, '$.stepRunDigest') = step_run_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_step_run_mutations_event_uidx ON "StepRunMutations" (event_id)`,
|
||||
`CREATE INDEX ql3_step_run_mutations_step_idx ON "StepRunMutations" (run_id, step_run_id, event_sequence, mutation_id)`,
|
||||
...LOCAL_STEP_RUN_REFERENCE_TRIGGERS.map((trigger) => trigger.sql),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1}';
|
||||
|
||||
export const local0052CapabilityV26Migration = defineLocalSqliteMigration({
|
||||
id: '0052-capability-v26',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 26,
|
||||
migration_id = '0051-step-runs',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 25
|
||||
AND migration_id = '0049-project-tool-definition-snapshots'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,169 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0053ToolExecutionEvidenceMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0053-tool-execution-evidence',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolExecutionTraceAnchors" (
|
||||
trace_id TEXT NOT NULL,
|
||||
span_id TEXT NOT NULL,
|
||||
parent_span_id TEXT,
|
||||
project_id TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
invocation_plan_digest TEXT NOT NULL,
|
||||
binding_digest TEXT NOT NULL,
|
||||
adapter_digest TEXT NOT NULL,
|
||||
redaction_contract_digest TEXT NOT NULL,
|
||||
audit_contract_digest TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
trace_digest TEXT NOT NULL,
|
||||
trace_json TEXT NOT NULL,
|
||||
CONSTRAINT tool_execution_trace_anchors_pkey
|
||||
PRIMARY KEY (trace_id, span_id),
|
||||
CONSTRAINT ql3_tool_execution_trace_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_tool_execution_trace_identity_check CHECK (
|
||||
length(trace_id) = 32 AND trace_id NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(span_id) = 16 AND span_id NOT GLOB '*[^0-9a-f]*' AND
|
||||
(parent_span_id IS NULL OR (
|
||||
length(parent_span_id) = 16 AND
|
||||
parent_span_id NOT GLOB '*[^0-9a-f]*' AND
|
||||
parent_span_id <> span_id
|
||||
)) AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_trace_digest_check CHECK (
|
||||
length(invocation_plan_digest) = 64 AND
|
||||
invocation_plan_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(binding_digest) = 64 AND
|
||||
binding_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(adapter_digest) = 64 AND
|
||||
adapter_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(redaction_contract_digest) = 64 AND
|
||||
redaction_contract_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(audit_contract_digest) = 64 AND
|
||||
audit_contract_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(trace_digest) = 64 AND
|
||||
trace_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_trace_time_check CHECK (
|
||||
created_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_trace_json_check CHECK (
|
||||
length(CAST(trace_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(trace_json) AND json_type(trace_json) = 'object' AND
|
||||
json_extract(trace_json, '$.schema') =
|
||||
'qinglong/tool-execution-trace-anchor@v1' AND
|
||||
json_extract(trace_json, '$.traceId') = trace_id AND
|
||||
json_extract(trace_json, '$.spanId') = span_id AND
|
||||
json_extract(trace_json, '$.parentSpanId') IS parent_span_id AND
|
||||
json_extract(trace_json, '$.projectId') = project_id AND
|
||||
json_extract(trace_json, '$.runId') = run_id AND
|
||||
json_extract(trace_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(trace_json, '$.invocationPlanDigest') =
|
||||
invocation_plan_digest AND
|
||||
json_extract(trace_json, '$.bindingDigest') = binding_digest AND
|
||||
json_extract(trace_json, '$.adapterDigest') = adapter_digest AND
|
||||
json_extract(trace_json, '$.redactionContractDigest') =
|
||||
redaction_contract_digest AND
|
||||
json_extract(trace_json, '$.auditContractDigest') =
|
||||
audit_contract_digest AND
|
||||
json_extract(trace_json, '$.createdAtMs') IS created_at_ms AND
|
||||
json_extract(trace_json, '$.traceDigest') = trace_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_execution_trace_run_idx ON "ToolExecutionTraceAnchors" (run_id, created_at_ms, trace_id, span_id)`,
|
||||
`CREATE INDEX ql3_tool_execution_trace_step_idx ON "ToolExecutionTraceAnchors" (run_id, step_run_id, created_at_ms, trace_id, span_id)`,
|
||||
`
|
||||
CREATE TABLE "ToolExecutionAuditReceipts" (
|
||||
event_id TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
trace_id TEXT NOT NULL,
|
||||
span_id TEXT NOT NULL,
|
||||
trace_digest TEXT NOT NULL,
|
||||
invocation_plan_digest TEXT NOT NULL,
|
||||
binding_digest TEXT NOT NULL,
|
||||
audit_record_digest TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
receipt_digest TEXT NOT NULL,
|
||||
audit_json TEXT NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_execution_audit_event_fk
|
||||
FOREIGN KEY (event_id)
|
||||
REFERENCES "QingLong3SecurityAuditEvents" (event_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_execution_audit_trace_fk
|
||||
FOREIGN KEY (trace_id, span_id)
|
||||
REFERENCES "ToolExecutionTraceAnchors" (trace_id, span_id)
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_tool_execution_audit_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE CASCADE,
|
||||
CONSTRAINT ql3_tool_execution_audit_identity_check CHECK (
|
||||
length(event_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(trace_id) = 32 AND trace_id NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(span_id) = 16 AND span_id NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_audit_digest_check CHECK (
|
||||
length(trace_digest) = 64 AND
|
||||
trace_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(invocation_plan_digest) = 64 AND
|
||||
invocation_plan_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(binding_digest) = 64 AND
|
||||
binding_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(audit_record_digest) = 64 AND
|
||||
audit_record_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(receipt_digest) = 64 AND
|
||||
receipt_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_audit_time_check CHECK (
|
||||
created_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_audit_json_check CHECK (
|
||||
length(CAST(audit_json AS BLOB)) BETWEEN 2 AND 8192 AND
|
||||
json_valid(audit_json) AND json_type(audit_json) = 'object' AND
|
||||
json_extract(audit_json, '$.eventId') = event_id AND
|
||||
json_extract(audit_json, '$.projectId') = project_id AND
|
||||
json_extract(audit_json, '$.operationId') = 'tool.invoke.start' AND
|
||||
json_extract(audit_json, '$.outcome') = 'allowed' AND
|
||||
json_type(audit_json, '$.fence') = 'object' AND
|
||||
json_extract(audit_json, '$.occurredAtMs') IS created_at_ms
|
||||
),
|
||||
CONSTRAINT ql3_tool_execution_audit_receipt_json_check CHECK (
|
||||
length(CAST(receipt_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/tool-execution-audit-receipt@v1' AND
|
||||
json_extract(receipt_json, '$.eventId') = event_id AND
|
||||
json_extract(receipt_json, '$.projectId') = project_id AND
|
||||
json_extract(receipt_json, '$.runId') = run_id AND
|
||||
json_extract(receipt_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(receipt_json, '$.traceId') = trace_id AND
|
||||
json_extract(receipt_json, '$.spanId') = span_id AND
|
||||
json_extract(receipt_json, '$.traceDigest') = trace_digest AND
|
||||
json_extract(receipt_json, '$.invocationPlanDigest') =
|
||||
invocation_plan_digest AND
|
||||
json_extract(receipt_json, '$.bindingDigest') = binding_digest AND
|
||||
json_extract(receipt_json, '$.auditRecordDigest') =
|
||||
audit_record_digest AND
|
||||
json_extract(receipt_json, '$.createdAtMs') IS created_at_ms AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_execution_audit_trace_uidx ON "ToolExecutionAuditReceipts" (trace_id, span_id)`,
|
||||
`CREATE INDEX ql3_tool_execution_audit_run_idx ON "ToolExecutionAuditReceipts" (run_id, created_at_ms, trace_id, span_id)`,
|
||||
`CREATE INDEX ql3_tool_execution_audit_step_idx ON "ToolExecutionAuditReceipts" (run_id, step_run_id, created_at_ms, event_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1}';
|
||||
|
||||
export const local0054CapabilityV27Migration = defineLocalSqliteMigration({
|
||||
id: '0054-capability-v27',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 27,
|
||||
migration_id = '0053-tool-execution-evidence',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 26
|
||||
AND migration_id = '0051-step-runs'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0055ToolExecutionStartBarriersMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0055-tool-execution-start-barriers',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolExecutionStartBarriers" (
|
||||
start_id TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
started_step_run_version INTEGER NOT NULL,
|
||||
step_run_mutation_id TEXT NOT NULL,
|
||||
run_event_id TEXT NOT NULL,
|
||||
trace_id TEXT NOT NULL,
|
||||
span_id TEXT NOT NULL,
|
||||
audit_event_id TEXT NOT NULL,
|
||||
command_digest TEXT NOT NULL,
|
||||
barrier_digest TEXT NOT NULL,
|
||||
started_at_ms INTEGER NOT NULL,
|
||||
barrier_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_start_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_mutation_fk
|
||||
FOREIGN KEY (step_run_mutation_id)
|
||||
REFERENCES "StepRunMutations" (mutation_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_event_fk
|
||||
FOREIGN KEY (run_event_id)
|
||||
REFERENCES "RunEvents" (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_trace_fk
|
||||
FOREIGN KEY (trace_id, span_id)
|
||||
REFERENCES "ToolExecutionTraceAnchors" (trace_id, span_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_audit_fk
|
||||
FOREIGN KEY (audit_event_id)
|
||||
REFERENCES "ToolExecutionAuditReceipts" (event_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_identity_check CHECK (
|
||||
length(start_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(run_event_id) BETWEEN 1 AND 128 AND
|
||||
length(trace_id) = 32 AND trace_id NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(span_id) = 16 AND span_id NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(audit_event_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_tool_start_version_time_check CHECK (
|
||||
started_step_run_version BETWEEN 2 AND 2147483647 AND
|
||||
started_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_start_digest_check CHECK (
|
||||
length(command_digest) = 64 AND
|
||||
command_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(barrier_digest) = 64 AND
|
||||
barrier_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_start_json_check CHECK (
|
||||
length(CAST(barrier_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(barrier_json) AND json_type(barrier_json) = 'object' AND
|
||||
json_extract(barrier_json, '$.schema') =
|
||||
'qinglong/tool-execution-start-barrier@v1' AND
|
||||
json_extract(barrier_json, '$.startId') = start_id AND
|
||||
json_extract(barrier_json, '$.projectId') = project_id AND
|
||||
json_extract(barrier_json, '$.runId') = run_id AND
|
||||
json_extract(barrier_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(barrier_json, '$.startedStepRunVersion') IS
|
||||
started_step_run_version AND
|
||||
json_extract(barrier_json, '$.stepRunMutationId') =
|
||||
step_run_mutation_id AND
|
||||
json_extract(barrier_json, '$.runEventId') = run_event_id AND
|
||||
json_extract(barrier_json, '$.traceId') = trace_id AND
|
||||
json_extract(barrier_json, '$.spanId') = span_id AND
|
||||
json_extract(barrier_json, '$.auditEventId') = audit_event_id AND
|
||||
json_extract(barrier_json, '$.commandDigest') = command_digest AND
|
||||
json_extract(barrier_json, '$.barrierDigest') = barrier_digest AND
|
||||
json_extract(barrier_json, '$.startedAtMs') IS started_at_ms
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_start_step_version_uidx ON "ToolExecutionStartBarriers" (run_id, step_run_id, started_step_run_version)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_start_mutation_uidx ON "ToolExecutionStartBarriers" (step_run_mutation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_start_event_uidx ON "ToolExecutionStartBarriers" (run_event_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_start_trace_uidx ON "ToolExecutionStartBarriers" (trace_id, span_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_start_audit_uidx ON "ToolExecutionStartBarriers" (audit_event_id)`,
|
||||
`CREATE INDEX ql3_tool_start_run_time_idx ON "ToolExecutionStartBarriers" (run_id, started_at_ms, start_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1}';
|
||||
|
||||
export const local0056CapabilityV28Migration = defineLocalSqliteMigration({
|
||||
id: '0056-capability-v28',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 28,
|
||||
migration_id = '0055-tool-execution-start-barriers',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 27
|
||||
AND migration_id = '0053-tool-execution-evidence'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0057ToolInvocationArtifactsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0057-tool-invocation-artifacts',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolInvocationInputArtifacts" (
|
||||
artifact_id TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
action_ref TEXT NOT NULL,
|
||||
input_digest TEXT NOT NULL,
|
||||
invocation_action_digest TEXT NOT NULL,
|
||||
artifact_digest TEXT NOT NULL,
|
||||
key_id TEXT NOT NULL,
|
||||
algorithm TEXT NOT NULL,
|
||||
plaintext_bytes INTEGER NOT NULL,
|
||||
sealed_at_ms INTEGER NOT NULL,
|
||||
artifact_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_input_artifact_project_fk
|
||||
FOREIGN KEY (project_id)
|
||||
REFERENCES "QingLong3Projects" (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_input_artifact_identity_check CHECK (
|
||||
length(artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(action_ref) BETWEEN 1 AND 255 AND
|
||||
length(key_id) BETWEEN 1 AND 128 AND
|
||||
algorithm = 'aes-256-gcm'
|
||||
),
|
||||
CONSTRAINT ql3_tool_input_artifact_digest_check CHECK (
|
||||
length(input_digest) = 64 AND
|
||||
input_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(invocation_action_digest) = 64 AND
|
||||
invocation_action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(artifact_digest) = 64 AND
|
||||
artifact_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_input_artifact_budget_check CHECK (
|
||||
plaintext_bytes BETWEEN 0 AND 65536 AND sealed_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_input_artifact_json_check CHECK (
|
||||
length(CAST(artifact_json AS BLOB)) BETWEEN 2 AND 98304 AND
|
||||
json_valid(artifact_json) AND json_type(artifact_json) = 'object' AND
|
||||
json_extract(artifact_json, '$.schema') =
|
||||
'qinglong/tool-invocation-input-artifact@v1' AND
|
||||
json_extract(artifact_json, '$.artifactId') = artifact_id AND
|
||||
json_extract(artifact_json, '$.projectId') = project_id AND
|
||||
json_extract(artifact_json, '$.actionRef') = action_ref AND
|
||||
json_extract(artifact_json, '$.inputDigest') = input_digest AND
|
||||
json_extract(artifact_json, '$.invocationActionDigest') =
|
||||
invocation_action_digest AND
|
||||
json_extract(artifact_json, '$.artifactDigest') = artifact_digest AND
|
||||
json_extract(artifact_json, '$.keyId') = key_id AND
|
||||
json_extract(artifact_json, '$.algorithm') = algorithm AND
|
||||
json_extract(artifact_json, '$.plaintextBytes') IS plaintext_bytes AND
|
||||
json_extract(artifact_json, '$.sealedAtMs') IS sealed_at_ms
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_input_artifact_action_uidx ON "ToolInvocationInputArtifacts" (project_id, action_ref)`,
|
||||
`CREATE INDEX ql3_tool_input_artifact_project_time_idx ON "ToolInvocationInputArtifacts" (project_id, sealed_at_ms, artifact_id)`,
|
||||
`
|
||||
CREATE TABLE "ToolInvocationPreviewArtifacts" (
|
||||
artifact_id TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
action_ref TEXT NOT NULL,
|
||||
action_digest TEXT NOT NULL,
|
||||
preview_digest TEXT NOT NULL,
|
||||
redaction_contract_digest TEXT NOT NULL,
|
||||
artifact_digest TEXT NOT NULL,
|
||||
byte_length INTEGER NOT NULL,
|
||||
sealed_at_ms INTEGER NOT NULL,
|
||||
artifact_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_preview_artifact_project_fk
|
||||
FOREIGN KEY (project_id)
|
||||
REFERENCES "QingLong3Projects" (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_preview_artifact_identity_check CHECK (
|
||||
length(artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(action_ref) BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_tool_preview_artifact_digest_check CHECK (
|
||||
length(action_digest) = 64 AND
|
||||
action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(preview_digest) = 64 AND
|
||||
preview_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(redaction_contract_digest) = 64 AND
|
||||
redaction_contract_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(artifact_digest) = 64 AND
|
||||
artifact_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_preview_artifact_budget_check CHECK (
|
||||
byte_length BETWEEN 2 AND 8192 AND sealed_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_preview_artifact_json_check CHECK (
|
||||
length(CAST(artifact_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(artifact_json) AND json_type(artifact_json) = 'object' AND
|
||||
json_extract(artifact_json, '$.schema') =
|
||||
'qinglong/tool-invocation-preview-artifact@v1' AND
|
||||
json_extract(artifact_json, '$.artifactId') = artifact_id AND
|
||||
json_extract(artifact_json, '$.projectId') = project_id AND
|
||||
json_extract(artifact_json, '$.actionRef') = action_ref AND
|
||||
json_extract(artifact_json, '$.actionDigest') = action_digest AND
|
||||
json_extract(artifact_json, '$.previewDigest') = preview_digest AND
|
||||
json_extract(artifact_json, '$.redactionContractDigest') =
|
||||
redaction_contract_digest AND
|
||||
json_extract(artifact_json, '$.artifactDigest') = artifact_digest AND
|
||||
json_extract(artifact_json, '$.byteLength') IS byte_length AND
|
||||
json_extract(artifact_json, '$.sealedAtMs') IS sealed_at_ms
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_preview_artifact_action_uidx ON "ToolInvocationPreviewArtifacts" (project_id, action_ref)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_preview_artifact_action_digest_uidx ON "ToolInvocationPreviewArtifacts" (action_digest)`,
|
||||
`CREATE INDEX ql3_tool_preview_artifact_project_time_idx ON "ToolInvocationPreviewArtifacts" (project_id, sealed_at_ms, artifact_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const PREVIOUS_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1}';
|
||||
const NEXT_CAPABILITIES =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1}';
|
||||
|
||||
export const local0058CapabilityV29Migration = defineLocalSqliteMigration({
|
||||
id: '0058-capability-v29',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 29,
|
||||
migration_id = '0057-tool-invocation-artifacts',
|
||||
capabilities = '${NEXT_CAPABILITIES}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 28
|
||||
AND migration_id = '0055-tool-execution-start-barriers'
|
||||
AND capabilities = '${PREVIOUS_CAPABILITIES}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0059ToolExecutionArtifactBindingsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0059-tool-execution-artifact-bindings',
|
||||
statements: [
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_tool_input_artifact_start_binding_uidx
|
||||
ON "ToolInvocationInputArtifacts" (
|
||||
artifact_id, artifact_digest, project_id, action_ref, input_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_tool_preview_artifact_start_binding_uidx
|
||||
ON "ToolInvocationPreviewArtifacts" (
|
||||
artifact_id, artifact_digest, project_id, action_ref, action_digest,
|
||||
preview_digest, redaction_contract_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "ToolExecutionStartArtifactBindings" (
|
||||
start_id TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
action_ref TEXT NOT NULL,
|
||||
input_artifact_id TEXT NOT NULL,
|
||||
input_artifact_digest TEXT NOT NULL,
|
||||
input_digest TEXT NOT NULL,
|
||||
preview_artifact_id TEXT NOT NULL,
|
||||
preview_artifact_digest TEXT NOT NULL,
|
||||
action_digest TEXT NOT NULL,
|
||||
preview_digest TEXT NOT NULL,
|
||||
redaction_contract_digest TEXT NOT NULL,
|
||||
bound_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_tool_start_artifact_barrier_fk
|
||||
FOREIGN KEY (start_id)
|
||||
REFERENCES "ToolExecutionStartBarriers" (start_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_input_artifact_fk
|
||||
FOREIGN KEY (
|
||||
input_artifact_id, input_artifact_digest, project_id, action_ref,
|
||||
input_digest
|
||||
)
|
||||
REFERENCES "ToolInvocationInputArtifacts" (
|
||||
artifact_id, artifact_digest, project_id, action_ref, input_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_preview_artifact_fk
|
||||
FOREIGN KEY (
|
||||
preview_artifact_id, preview_artifact_digest, project_id, action_ref,
|
||||
action_digest, preview_digest, redaction_contract_digest
|
||||
)
|
||||
REFERENCES "ToolInvocationPreviewArtifacts" (
|
||||
artifact_id, artifact_digest, project_id, action_ref, action_digest,
|
||||
preview_digest, redaction_contract_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_start_artifact_identity_check CHECK (
|
||||
length(start_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(action_ref) BETWEEN 1 AND 255 AND
|
||||
length(input_artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(preview_artifact_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_tool_start_artifact_digest_check CHECK (
|
||||
length(input_artifact_digest) = 64 AND
|
||||
input_artifact_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(input_digest) = 64 AND
|
||||
input_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(preview_artifact_digest) = 64 AND
|
||||
preview_artifact_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(action_digest) = 64 AND
|
||||
action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(preview_digest) = 64 AND
|
||||
preview_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(redaction_contract_digest) = 64 AND
|
||||
redaction_contract_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_start_artifact_time_check CHECK (bound_at_ms >= 0)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_start_artifact_input_idx ON "ToolExecutionStartArtifactBindings" (input_artifact_id, start_id)`,
|
||||
`CREATE INDEX ql3_tool_start_artifact_preview_idx ON "ToolExecutionStartArtifactBindings" (preview_artifact_id, start_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V29 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1}';
|
||||
const CAPABILITIES_V30 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1}';
|
||||
|
||||
export const local0060CapabilityV30Migration = defineLocalSqliteMigration({
|
||||
id: '0060-capability-v30',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 30,
|
||||
migration_id = '0059-tool-execution-artifact-bindings',
|
||||
capabilities = '${CAPABILITIES_V30}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 29
|
||||
AND migration_id = '0057-tool-invocation-artifacts'
|
||||
AND capabilities = '${CAPABILITIES_V29}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,144 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0061ToolExecutionCompletionsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0061-tool-execution-completions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolExecutionCompletions" (
|
||||
start_id TEXT PRIMARY KEY NOT NULL,
|
||||
artifact_id TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
started_step_run_version INTEGER NOT NULL,
|
||||
completed_step_run_version INTEGER NOT NULL,
|
||||
barrier_digest TEXT NOT NULL,
|
||||
adapter_digest TEXT NOT NULL,
|
||||
output_digest TEXT NOT NULL,
|
||||
execution_result_digest TEXT NOT NULL,
|
||||
artifact_digest TEXT NOT NULL,
|
||||
key_id TEXT NOT NULL,
|
||||
algorithm TEXT NOT NULL,
|
||||
plaintext_bytes INTEGER NOT NULL,
|
||||
step_run_mutation_id TEXT NOT NULL,
|
||||
step_run_mutation_digest TEXT NOT NULL,
|
||||
completed_step_run_digest TEXT NOT NULL,
|
||||
run_event_id TEXT NOT NULL,
|
||||
completed_at_ms INTEGER NOT NULL,
|
||||
completion_digest TEXT NOT NULL,
|
||||
artifact_json TEXT NOT NULL,
|
||||
completion_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_completion_start_fk
|
||||
FOREIGN KEY (start_id)
|
||||
REFERENCES "ToolExecutionStartBarriers" (start_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_completion_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_completion_mutation_fk
|
||||
FOREIGN KEY (step_run_mutation_id)
|
||||
REFERENCES "StepRunMutations" (mutation_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_completion_event_fk
|
||||
FOREIGN KEY (run_event_id)
|
||||
REFERENCES "RunEvents" (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_completion_identity_check CHECK (
|
||||
length(start_id) BETWEEN 1 AND 128 AND
|
||||
length(artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(key_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(run_event_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_tool_completion_version_check CHECK (
|
||||
started_step_run_version BETWEEN 2 AND 2147483646 AND
|
||||
completed_step_run_version = started_step_run_version + 1
|
||||
),
|
||||
CONSTRAINT ql3_tool_completion_digest_check CHECK (
|
||||
length(barrier_digest) = 64 AND
|
||||
barrier_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(adapter_digest) = 64 AND
|
||||
adapter_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(output_digest) = 64 AND
|
||||
output_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(execution_result_digest) = 64 AND
|
||||
execution_result_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(artifact_digest) = 64 AND
|
||||
artifact_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(step_run_mutation_digest) = 64 AND
|
||||
step_run_mutation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(completed_step_run_digest) = 64 AND
|
||||
completed_step_run_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(completion_digest) = 64 AND
|
||||
completion_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_completion_budget_check CHECK (
|
||||
algorithm = 'aes-256-gcm' AND
|
||||
plaintext_bytes BETWEEN 0 AND 262144 AND
|
||||
completed_at_ms >= 0 AND
|
||||
length(CAST(artifact_json AS BLOB)) BETWEEN 2 AND 393216 AND
|
||||
length(CAST(completion_json AS BLOB)) BETWEEN 2 AND 24576
|
||||
),
|
||||
CONSTRAINT ql3_tool_completion_json_check CHECK (
|
||||
json_valid(artifact_json) AND
|
||||
json_type(artifact_json) = 'object' AND
|
||||
json_extract(artifact_json, '$.schema') =
|
||||
'qinglong/tool-execution-result-artifact@v1' AND
|
||||
json_extract(artifact_json, '$.artifactId') = artifact_id AND
|
||||
json_extract(artifact_json, '$.projectId') = project_id AND
|
||||
json_extract(artifact_json, '$.startId') = start_id AND
|
||||
json_extract(artifact_json, '$.runId') = run_id AND
|
||||
json_extract(artifact_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(artifact_json, '$.barrierDigest') = barrier_digest AND
|
||||
json_extract(artifact_json, '$.adapterDigest') = adapter_digest AND
|
||||
json_extract(artifact_json, '$.outputDigest') = output_digest AND
|
||||
json_extract(artifact_json, '$.executionResultDigest') =
|
||||
execution_result_digest AND
|
||||
json_extract(artifact_json, '$.artifactDigest') = artifact_digest AND
|
||||
json_extract(artifact_json, '$.keyId') = key_id AND
|
||||
json_extract(artifact_json, '$.algorithm') = algorithm AND
|
||||
json_extract(artifact_json, '$.plaintextBytes') = plaintext_bytes AND
|
||||
json_extract(artifact_json, '$.sealedAtMs') = completed_at_ms AND
|
||||
json_valid(completion_json) AND
|
||||
json_type(completion_json) = 'object' AND
|
||||
json_extract(completion_json, '$.schema') =
|
||||
'qinglong/tool-execution-completion@v1' AND
|
||||
json_extract(completion_json, '$.startId') = start_id AND
|
||||
json_extract(completion_json, '$.projectId') = project_id AND
|
||||
json_extract(completion_json, '$.runId') = run_id AND
|
||||
json_extract(completion_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(completion_json, '$.startedStepRunVersion') =
|
||||
started_step_run_version AND
|
||||
json_extract(completion_json, '$.completedStepRunVersion') =
|
||||
completed_step_run_version AND
|
||||
json_extract(completion_json, '$.barrierDigest') = barrier_digest AND
|
||||
json_extract(completion_json, '$.adapterDigest') = adapter_digest AND
|
||||
json_extract(completion_json, '$.resultArtifact.artifactId') =
|
||||
artifact_id AND
|
||||
json_extract(completion_json, '$.resultArtifact.artifactDigest') =
|
||||
artifact_digest AND
|
||||
json_extract(completion_json, '$.resultArtifact.outputDigest') =
|
||||
output_digest AND
|
||||
json_extract(
|
||||
completion_json, '$.resultArtifact.executionResultDigest'
|
||||
) = execution_result_digest AND
|
||||
json_extract(completion_json, '$.stepRunMutationId') =
|
||||
step_run_mutation_id AND
|
||||
json_extract(completion_json, '$.stepRunMutationDigest') =
|
||||
step_run_mutation_digest AND
|
||||
json_extract(completion_json, '$.completedStepRunDigest') =
|
||||
completed_step_run_digest AND
|
||||
json_extract(completion_json, '$.runEventId') = run_event_id AND
|
||||
json_extract(completion_json, '$.completedAtMs') = completed_at_ms AND
|
||||
json_extract(completion_json, '$.completionDigest') = completion_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_completion_artifact_uidx ON "ToolExecutionCompletions" (artifact_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_completion_mutation_uidx ON "ToolExecutionCompletions" (step_run_mutation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_completion_event_uidx ON "ToolExecutionCompletions" (run_event_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_completion_step_version_uidx ON "ToolExecutionCompletions" (run_id, step_run_id, completed_step_run_version)`,
|
||||
`CREATE INDEX ql3_tool_completion_project_time_idx ON "ToolExecutionCompletions" (project_id, completed_at_ms, start_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V30 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1}';
|
||||
const CAPABILITIES_V31 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1}';
|
||||
|
||||
export const local0062CapabilityV31Migration = defineLocalSqliteMigration({
|
||||
id: '0062-capability-v31',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 31,
|
||||
migration_id = '0061-tool-execution-completions',
|
||||
capabilities = '${CAPABILITIES_V31}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 30
|
||||
AND migration_id = '0059-tool-execution-artifact-bindings'
|
||||
AND capabilities = '${CAPABILITIES_V30}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0063ToolExecutionFailureCompletionsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0063-tool-execution-failure-completions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolExecutionFailureCompletions" (
|
||||
start_id TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
started_step_run_version INTEGER NOT NULL,
|
||||
completed_step_run_version INTEGER NOT NULL,
|
||||
barrier_digest TEXT NOT NULL,
|
||||
adapter_digest TEXT NOT NULL,
|
||||
outcome TEXT NOT NULL,
|
||||
result_code TEXT NOT NULL,
|
||||
error_summary TEXT NOT NULL,
|
||||
step_run_mutation_id TEXT NOT NULL,
|
||||
step_run_mutation_digest TEXT NOT NULL,
|
||||
completed_step_run_digest TEXT NOT NULL,
|
||||
run_event_id TEXT NOT NULL,
|
||||
completed_at_ms INTEGER NOT NULL,
|
||||
completion_digest TEXT NOT NULL,
|
||||
completion_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_failure_completion_start_fk
|
||||
FOREIGN KEY (start_id)
|
||||
REFERENCES "ToolExecutionStartBarriers" (start_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_failure_completion_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_failure_completion_mutation_fk
|
||||
FOREIGN KEY (step_run_mutation_id)
|
||||
REFERENCES "StepRunMutations" (mutation_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_failure_completion_event_fk
|
||||
FOREIGN KEY (run_event_id)
|
||||
REFERENCES "RunEvents" (id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_failure_completion_identity_check CHECK (
|
||||
length(start_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(run_event_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_tool_failure_completion_version_check CHECK (
|
||||
started_step_run_version BETWEEN 2 AND 2147483646 AND
|
||||
completed_step_run_version = started_step_run_version + 1
|
||||
),
|
||||
CONSTRAINT ql3_tool_failure_completion_digest_check CHECK (
|
||||
length(barrier_digest) = 64 AND
|
||||
barrier_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(adapter_digest) = 64 AND
|
||||
adapter_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(step_run_mutation_digest) = 64 AND
|
||||
step_run_mutation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(completed_step_run_digest) = 64 AND
|
||||
completed_step_run_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(completion_digest) = 64 AND
|
||||
completion_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_failure_completion_fact_check CHECK (
|
||||
(
|
||||
outcome = 'failed' AND
|
||||
result_code = 'tool_adapter_failed' AND
|
||||
error_summary = 'Trusted Tool execution failed'
|
||||
) OR (
|
||||
outcome = 'timed_out' AND
|
||||
result_code = 'tool_deadline_exceeded' AND
|
||||
error_summary = 'Trusted Tool execution deadline exceeded'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_tool_failure_completion_budget_check CHECK (
|
||||
completed_at_ms >= 0 AND
|
||||
length(CAST(completion_json AS BLOB)) BETWEEN 2 AND 24576
|
||||
),
|
||||
CONSTRAINT ql3_tool_failure_completion_json_check CHECK (
|
||||
json_valid(completion_json) AND
|
||||
json_type(completion_json) = 'object' AND
|
||||
json_extract(completion_json, '$.schema') =
|
||||
'qinglong/tool-execution-failure-completion@v1' AND
|
||||
json_extract(completion_json, '$.startId') = start_id AND
|
||||
json_extract(completion_json, '$.projectId') = project_id AND
|
||||
json_extract(completion_json, '$.runId') = run_id AND
|
||||
json_extract(completion_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(completion_json, '$.startedStepRunVersion') =
|
||||
started_step_run_version AND
|
||||
json_extract(completion_json, '$.completedStepRunVersion') =
|
||||
completed_step_run_version AND
|
||||
json_extract(completion_json, '$.barrierDigest') = barrier_digest AND
|
||||
json_extract(completion_json, '$.adapterDigest') = adapter_digest AND
|
||||
json_extract(completion_json, '$.outcome') = outcome AND
|
||||
json_extract(completion_json, '$.resultCode') = result_code AND
|
||||
json_extract(completion_json, '$.errorSummary') = error_summary AND
|
||||
json_extract(completion_json, '$.stepRunMutationId') =
|
||||
step_run_mutation_id AND
|
||||
json_extract(completion_json, '$.stepRunMutationDigest') =
|
||||
step_run_mutation_digest AND
|
||||
json_extract(completion_json, '$.completedStepRunDigest') =
|
||||
completed_step_run_digest AND
|
||||
json_extract(completion_json, '$.runEventId') = run_event_id AND
|
||||
json_extract(completion_json, '$.completedAtMs') = completed_at_ms AND
|
||||
json_extract(completion_json, '$.completionDigest') = completion_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_failure_completion_mutation_uidx ON "ToolExecutionFailureCompletions" (step_run_mutation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_failure_completion_event_uidx ON "ToolExecutionFailureCompletions" (run_event_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_tool_failure_completion_step_version_uidx ON "ToolExecutionFailureCompletions" (run_id, step_run_id, completed_step_run_version)`,
|
||||
`CREATE INDEX ql3_tool_failure_completion_project_time_idx ON "ToolExecutionFailureCompletions" (project_id, completed_at_ms, start_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V31 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1}';
|
||||
const CAPABILITIES_V32 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1}';
|
||||
|
||||
export const local0064CapabilityV32Migration = defineLocalSqliteMigration({
|
||||
id: '0064-capability-v32',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 32,
|
||||
migration_id = '0063-tool-execution-failure-completions',
|
||||
capabilities = '${CAPABILITIES_V32}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 31
|
||||
AND migration_id = '0061-tool-execution-completions'
|
||||
AND capabilities = '${CAPABILITIES_V31}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0065ToolResultKeyCatalogMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0065-tool-result-key-catalog',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolResultKeyCatalogGenerations" (
|
||||
authority TEXT NOT NULL,
|
||||
generation INTEGER NOT NULL,
|
||||
previous_generation INTEGER,
|
||||
previous_catalog_digest TEXT,
|
||||
active_key_id TEXT,
|
||||
mutation_kind TEXT NOT NULL,
|
||||
mutation_id TEXT NOT NULL,
|
||||
catalog_digest TEXT NOT NULL,
|
||||
command_digest TEXT NOT NULL,
|
||||
committed_at_ms INTEGER NOT NULL,
|
||||
catalog_json TEXT NOT NULL,
|
||||
PRIMARY KEY (authority, generation),
|
||||
UNIQUE (authority, generation, catalog_digest),
|
||||
UNIQUE (mutation_id),
|
||||
UNIQUE (catalog_digest),
|
||||
CONSTRAINT ql3_tool_result_key_catalog_previous_fk
|
||||
FOREIGN KEY (
|
||||
authority, previous_generation, previous_catalog_digest
|
||||
)
|
||||
REFERENCES "ToolResultKeyCatalogGenerations" (
|
||||
authority, generation, catalog_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_key_catalog_authority_check CHECK (
|
||||
authority = 'trusted-tool-results'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_catalog_generation_check CHECK (
|
||||
generation BETWEEN 1 AND 2147483647 AND
|
||||
(
|
||||
(
|
||||
generation = 1 AND
|
||||
previous_generation IS NULL AND
|
||||
previous_catalog_digest IS NULL AND
|
||||
mutation_kind = 'bootstrap'
|
||||
) OR (
|
||||
generation > 1 AND
|
||||
previous_generation = generation - 1 AND
|
||||
previous_catalog_digest IS NOT NULL AND
|
||||
mutation_kind IN (
|
||||
'rotate', 'retire', 'mark_lost', 'restore'
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_catalog_identity_check CHECK (
|
||||
active_key_id IS NULL OR
|
||||
length(active_key_id) BETWEEN 1 AND 128 AND
|
||||
active_key_id NOT GLOB '*[^A-Za-z0-9._-]*' AND
|
||||
substr(active_key_id, 1, 1) GLOB '[A-Za-z0-9]'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_catalog_digest_check CHECK (
|
||||
(
|
||||
previous_catalog_digest IS NULL OR
|
||||
length(previous_catalog_digest) = 64 AND
|
||||
previous_catalog_digest NOT GLOB '*[^0-9a-f]*'
|
||||
) AND
|
||||
length(catalog_digest) = 64 AND
|
||||
catalog_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(command_digest) = 64 AND
|
||||
command_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_catalog_budget_check CHECK (
|
||||
committed_at_ms >= 0 AND
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(CAST(catalog_json AS BLOB)) BETWEEN 2 AND 65536
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_catalog_json_check CHECK (
|
||||
json_valid(catalog_json) AND
|
||||
json_type(catalog_json) = 'object' AND
|
||||
json_extract(catalog_json, '$.schema') =
|
||||
'qinglong/tool-result-key-catalog@v1' AND
|
||||
json_extract(catalog_json, '$.generation') = generation AND
|
||||
(
|
||||
(
|
||||
previous_catalog_digest IS NULL AND
|
||||
json_type(catalog_json, '$.previousCatalogDigest') = 'null'
|
||||
) OR
|
||||
json_extract(catalog_json, '$.previousCatalogDigest') =
|
||||
previous_catalog_digest
|
||||
) AND
|
||||
(
|
||||
(
|
||||
active_key_id IS NULL AND
|
||||
json_type(catalog_json, '$.activeKeyId') = 'null'
|
||||
) OR
|
||||
json_extract(catalog_json, '$.activeKeyId') = active_key_id
|
||||
) AND
|
||||
json_extract(catalog_json, '$.mutationKind') = mutation_kind AND
|
||||
json_extract(catalog_json, '$.mutationId') = mutation_id AND
|
||||
json_extract(catalog_json, '$.catalogDigest') = catalog_digest AND
|
||||
json_extract(catalog_json, '$.committedAtMs') = committed_at_ms AND
|
||||
json_type(catalog_json, '$.keys') = 'array' AND
|
||||
json_array_length(json_extract(catalog_json, '$.keys'))
|
||||
BETWEEN 1 AND 64
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_result_key_catalog_current_idx ON "ToolResultKeyCatalogGenerations" (authority, generation DESC)`,
|
||||
`
|
||||
CREATE TABLE "ToolExecutionResultKeyBindings" (
|
||||
start_id TEXT PRIMARY KEY NOT NULL,
|
||||
artifact_id TEXT NOT NULL UNIQUE,
|
||||
artifact_digest TEXT NOT NULL,
|
||||
catalog_authority TEXT NOT NULL,
|
||||
catalog_generation INTEGER NOT NULL,
|
||||
catalog_digest TEXT NOT NULL,
|
||||
key_id TEXT NOT NULL,
|
||||
material_proof TEXT NOT NULL,
|
||||
binding_digest TEXT NOT NULL UNIQUE,
|
||||
CONSTRAINT ql3_tool_result_key_binding_completion_fk
|
||||
FOREIGN KEY (start_id)
|
||||
REFERENCES "ToolExecutionCompletions" (start_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_key_binding_artifact_fk
|
||||
FOREIGN KEY (artifact_id)
|
||||
REFERENCES "ToolExecutionCompletions" (artifact_id) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_key_binding_catalog_fk
|
||||
FOREIGN KEY (
|
||||
catalog_authority, catalog_generation, catalog_digest
|
||||
)
|
||||
REFERENCES "ToolResultKeyCatalogGenerations" (
|
||||
authority, generation, catalog_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_key_binding_authority_check CHECK (
|
||||
catalog_authority = 'trusted-tool-results'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_binding_identity_check CHECK (
|
||||
length(start_id) BETWEEN 1 AND 128 AND
|
||||
length(artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(key_id) BETWEEN 1 AND 128 AND
|
||||
key_id NOT GLOB '*[^A-Za-z0-9._-]*' AND
|
||||
substr(key_id, 1, 1) GLOB '[A-Za-z0-9]' AND
|
||||
catalog_generation BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_binding_digest_check CHECK (
|
||||
length(artifact_digest) = 64 AND
|
||||
artifact_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(catalog_digest) = 64 AND
|
||||
catalog_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(material_proof) = 64 AND
|
||||
material_proof NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(binding_digest) = 64 AND
|
||||
binding_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_result_key_binding_catalog_idx ON "ToolExecutionResultKeyBindings" (catalog_generation, key_id, start_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V32 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1}';
|
||||
const CAPABILITIES_V33 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1}';
|
||||
|
||||
export const local0066CapabilityV33Migration = defineLocalSqliteMigration({
|
||||
id: '0066-capability-v33',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 33,
|
||||
migration_id = '0065-tool-result-key-catalog',
|
||||
capabilities = '${CAPABILITIES_V33}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 32
|
||||
AND migration_id = '0063-tool-execution-failure-completions'
|
||||
AND capabilities = '${CAPABILITIES_V32}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,238 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0067ToolResultRekeyOverlaysMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0067-tool-result-rekey-overlays',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "ToolExecutionResultRekeyOverlays" (
|
||||
overlay_id TEXT PRIMARY KEY NOT NULL,
|
||||
artifact_id TEXT NOT NULL,
|
||||
source_binding_digest TEXT NOT NULL,
|
||||
revision INTEGER NOT NULL,
|
||||
previous_overlay_digest TEXT,
|
||||
from_key_id TEXT NOT NULL,
|
||||
target_catalog_authority TEXT NOT NULL,
|
||||
target_catalog_generation INTEGER NOT NULL,
|
||||
target_catalog_digest TEXT NOT NULL,
|
||||
target_key_id TEXT NOT NULL,
|
||||
target_material_proof TEXT NOT NULL,
|
||||
mutation_id TEXT NOT NULL UNIQUE,
|
||||
command_digest TEXT NOT NULL,
|
||||
overlay_digest TEXT NOT NULL UNIQUE,
|
||||
rekeyed_at_ms INTEGER NOT NULL,
|
||||
overlay_json TEXT NOT NULL,
|
||||
UNIQUE (artifact_id, revision),
|
||||
UNIQUE (artifact_id, revision, overlay_digest),
|
||||
CONSTRAINT ql3_tool_result_rekey_artifact_fk
|
||||
FOREIGN KEY (artifact_id)
|
||||
REFERENCES "ToolExecutionResultKeyBindings" (artifact_id)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_rekey_binding_fk
|
||||
FOREIGN KEY (source_binding_digest)
|
||||
REFERENCES "ToolExecutionResultKeyBindings" (binding_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_rekey_previous_fk
|
||||
FOREIGN KEY (previous_overlay_digest)
|
||||
REFERENCES "ToolExecutionResultRekeyOverlays" (overlay_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_rekey_catalog_fk
|
||||
FOREIGN KEY (
|
||||
target_catalog_authority,
|
||||
target_catalog_generation,
|
||||
target_catalog_digest
|
||||
)
|
||||
REFERENCES "ToolResultKeyCatalogGenerations" (
|
||||
authority, generation, catalog_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_rekey_revision_check CHECK (
|
||||
revision BETWEEN 1 AND 2147483647 AND
|
||||
(
|
||||
(revision = 1 AND previous_overlay_digest IS NULL) OR
|
||||
(revision > 1 AND previous_overlay_digest IS NOT NULL)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_rekey_authority_check CHECK (
|
||||
target_catalog_authority = 'trusted-tool-results'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_rekey_identity_check CHECK (
|
||||
length(overlay_id) BETWEEN 1 AND 128 AND
|
||||
length(artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(from_key_id) BETWEEN 1 AND 128 AND
|
||||
from_key_id NOT GLOB '*[^A-Za-z0-9._-]*' AND
|
||||
substr(from_key_id, 1, 1) GLOB '[A-Za-z0-9]' AND
|
||||
length(target_key_id) BETWEEN 1 AND 128 AND
|
||||
target_key_id NOT GLOB '*[^A-Za-z0-9._-]*' AND
|
||||
substr(target_key_id, 1, 1) GLOB '[A-Za-z0-9]' AND
|
||||
from_key_id <> target_key_id AND
|
||||
target_catalog_generation BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_rekey_digest_check CHECK (
|
||||
(
|
||||
previous_overlay_digest IS NULL OR
|
||||
length(previous_overlay_digest) = 64 AND
|
||||
previous_overlay_digest NOT GLOB '*[^0-9a-f]*'
|
||||
) AND
|
||||
length(source_binding_digest) = 64 AND
|
||||
source_binding_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(target_catalog_digest) = 64 AND
|
||||
target_catalog_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(target_material_proof) = 64 AND
|
||||
target_material_proof NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(command_digest) = 64 AND
|
||||
command_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(overlay_digest) = 64 AND
|
||||
overlay_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_rekey_budget_check CHECK (
|
||||
rekeyed_at_ms >= 0 AND
|
||||
length(CAST(overlay_json AS BLOB)) BETWEEN 2 AND 393216
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_rekey_json_check CHECK (
|
||||
json_valid(overlay_json) AND
|
||||
json_type(overlay_json) = 'object' AND
|
||||
json_extract(overlay_json, '$.schema') =
|
||||
'qinglong/tool-execution-result-rekey-overlay@v1' AND
|
||||
json_extract(overlay_json, '$.overlayId') = overlay_id AND
|
||||
json_extract(overlay_json, '$.sourceArtifact.artifactId') =
|
||||
artifact_id AND
|
||||
json_extract(overlay_json, '$.sourceBindingDigest') =
|
||||
source_binding_digest AND
|
||||
json_extract(overlay_json, '$.revision') = revision AND
|
||||
(
|
||||
(
|
||||
previous_overlay_digest IS NULL AND
|
||||
json_type(overlay_json, '$.previousOverlayDigest') = 'null'
|
||||
) OR
|
||||
json_extract(overlay_json, '$.previousOverlayDigest') =
|
||||
previous_overlay_digest
|
||||
) AND
|
||||
json_extract(overlay_json, '$.fromKeyId') = from_key_id AND
|
||||
json_extract(overlay_json, '$.targetCatalogFence.generation') =
|
||||
target_catalog_generation AND
|
||||
json_extract(overlay_json, '$.targetCatalogFence.catalogDigest') =
|
||||
target_catalog_digest AND
|
||||
json_extract(overlay_json, '$.targetCatalogFence.keyId') =
|
||||
target_key_id AND
|
||||
json_extract(overlay_json, '$.targetCatalogFence.materialProof') =
|
||||
target_material_proof AND
|
||||
json_extract(overlay_json, '$.rekeyedAtMs') = rekeyed_at_ms AND
|
||||
json_extract(overlay_json, '$.overlayDigest') = overlay_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_result_rekey_artifact_idx ON "ToolExecutionResultRekeyOverlays" (artifact_id, revision DESC)`,
|
||||
`CREATE INDEX ql3_tool_result_rekey_target_idx ON "ToolExecutionResultRekeyOverlays" (target_key_id, artifact_id, revision DESC)`,
|
||||
`
|
||||
CREATE TABLE "ToolExecutionResultRekeyHeads" (
|
||||
artifact_id TEXT PRIMARY KEY NOT NULL,
|
||||
revision INTEGER NOT NULL,
|
||||
overlay_id TEXT NOT NULL UNIQUE,
|
||||
overlay_digest TEXT NOT NULL UNIQUE,
|
||||
target_catalog_generation INTEGER NOT NULL,
|
||||
target_catalog_digest TEXT NOT NULL,
|
||||
target_key_id TEXT NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
CONSTRAINT ql3_tool_result_rekey_head_overlay_fk
|
||||
FOREIGN KEY (artifact_id, revision, overlay_digest)
|
||||
REFERENCES "ToolExecutionResultRekeyOverlays" (
|
||||
artifact_id, revision, overlay_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_rekey_head_identity_check CHECK (
|
||||
revision BETWEEN 1 AND 2147483647 AND
|
||||
length(artifact_id) BETWEEN 1 AND 128 AND
|
||||
length(overlay_id) BETWEEN 1 AND 128 AND
|
||||
length(target_key_id) BETWEEN 1 AND 128 AND
|
||||
target_key_id NOT GLOB '*[^A-Za-z0-9._-]*' AND
|
||||
substr(target_key_id, 1, 1) GLOB '[A-Za-z0-9]' AND
|
||||
target_catalog_generation BETWEEN 1 AND 2147483647 AND
|
||||
updated_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_rekey_head_digest_check CHECK (
|
||||
length(overlay_digest) = 64 AND
|
||||
overlay_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(target_catalog_digest) = 64 AND
|
||||
target_catalog_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_result_rekey_head_target_idx ON "ToolExecutionResultRekeyHeads" (target_key_id, artifact_id)`,
|
||||
`
|
||||
CREATE TABLE "ToolResultKeyRetirementReceipts" (
|
||||
receipt_digest TEXT PRIMARY KEY NOT NULL,
|
||||
catalog_authority TEXT NOT NULL,
|
||||
catalog_generation INTEGER NOT NULL,
|
||||
catalog_digest TEXT NOT NULL,
|
||||
key_id TEXT NOT NULL,
|
||||
material_proof TEXT NOT NULL,
|
||||
mutation_id TEXT NOT NULL UNIQUE,
|
||||
command_digest TEXT NOT NULL,
|
||||
binding_count INTEGER NOT NULL,
|
||||
overlay_head_count INTEGER NOT NULL,
|
||||
uncovered_binding_count INTEGER NOT NULL,
|
||||
uncovered_overlay_head_count INTEGER NOT NULL,
|
||||
coverage_digest TEXT NOT NULL,
|
||||
created_at_ms INTEGER NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_tool_result_key_retirement_catalog_fk
|
||||
FOREIGN KEY (
|
||||
catalog_authority, catalog_generation, catalog_digest
|
||||
)
|
||||
REFERENCES "ToolResultKeyCatalogGenerations" (
|
||||
authority, generation, catalog_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_tool_result_key_retirement_authority_check CHECK (
|
||||
catalog_authority = 'trusted-tool-results'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_retirement_identity_check CHECK (
|
||||
catalog_generation BETWEEN 1 AND 2147483647 AND
|
||||
length(key_id) BETWEEN 1 AND 128 AND
|
||||
key_id NOT GLOB '*[^A-Za-z0-9._-]*' AND
|
||||
substr(key_id, 1, 1) GLOB '[A-Za-z0-9]' AND
|
||||
length(mutation_id) BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_retirement_count_check CHECK (
|
||||
binding_count BETWEEN 0 AND 2147483647 AND
|
||||
overlay_head_count BETWEEN 0 AND 2147483647 AND
|
||||
uncovered_binding_count = 0 AND
|
||||
uncovered_overlay_head_count = 0 AND
|
||||
created_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_retirement_digest_check CHECK (
|
||||
length(receipt_digest) = 64 AND
|
||||
receipt_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(catalog_digest) = 64 AND
|
||||
catalog_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(material_proof) = 64 AND
|
||||
material_proof NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(command_digest) = 64 AND
|
||||
command_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(coverage_digest) = 64 AND
|
||||
coverage_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_tool_result_key_retirement_json_check CHECK (
|
||||
json_valid(receipt_json) AND
|
||||
json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/tool-result-key-retirement-receipt@v1' AND
|
||||
json_extract(receipt_json, '$.catalogGeneration') =
|
||||
catalog_generation AND
|
||||
json_extract(receipt_json, '$.catalogDigest') = catalog_digest AND
|
||||
json_extract(receipt_json, '$.keyId') = key_id AND
|
||||
json_extract(receipt_json, '$.materialProof') = material_proof AND
|
||||
json_extract(receipt_json, '$.mutationId') = mutation_id AND
|
||||
json_extract(receipt_json, '$.bindingCount') = binding_count AND
|
||||
json_extract(receipt_json, '$.overlayHeadCount') =
|
||||
overlay_head_count AND
|
||||
json_extract(receipt_json, '$.uncoveredBindingCount') = 0 AND
|
||||
json_extract(receipt_json, '$.uncoveredOverlayHeadCount') = 0 AND
|
||||
json_extract(receipt_json, '$.coverageDigest') = coverage_digest AND
|
||||
json_extract(receipt_json, '$.createdAtMs') = created_at_ms AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_tool_result_key_retirement_catalog_idx ON "ToolResultKeyRetirementReceipts" (catalog_generation, key_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V33 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1}';
|
||||
const CAPABILITIES_V34 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1}';
|
||||
|
||||
export const local0068CapabilityV34Migration = defineLocalSqliteMigration({
|
||||
id: '0068-capability-v34',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 34,
|
||||
migration_id = '0067-tool-result-rekey-overlays',
|
||||
capabilities = '${CAPABILITIES_V34}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 33
|
||||
AND migration_id = '0065-tool-result-key-catalog'
|
||||
AND capabilities = '${CAPABILITIES_V33}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,298 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0069PluginPackageQuarantineMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0069-plugin-package-quarantine',
|
||||
statements: [
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_plugin_package_installs_quarantine_target_uidx
|
||||
ON "QingLong3PluginPackageInstalls" (
|
||||
project_id, package_name, installation_id, lock_digest, record_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_project_tool_definition_snapshot_withdrawal_uidx
|
||||
ON "QingLong3ProjectToolDefinitionSnapshots" (
|
||||
project_id, active_vector_digest, snapshot_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageQuarantineEvents" (
|
||||
event_digest TEXT PRIMARY KEY NOT NULL,
|
||||
mutation_id TEXT NOT NULL,
|
||||
revocation_receipt_digest TEXT NOT NULL,
|
||||
impact_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
install_state TEXT NOT NULL,
|
||||
install_version INTEGER NOT NULL,
|
||||
install_record_digest TEXT NOT NULL,
|
||||
active_lock_digest TEXT,
|
||||
proposer_type TEXT NOT NULL,
|
||||
proposer_id TEXT NOT NULL,
|
||||
confirmer_type TEXT NOT NULL,
|
||||
confirmer_id TEXT NOT NULL,
|
||||
authorization_mode TEXT NOT NULL,
|
||||
reason_code TEXT NOT NULL,
|
||||
occurred_at_ms INTEGER NOT NULL,
|
||||
event_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_quarantine_install_fk
|
||||
FOREIGN KEY (
|
||||
project_id, package_name, installation_id, lock_digest,
|
||||
install_record_digest
|
||||
)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (
|
||||
project_id, package_name, installation_id, lock_digest, record_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_quarantine_identity_check CHECK (
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
install_state IN ('queued','staged','activating','active') AND
|
||||
install_version BETWEEN 1 AND 2147483647
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_quarantine_state_check CHECK (
|
||||
(
|
||||
install_state = 'active' AND active_lock_digest = lock_digest
|
||||
) OR (
|
||||
install_state <> 'active' AND
|
||||
(active_lock_digest IS NULL OR active_lock_digest <> lock_digest)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_quarantine_subject_check CHECK (
|
||||
proposer_type IN ('user','api_app','mcp_client','agent','system','worker') AND
|
||||
confirmer_type IN ('user','api_app','mcp_client','agent','system','worker') AND
|
||||
length(proposer_id) BETWEEN 1 AND 255 AND
|
||||
length(confirmer_id) BETWEEN 1 AND 255 AND
|
||||
authorization_mode IN ('dual_control','break_glass') AND
|
||||
(
|
||||
authorization_mode = 'break_glass' OR
|
||||
proposer_type <> confirmer_type OR proposer_id <> confirmer_id
|
||||
) AND
|
||||
reason_code IN (
|
||||
'suspected_key_compromise','confirmed_key_compromise'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_quarantine_digest_check CHECK (
|
||||
length(event_digest) = 64 AND
|
||||
event_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(revocation_receipt_digest) = 64 AND
|
||||
revocation_receipt_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(impact_digest) = 64 AND
|
||||
impact_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(install_record_digest) = 64 AND
|
||||
install_record_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(
|
||||
active_lock_digest IS NULL OR
|
||||
length(active_lock_digest) = 64 AND
|
||||
active_lock_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_quarantine_json_check CHECK (
|
||||
length(CAST(event_json AS BLOB)) BETWEEN 2 AND 262144 AND
|
||||
json_valid(event_json) AND json_type(event_json) = 'object' AND
|
||||
json_extract(event_json, '$.schema') =
|
||||
'qinglong/plugin-package-quarantine-event@v1' AND
|
||||
json_extract(event_json, '$.mutationId') = mutation_id AND
|
||||
json_extract(event_json, '$.revocationReceiptDigest') =
|
||||
revocation_receipt_digest AND
|
||||
json_extract(event_json, '$.impactDigest') = impact_digest AND
|
||||
json_extract(event_json, '$.target.projectId') = project_id AND
|
||||
json_extract(event_json, '$.target.packageName') = package_name AND
|
||||
json_extract(event_json, '$.target.installationId') = installation_id AND
|
||||
json_extract(event_json, '$.target.lockDigest') = lock_digest AND
|
||||
json_extract(event_json, '$.target.installState') = install_state AND
|
||||
json_extract(event_json, '$.target.installVersion') = install_version AND
|
||||
json_extract(event_json, '$.target.installRecordDigest') =
|
||||
install_record_digest AND
|
||||
(
|
||||
(
|
||||
active_lock_digest IS NULL AND
|
||||
json_type(event_json, '$.target.activeLockDigest') = 'null'
|
||||
) OR
|
||||
json_extract(event_json, '$.target.activeLockDigest') =
|
||||
active_lock_digest
|
||||
) AND
|
||||
json_extract(event_json, '$.proposer.type') = proposer_type AND
|
||||
json_extract(event_json, '$.proposer.id') = proposer_id AND
|
||||
json_extract(event_json, '$.confirmer.type') = confirmer_type AND
|
||||
json_extract(event_json, '$.confirmer.id') = confirmer_id AND
|
||||
json_extract(event_json, '$.authorizationMode') = authorization_mode AND
|
||||
json_extract(event_json, '$.reasonCode') = reason_code AND
|
||||
json_extract(event_json, '$.occurredAtMs') = occurred_at_ms AND
|
||||
json_extract(event_json, '$.eventDigest') = event_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_quarantine_time_check CHECK (
|
||||
occurred_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_quarantine_mutation_uidx ON "QingLong3PluginPackageQuarantineEvents" (mutation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_quarantine_target_uidx ON "QingLong3PluginPackageQuarantineEvents" (project_id, package_name, installation_id, lock_digest)`,
|
||||
`CREATE INDEX ql3_plugin_package_quarantine_lock_idx ON "QingLong3PluginPackageQuarantineEvents" (lock_digest, project_id, package_name)`,
|
||||
`CREATE INDEX ql3_plugin_package_quarantine_project_idx ON "QingLong3PluginPackageQuarantineEvents" (project_id, package_name, occurred_at_ms, event_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageWithdrawalReceipts" (
|
||||
event_digest TEXT PRIMARY KEY NOT NULL,
|
||||
receipt_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
capability_status TEXT NOT NULL,
|
||||
task_count INTEGER NOT NULL,
|
||||
previous_active_vector_digest TEXT,
|
||||
current_active_vector_digest TEXT,
|
||||
current_tool_snapshot_digest TEXT,
|
||||
retained_source_count INTEGER NOT NULL,
|
||||
committed_at_ms INTEGER NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_event_fk
|
||||
FOREIGN KEY (event_digest)
|
||||
REFERENCES "QingLong3PluginPackageQuarantineEvents" (event_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_snapshot_fk
|
||||
FOREIGN KEY (
|
||||
project_id, current_active_vector_digest, current_tool_snapshot_digest
|
||||
)
|
||||
REFERENCES "QingLong3ProjectToolDefinitionSnapshots" (
|
||||
project_id, active_vector_digest, snapshot_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_disposition_check CHECK (
|
||||
(
|
||||
capability_status = 'not_active' AND
|
||||
task_count = 0 AND
|
||||
previous_active_vector_digest IS NULL AND
|
||||
current_active_vector_digest IS NULL AND
|
||||
current_tool_snapshot_digest IS NULL AND
|
||||
retained_source_count = 0
|
||||
) OR (
|
||||
capability_status = 'withdrawn' AND
|
||||
task_count BETWEEN 0 AND 128 AND
|
||||
previous_active_vector_digest IS NOT NULL AND
|
||||
current_active_vector_digest IS NOT NULL AND
|
||||
previous_active_vector_digest <> current_active_vector_digest AND
|
||||
current_tool_snapshot_digest IS NOT NULL AND
|
||||
retained_source_count BETWEEN 0 AND 128
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_digest_check CHECK (
|
||||
length(event_digest) = 64 AND
|
||||
event_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(receipt_digest) = 64 AND
|
||||
receipt_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(
|
||||
previous_active_vector_digest IS NULL OR
|
||||
length(previous_active_vector_digest) = 64 AND
|
||||
previous_active_vector_digest NOT GLOB '*[^0-9a-f]*'
|
||||
) AND
|
||||
(
|
||||
current_active_vector_digest IS NULL OR
|
||||
length(current_active_vector_digest) = 64 AND
|
||||
current_active_vector_digest NOT GLOB '*[^0-9a-f]*'
|
||||
) AND
|
||||
(
|
||||
current_tool_snapshot_digest IS NULL OR
|
||||
length(current_tool_snapshot_digest) = 64 AND
|
||||
current_tool_snapshot_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_json_check CHECK (
|
||||
length(CAST(receipt_json AS BLOB)) BETWEEN 2 AND 8388608 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/plugin-package-withdrawal-receipt@v1' AND
|
||||
json_extract(receipt_json, '$.eventDigest') = event_digest AND
|
||||
json_extract(receipt_json, '$.target.projectId') = project_id AND
|
||||
json_extract(receipt_json, '$.capability.status') = capability_status AND
|
||||
json_array_length(
|
||||
json_extract(receipt_json, '$.capability.taskWithdrawals')
|
||||
) = task_count AND
|
||||
(
|
||||
(
|
||||
previous_active_vector_digest IS NULL AND
|
||||
json_type(
|
||||
receipt_json, '$.capability.previousActiveVectorDigest'
|
||||
) = 'null'
|
||||
) OR
|
||||
json_extract(
|
||||
receipt_json, '$.capability.previousActiveVectorDigest'
|
||||
) = previous_active_vector_digest
|
||||
) AND
|
||||
(
|
||||
(
|
||||
current_active_vector_digest IS NULL AND
|
||||
json_type(
|
||||
receipt_json, '$.capability.currentActiveVectorDigest'
|
||||
) = 'null'
|
||||
) OR
|
||||
json_extract(
|
||||
receipt_json, '$.capability.currentActiveVectorDigest'
|
||||
) = current_active_vector_digest
|
||||
) AND
|
||||
(
|
||||
(
|
||||
current_tool_snapshot_digest IS NULL AND
|
||||
json_type(
|
||||
receipt_json, '$.capability.currentToolSnapshotDigest'
|
||||
) = 'null'
|
||||
) OR
|
||||
json_extract(
|
||||
receipt_json, '$.capability.currentToolSnapshotDigest'
|
||||
) = current_tool_snapshot_digest
|
||||
) AND
|
||||
json_extract(receipt_json, '$.capability.retainedSourceCount') =
|
||||
retained_source_count AND
|
||||
json_extract(receipt_json, '$.committedAtMs') = committed_at_ms AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_time_check CHECK (
|
||||
committed_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_withdrawal_receipt_uidx ON "QingLong3PluginPackageWithdrawalReceipts" (receipt_digest)`,
|
||||
`CREATE INDEX ql3_plugin_package_withdrawal_snapshot_idx ON "QingLong3PluginPackageWithdrawalReceipts" (current_tool_snapshot_digest, event_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageWithdrawalTasks" (
|
||||
event_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
previous_revision INTEGER NOT NULL,
|
||||
disabled_revision INTEGER NOT NULL,
|
||||
previous_content_digest TEXT NOT NULL,
|
||||
disabled_content_digest TEXT NOT NULL,
|
||||
PRIMARY KEY (event_digest, task_id),
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_task_receipt_fk
|
||||
FOREIGN KEY (event_digest)
|
||||
REFERENCES "QingLong3PluginPackageWithdrawalReceipts" (event_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_task_previous_fk
|
||||
FOREIGN KEY (project_id, task_id, previous_revision)
|
||||
REFERENCES "QingLong3TaskDefinitionRevisions" (
|
||||
project_id, task_id, revision
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_task_disabled_fk
|
||||
FOREIGN KEY (project_id, task_id, disabled_revision)
|
||||
REFERENCES "QingLong3TaskDefinitionRevisions" (
|
||||
project_id, task_id, revision
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_task_identity_check CHECK (
|
||||
length(task_id) BETWEEN 1 AND 128 AND
|
||||
previous_revision BETWEEN 1 AND 2147483646 AND
|
||||
disabled_revision = previous_revision + 1
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_withdrawal_task_digest_check CHECK (
|
||||
length(event_digest) = 64 AND
|
||||
event_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(previous_content_digest) = 64 AND
|
||||
previous_content_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(disabled_content_digest) = 64 AND
|
||||
disabled_content_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_plugin_package_withdrawal_task_task_idx ON "QingLong3PluginPackageWithdrawalTasks" (project_id, task_id, event_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V34 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1}';
|
||||
const CAPABILITIES_V35 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
|
||||
export const local0070CapabilityV35Migration = defineLocalSqliteMigration({
|
||||
id: '0070-capability-v35',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 35,
|
||||
migration_id = '0069-plugin-package-quarantine',
|
||||
capabilities = '${CAPABILITIES_V35}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 34
|
||||
AND migration_id = '0067-tool-result-rekey-overlays'
|
||||
AND capabilities = '${CAPABILITIES_V34}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0071LocalIdentityCredentialAdministrationMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0071-local-identity-credential-administration',
|
||||
statements: [
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_local_credential_pepper_binding_triple_uidx"
|
||||
ON "QingLong3ApiCredentialPepperBindings" (
|
||||
"credential_id", "credential_version", "pepper_key_id"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3IdentityAdministrationMutations" (
|
||||
"mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"operation" TEXT NOT NULL,
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"subject_version" INTEGER NOT NULL,
|
||||
"expected_previous_version" INTEGER NOT NULL,
|
||||
"status" TEXT NOT NULL,
|
||||
"changed_by_type" TEXT NOT NULL,
|
||||
"changed_by_id" TEXT NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL UNIQUE,
|
||||
"identity_created_at_ms" INTEGER NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("subject_type", "subject_id")
|
||||
REFERENCES "QingLong3IdentitySubjects" ("subject_type", "subject_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_identity_admin_mutation_id_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
),
|
||||
CONSTRAINT ql3_identity_admin_operation_check CHECK (
|
||||
"operation" IN ('register','enable','disable')
|
||||
),
|
||||
CONSTRAINT ql3_identity_admin_subject_check CHECK (
|
||||
"subject_type" IN ('user','api_app','mcp_client','agent')
|
||||
AND length("subject_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_identity_admin_transition_check CHECK (
|
||||
"subject_version" = "expected_previous_version" + 1
|
||||
AND "subject_version" BETWEEN 1 AND 2147483647
|
||||
AND "expected_previous_version" BETWEEN 0 AND 2147483646
|
||||
AND (
|
||||
("operation" = 'register'
|
||||
AND "expected_previous_version" = 0 AND "status" = 'active')
|
||||
OR ("operation" = 'enable'
|
||||
AND "expected_previous_version" > 0 AND "status" = 'active')
|
||||
OR ("operation" = 'disable'
|
||||
AND "expected_previous_version" > 0 AND "status" = 'disabled')
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_identity_admin_actor_check CHECK (
|
||||
"changed_by_type" = 'user'
|
||||
AND length("changed_by_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_identity_admin_audit_check CHECK (
|
||||
"audit_event_id" = "mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_identity_admin_time_check CHECK (
|
||||
"identity_created_at_ms" >= 0
|
||||
AND "created_at_ms" >= "identity_created_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_identity_admin_subject_idx"
|
||||
ON "QingLong3IdentityAdministrationMutations" (
|
||||
"subject_type", "subject_id", "subject_version" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ApiCredentialAdministrationMutations" (
|
||||
"mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"operation" TEXT NOT NULL,
|
||||
"credential_id" TEXT NOT NULL,
|
||||
"credential_version" INTEGER NOT NULL,
|
||||
"expected_previous_version" INTEGER NOT NULL,
|
||||
"subject_type" TEXT NOT NULL,
|
||||
"subject_id" TEXT NOT NULL,
|
||||
"subject_status" TEXT NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"pepper_key_id" TEXT NOT NULL,
|
||||
"secret_digest" TEXT NOT NULL,
|
||||
"not_before_at_ms" INTEGER NOT NULL,
|
||||
"expires_at_ms" INTEGER NOT NULL,
|
||||
"delivery_digest" TEXT,
|
||||
"changed_by_type" TEXT NOT NULL,
|
||||
"changed_by_id" TEXT NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL UNIQUE,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("credential_id", "credential_version")
|
||||
REFERENCES "QingLong3ApiCredentials" ("credential_id", "version")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("credential_id", "credential_version", "pepper_key_id")
|
||||
REFERENCES "QingLong3ApiCredentialPepperBindings" (
|
||||
"credential_id", "credential_version", "pepper_key_id"
|
||||
) ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_credential_admin_mutation_id_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_operation_check CHECK (
|
||||
"operation" IN ('issue','rotate','revoke')
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_identity_check CHECK (
|
||||
length("credential_id") BETWEEN 1 AND 64
|
||||
AND "credential_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND "subject_type" IN ('user','api_app','mcp_client','agent')
|
||||
AND length("subject_id") BETWEEN 1 AND 255
|
||||
AND "subject_status" IN ('active','disabled')
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_transition_check CHECK (
|
||||
"credential_version" = "expected_previous_version" + 1
|
||||
AND "credential_version" BETWEEN 1 AND 2147483647
|
||||
AND "expected_previous_version" BETWEEN 0 AND 2147483646
|
||||
AND (
|
||||
("operation" = 'issue'
|
||||
AND "expected_previous_version" = 0 AND "state" = 'active')
|
||||
OR ("operation" = 'rotate'
|
||||
AND "expected_previous_version" > 0 AND "state" = 'active')
|
||||
OR ("operation" = 'revoke'
|
||||
AND "expected_previous_version" > 0 AND "state" = 'revoked')
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_digest_check CHECK (
|
||||
length("pepper_key_id") BETWEEN 1 AND 64
|
||||
AND "pepper_key_id" NOT GLOB '*[^A-Za-z0-9._:-]*'
|
||||
AND length("secret_digest") = 64
|
||||
AND "secret_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND (
|
||||
("operation" IN ('issue','rotate')
|
||||
AND length("delivery_digest") = 64
|
||||
AND "delivery_digest" NOT GLOB '*[^0-9a-f]*')
|
||||
OR ("operation" = 'revoke' AND "delivery_digest" IS NULL)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_lifetime_check CHECK (
|
||||
"created_at_ms" >= 0
|
||||
AND "not_before_at_ms" >= "created_at_ms"
|
||||
AND "expires_at_ms" > "not_before_at_ms"
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_actor_check CHECK (
|
||||
"changed_by_type" = 'user'
|
||||
AND length("changed_by_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_credential_admin_audit_check CHECK (
|
||||
"audit_event_id" = "mutation_id"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_credential_admin_credential_idx"
|
||||
ON "QingLong3ApiCredentialAdministrationMutations" (
|
||||
"credential_id", "credential_version" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_credential_admin_subject_idx"
|
||||
ON "QingLong3ApiCredentialAdministrationMutations" (
|
||||
"subject_type", "subject_id", "created_at_ms" DESC
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3ApiCredentialDeliveryAcknowledgements" (
|
||||
"credential_mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"acknowledgement_mutation_id" TEXT NOT NULL UNIQUE,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"delivery_digest" TEXT NOT NULL,
|
||||
"acknowledged_by_type" TEXT NOT NULL,
|
||||
"acknowledged_by_id" TEXT NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL UNIQUE,
|
||||
"acknowledged_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("credential_mutation_id")
|
||||
REFERENCES "QingLong3ApiCredentialAdministrationMutations" ("mutation_id")
|
||||
ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_credential_delivery_ack_identity_check CHECK (
|
||||
length("credential_mutation_id") = 36
|
||||
AND length("acknowledgement_mutation_id") = 36
|
||||
AND "credential_mutation_id" <> "acknowledgement_mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_credential_delivery_ack_digest_check CHECK (
|
||||
length("delivery_digest") = 64
|
||||
AND "delivery_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_credential_delivery_ack_actor_check CHECK (
|
||||
"acknowledged_by_type" = 'user'
|
||||
AND length("acknowledged_by_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_credential_delivery_ack_audit_check CHECK (
|
||||
"audit_event_id" = "acknowledgement_mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_credential_delivery_ack_time_check CHECK (
|
||||
"acknowledged_at_ms" >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_credential_delivery_ack_project_idx"
|
||||
ON "QingLong3ApiCredentialDeliveryAcknowledgements" (
|
||||
"project_id", "acknowledged_at_ms" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V35 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
const CAPABILITIES_V36 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
|
||||
export const local0072CapabilityV36Migration = defineLocalSqliteMigration({
|
||||
id: '0072-capability-v36',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 36,
|
||||
migration_id = '0071-local-identity-credential-administration',
|
||||
capabilities = '${CAPABILITIES_V36}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 35
|
||||
AND migration_id = '0069-plugin-package-quarantine'
|
||||
AND capabilities = '${CAPABILITIES_V35}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0073LocalProjectAdministrationMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0073-local-project-administration',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3ProjectAdministrationMutations" (
|
||||
"mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"operation" TEXT NOT NULL,
|
||||
"authority_project_id" TEXT NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"project_name" TEXT NOT NULL,
|
||||
"project_slug" TEXT NOT NULL,
|
||||
"project_status" TEXT NOT NULL,
|
||||
"project_version" INTEGER NOT NULL,
|
||||
"expected_previous_version" INTEGER NOT NULL,
|
||||
"changed_by_type" TEXT NOT NULL,
|
||||
"changed_by_id" TEXT NOT NULL,
|
||||
"initial_owner_binding_version" INTEGER,
|
||||
"audit_event_id" TEXT NOT NULL UNIQUE,
|
||||
"project_created_at_ms" INTEGER NOT NULL,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("authority_project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_project_admin_mutation_id_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
AND substr("mutation_id", 9, 1) = '-'
|
||||
AND substr("mutation_id", 14, 1) = '-'
|
||||
AND substr("mutation_id", 19, 1) = '-'
|
||||
AND substr("mutation_id", 24, 1) = '-'
|
||||
AND replace("mutation_id", '-', '') NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_project_admin_operation_check CHECK (
|
||||
"operation" IN ('create','archive','restore')
|
||||
),
|
||||
CONSTRAINT ql3_project_admin_identity_check CHECK (
|
||||
length("authority_project_id") BETWEEN 1 AND 128
|
||||
AND length("project_id") BETWEEN 1 AND 128
|
||||
AND length("project_name") BETWEEN 1 AND 255
|
||||
AND length("project_slug") BETWEEN 1 AND 128
|
||||
AND "project_slug" = lower("project_slug")
|
||||
AND "project_slug" NOT GLOB '*[^a-z0-9-]*'
|
||||
AND substr("project_slug", 1, 1) NOT GLOB '[^a-z0-9]'
|
||||
AND substr("project_slug", -1, 1) NOT GLOB '[^a-z0-9]'
|
||||
),
|
||||
CONSTRAINT ql3_project_admin_transition_check CHECK (
|
||||
"project_version" = "expected_previous_version" + 1
|
||||
AND "project_version" BETWEEN 1 AND 2147483647
|
||||
AND "expected_previous_version" BETWEEN 0 AND 2147483646
|
||||
AND (
|
||||
("operation" = 'create'
|
||||
AND "expected_previous_version" = 0
|
||||
AND "project_status" = 'active'
|
||||
AND "initial_owner_binding_version" = 1)
|
||||
OR ("operation" = 'archive'
|
||||
AND "expected_previous_version" > 0
|
||||
AND "project_status" = 'archived'
|
||||
AND "initial_owner_binding_version" IS NULL)
|
||||
OR ("operation" = 'restore'
|
||||
AND "expected_previous_version" > 0
|
||||
AND "project_status" = 'active'
|
||||
AND "initial_owner_binding_version" IS NULL)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_project_admin_actor_check CHECK (
|
||||
"changed_by_type" = 'user'
|
||||
AND length("changed_by_id") BETWEEN 1 AND 255
|
||||
),
|
||||
CONSTRAINT ql3_project_admin_audit_check CHECK (
|
||||
"audit_event_id" = "mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_project_admin_time_check CHECK (
|
||||
"project_created_at_ms" >= 0
|
||||
AND "created_at_ms" >= "project_created_at_ms"
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE UNIQUE INDEX "ql3_project_admin_project_version_uidx"
|
||||
ON "QingLong3ProjectAdministrationMutations" (
|
||||
"project_id", "project_version"
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_project_admin_authority_time_idx"
|
||||
ON "QingLong3ProjectAdministrationMutations" (
|
||||
"authority_project_id", "created_at_ms" DESC, "mutation_id" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V36 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
const CAPABILITIES_V37 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
|
||||
export const local0074CapabilityV37Migration = defineLocalSqliteMigration({
|
||||
id: '0074-capability-v37',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 37,
|
||||
migration_id = '0073-local-project-administration',
|
||||
capabilities = '${CAPABILITIES_V37}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 36
|
||||
AND migration_id = '0071-local-identity-credential-administration'
|
||||
AND capabilities = '${CAPABILITIES_V36}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0075SecurityAuditCompactionsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0075-security-audit-compactions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3SecurityAuditCompactions" (
|
||||
"mutation_id" TEXT PRIMARY KEY NOT NULL,
|
||||
"request_id" TEXT NOT NULL,
|
||||
"authority_project_id" TEXT NOT NULL,
|
||||
"retention_ms" INTEGER NOT NULL,
|
||||
"eligible_before_ms" INTEGER NOT NULL,
|
||||
"batch_limit" INTEGER NOT NULL,
|
||||
"deleted_count" INTEGER NOT NULL,
|
||||
"deleted_payload_bytes" INTEGER NOT NULL,
|
||||
"first_occurred_at_ms" INTEGER,
|
||||
"first_event_id" TEXT,
|
||||
"last_occurred_at_ms" INTEGER,
|
||||
"last_event_id" TEXT,
|
||||
"records_digest" TEXT NOT NULL,
|
||||
"audit_event_id" TEXT NOT NULL UNIQUE,
|
||||
"created_at_ms" INTEGER NOT NULL,
|
||||
FOREIGN KEY ("authority_project_id")
|
||||
REFERENCES "QingLong3Projects" ("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY ("audit_event_id")
|
||||
REFERENCES "QingLong3SecurityAuditEvents" ("event_id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_audit_compaction_mutation_check CHECK (
|
||||
length("mutation_id") = 36
|
||||
AND substr("mutation_id", 9, 1) = '-'
|
||||
AND substr("mutation_id", 14, 1) = '-'
|
||||
AND substr("mutation_id", 19, 1) = '-'
|
||||
AND substr("mutation_id", 24, 1) = '-'
|
||||
AND replace("mutation_id", '-', '') NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_audit_compaction_request_check CHECK (
|
||||
length("request_id") BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_audit_compaction_authority_check CHECK (
|
||||
length("authority_project_id") BETWEEN 1 AND 128
|
||||
),
|
||||
CONSTRAINT ql3_audit_compaction_policy_check CHECK (
|
||||
"retention_ms" BETWEEN 2592000000 AND 315360000000
|
||||
AND "eligible_before_ms" >= 0
|
||||
AND "eligible_before_ms" + "retention_ms" <= "created_at_ms"
|
||||
AND "batch_limit" BETWEEN 1 AND 512
|
||||
),
|
||||
CONSTRAINT ql3_audit_compaction_result_check CHECK (
|
||||
"deleted_count" BETWEEN 0 AND "batch_limit"
|
||||
AND "deleted_payload_bytes" BETWEEN 0 AND 16777216
|
||||
AND length("records_digest") = 64
|
||||
AND "records_digest" NOT GLOB '*[^0-9a-f]*'
|
||||
AND (
|
||||
("deleted_count" = 0
|
||||
AND "deleted_payload_bytes" = 0
|
||||
AND "first_occurred_at_ms" IS NULL
|
||||
AND "first_event_id" IS NULL
|
||||
AND "last_occurred_at_ms" IS NULL
|
||||
AND "last_event_id" IS NULL)
|
||||
OR ("deleted_count" > 0
|
||||
AND "deleted_payload_bytes" > 0
|
||||
AND "first_occurred_at_ms" >= 0
|
||||
AND "last_occurred_at_ms" >= "first_occurred_at_ms"
|
||||
AND length("first_event_id") = 36
|
||||
AND length("last_event_id") = 36)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_audit_compaction_audit_check CHECK (
|
||||
"audit_event_id" = "mutation_id"
|
||||
),
|
||||
CONSTRAINT ql3_audit_compaction_time_check CHECK (
|
||||
"created_at_ms" >= 2592000000
|
||||
)
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE INDEX "ql3_audit_compaction_authority_time_idx"
|
||||
ON "QingLong3SecurityAuditCompactions" (
|
||||
"authority_project_id", "created_at_ms" DESC, "mutation_id" DESC
|
||||
)
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V37 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
const CAPABILITIES_V38 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
|
||||
export const local0076CapabilityV38Migration = defineLocalSqliteMigration({
|
||||
id: '0076-capability-v38',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 38,
|
||||
migration_id = '0075-security-audit-compactions',
|
||||
capabilities = '${CAPABILITIES_V38}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 37
|
||||
AND migration_id = '0073-local-project-administration'
|
||||
AND capabilities = '${CAPABILITIES_V37}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,349 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0077PluginPackageLifecycleMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0077-plugin-package-lifecycle',
|
||||
statements: [
|
||||
`
|
||||
CREATE UNIQUE INDEX ql3_approved_action_dispatch_lifecycle_uidx
|
||||
ON "QingLong3ApprovedActionDispatches" (
|
||||
dispatch_id, project_id, action_type, action_digest, preview_digest
|
||||
)
|
||||
`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageLifecycleEvents" (
|
||||
event_digest TEXT PRIMARY KEY NOT NULL,
|
||||
mutation_id TEXT NOT NULL,
|
||||
dispatch_id TEXT NOT NULL,
|
||||
approved_action_type TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
install_version INTEGER NOT NULL,
|
||||
install_record_digest TEXT NOT NULL,
|
||||
expected_version INTEGER NOT NULL,
|
||||
expected_disposition TEXT NOT NULL,
|
||||
expected_event_digest TEXT,
|
||||
generation_digest TEXT NOT NULL,
|
||||
materialized_revision_digest TEXT NOT NULL,
|
||||
current_tool_snapshot_digest TEXT NOT NULL,
|
||||
reference_graph_digest TEXT NOT NULL,
|
||||
impact_digest TEXT NOT NULL,
|
||||
action_digest TEXT NOT NULL,
|
||||
requested_by_type TEXT NOT NULL,
|
||||
requested_by_id TEXT NOT NULL,
|
||||
approved_by_type TEXT NOT NULL,
|
||||
approved_by_id TEXT NOT NULL,
|
||||
authorization_mode TEXT NOT NULL,
|
||||
occurred_at_ms INTEGER NOT NULL,
|
||||
event_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_install_fk
|
||||
FOREIGN KEY (
|
||||
project_id, package_name, installation_id, lock_digest,
|
||||
install_record_digest
|
||||
)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (
|
||||
project_id, package_name, installation_id, lock_digest, record_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_dispatch_fk
|
||||
FOREIGN KEY (
|
||||
dispatch_id, project_id, approved_action_type, action_digest,
|
||||
impact_digest
|
||||
)
|
||||
REFERENCES "QingLong3ApprovedActionDispatches" (
|
||||
dispatch_id, project_id, action_type, action_digest, preview_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_previous_event_fk
|
||||
FOREIGN KEY (expected_event_digest)
|
||||
REFERENCES "QingLong3PluginPackageLifecycleEvents" (event_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_identity_check CHECK (
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(dispatch_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
install_version BETWEEN 1 AND 2147483647 AND
|
||||
action IN ('disable','enable','uninstall') AND
|
||||
approved_action_type = 'plugin_package.lifecycle.' || action
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_expectation_check CHECK (
|
||||
(
|
||||
action = 'disable' AND expected_disposition = 'active'
|
||||
) OR (
|
||||
action IN ('enable','uninstall') AND
|
||||
expected_disposition = 'disabled'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_origin_check CHECK (
|
||||
(
|
||||
expected_version = 0 AND
|
||||
expected_disposition = 'active' AND
|
||||
expected_event_digest IS NULL
|
||||
) OR (
|
||||
expected_version BETWEEN 1 AND 2147483646 AND
|
||||
expected_event_digest IS NOT NULL
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_subject_check CHECK (
|
||||
requested_by_type = 'user' AND approved_by_type = 'user' AND
|
||||
length(requested_by_id) BETWEEN 1 AND 255 AND
|
||||
length(approved_by_id) BETWEEN 1 AND 255 AND
|
||||
authorization_mode IN ('human_confirmation','separation_of_duty') AND
|
||||
(
|
||||
(
|
||||
authorization_mode = 'human_confirmation' AND
|
||||
requested_by_id = approved_by_id
|
||||
) OR (
|
||||
authorization_mode = 'separation_of_duty' AND
|
||||
requested_by_id <> approved_by_id
|
||||
)
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_digest_check CHECK (
|
||||
length(event_digest) = 64 AND
|
||||
event_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(install_record_digest) = 64 AND
|
||||
install_record_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(materialized_revision_digest) = 64 AND
|
||||
materialized_revision_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(current_tool_snapshot_digest) = 64 AND
|
||||
current_tool_snapshot_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(reference_graph_digest) = 64 AND
|
||||
reference_graph_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(impact_digest) = 64 AND
|
||||
impact_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(action_digest) = 64 AND
|
||||
action_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(
|
||||
expected_event_digest IS NULL OR
|
||||
length(expected_event_digest) = 64 AND
|
||||
expected_event_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_json_check CHECK (
|
||||
length(CAST(event_json AS BLOB)) BETWEEN 2 AND 524288 AND
|
||||
json_valid(event_json) AND json_type(event_json) = 'object' AND
|
||||
json_extract(event_json, '$.schema') =
|
||||
'qinglong/plugin-package-lifecycle-event@v1' AND
|
||||
json_extract(event_json, '$.mutationId') = mutation_id AND
|
||||
json_extract(event_json, '$.dispatchId') = dispatch_id AND
|
||||
json_extract(event_json, '$.impact.schema') =
|
||||
'qinglong/plugin-package-lifecycle-impact@v1' AND
|
||||
json_extract(event_json, '$.impact.action') = action AND
|
||||
json_extract(event_json, '$.impact.target.projectId') = project_id AND
|
||||
json_extract(event_json, '$.impact.target.packageName') = package_name AND
|
||||
json_extract(event_json, '$.impact.target.installationId') =
|
||||
installation_id AND
|
||||
json_extract(event_json, '$.impact.target.lockDigest') = lock_digest AND
|
||||
json_extract(event_json, '$.impact.target.installVersion') =
|
||||
install_version AND
|
||||
json_extract(event_json, '$.impact.target.installRecordDigest') =
|
||||
install_record_digest AND
|
||||
json_extract(event_json, '$.impact.expected.version') = expected_version AND
|
||||
json_extract(event_json, '$.impact.expected.disposition') =
|
||||
expected_disposition AND
|
||||
(
|
||||
(
|
||||
expected_event_digest IS NULL AND
|
||||
json_type(event_json, '$.impact.expected.eventDigest') = 'null'
|
||||
) OR
|
||||
json_extract(event_json, '$.impact.expected.eventDigest') =
|
||||
expected_event_digest
|
||||
) AND
|
||||
json_extract(event_json, '$.impact.generationDigest') =
|
||||
generation_digest AND
|
||||
json_extract(event_json, '$.impact.materializedRevisionDigest') =
|
||||
materialized_revision_digest AND
|
||||
json_extract(event_json, '$.impact.currentToolSnapshotDigest') =
|
||||
current_tool_snapshot_digest AND
|
||||
json_extract(event_json, '$.impact.referenceGraphDigest') =
|
||||
reference_graph_digest AND
|
||||
json_extract(event_json, '$.impact.impactDigest') = impact_digest AND
|
||||
json_extract(event_json, '$.actionDigest') = action_digest AND
|
||||
json_extract(event_json, '$.requestedBy.type') = requested_by_type AND
|
||||
json_extract(event_json, '$.requestedBy.id') = requested_by_id AND
|
||||
json_extract(event_json, '$.approvedBy.type') = approved_by_type AND
|
||||
json_extract(event_json, '$.approvedBy.id') = approved_by_id AND
|
||||
json_extract(event_json, '$.authorizationMode') = authorization_mode AND
|
||||
json_extract(event_json, '$.occurredAtMs') = occurred_at_ms AND
|
||||
json_extract(event_json, '$.eventDigest') = event_digest
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_time_check CHECK (
|
||||
occurred_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_lifecycle_mutation_uidx ON "QingLong3PluginPackageLifecycleEvents" (mutation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_lifecycle_dispatch_uidx ON "QingLong3PluginPackageLifecycleEvents" (dispatch_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_lifecycle_target_version_uidx ON "QingLong3PluginPackageLifecycleEvents" (project_id, package_name, installation_id, lock_digest, expected_version)`,
|
||||
`CREATE INDEX ql3_plugin_package_lifecycle_project_idx ON "QingLong3PluginPackageLifecycleEvents" (project_id, package_name, occurred_at_ms, event_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageLifecycleHeads" (
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
install_record_digest TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
disposition TEXT NOT NULL,
|
||||
event_digest TEXT NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
PRIMARY KEY (project_id, package_name),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_head_install_fk
|
||||
FOREIGN KEY (
|
||||
project_id, package_name, installation_id, lock_digest,
|
||||
install_record_digest
|
||||
)
|
||||
REFERENCES "QingLong3PluginPackageInstalls" (
|
||||
project_id, package_name, installation_id, lock_digest, record_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_head_event_fk
|
||||
FOREIGN KEY (event_digest)
|
||||
REFERENCES "QingLong3PluginPackageLifecycleEvents" (event_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_head_state_check CHECK (
|
||||
version BETWEEN 1 AND 2147483647 AND
|
||||
disposition IN ('active','disabled','uninstalled') AND
|
||||
updated_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_head_digest_check CHECK (
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(install_record_digest) = 64 AND
|
||||
install_record_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(event_digest) = 64 AND
|
||||
event_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_lifecycle_head_event_uidx ON "QingLong3PluginPackageLifecycleHeads" (event_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageLifecycleReceipts" (
|
||||
event_digest TEXT PRIMARY KEY NOT NULL,
|
||||
receipt_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
capability_status TEXT NOT NULL,
|
||||
task_count INTEGER NOT NULL,
|
||||
previous_active_vector_digest TEXT NOT NULL,
|
||||
current_active_vector_digest TEXT NOT NULL,
|
||||
current_tool_snapshot_digest TEXT NOT NULL,
|
||||
retained_source_count INTEGER NOT NULL,
|
||||
committed_at_ms INTEGER NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_receipt_event_fk
|
||||
FOREIGN KEY (event_digest)
|
||||
REFERENCES "QingLong3PluginPackageLifecycleEvents" (event_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_receipt_snapshot_fk
|
||||
FOREIGN KEY (
|
||||
project_id, current_active_vector_digest, current_tool_snapshot_digest
|
||||
)
|
||||
REFERENCES "QingLong3ProjectToolDefinitionSnapshots" (
|
||||
project_id, active_vector_digest, snapshot_digest
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_receipt_state_check CHECK (
|
||||
(
|
||||
action = 'disable' AND capability_status = 'withdrawn' AND
|
||||
previous_active_vector_digest <> current_active_vector_digest
|
||||
) OR (
|
||||
action = 'enable' AND capability_status = 'restored' AND
|
||||
previous_active_vector_digest <> current_active_vector_digest
|
||||
) OR (
|
||||
action = 'uninstall' AND capability_status = 'retired' AND
|
||||
task_count = 0 AND
|
||||
previous_active_vector_digest = current_active_vector_digest
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_receipt_bounds_check CHECK (
|
||||
task_count BETWEEN 0 AND 128 AND
|
||||
retained_source_count BETWEEN 0 AND 128 AND
|
||||
committed_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_receipt_digest_check CHECK (
|
||||
length(receipt_digest) = 64 AND
|
||||
receipt_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(previous_active_vector_digest) = 64 AND
|
||||
previous_active_vector_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(current_active_vector_digest) = 64 AND
|
||||
current_active_vector_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(current_tool_snapshot_digest) = 64 AND
|
||||
current_tool_snapshot_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_receipt_json_check CHECK (
|
||||
length(CAST(receipt_json AS BLOB)) BETWEEN 2 AND 524288 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/plugin-package-lifecycle-receipt@v1' AND
|
||||
json_extract(receipt_json, '$.eventDigest') = event_digest AND
|
||||
json_extract(receipt_json, '$.action') = action AND
|
||||
json_extract(receipt_json, '$.target.projectId') = project_id AND
|
||||
json_extract(receipt_json, '$.capability.status') = capability_status AND
|
||||
json_array_length(
|
||||
json_extract(receipt_json, '$.capability.taskTransitions')
|
||||
) = task_count AND
|
||||
json_extract(
|
||||
receipt_json, '$.capability.previousActiveVectorDigest'
|
||||
) = previous_active_vector_digest AND
|
||||
json_extract(
|
||||
receipt_json, '$.capability.currentActiveVectorDigest'
|
||||
) = current_active_vector_digest AND
|
||||
json_extract(receipt_json, '$.capability.currentToolSnapshotDigest') =
|
||||
current_tool_snapshot_digest AND
|
||||
json_extract(receipt_json, '$.capability.retainedSourceCount') =
|
||||
retained_source_count AND
|
||||
json_extract(receipt_json, '$.committedAtMs') = committed_at_ms AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_lifecycle_receipt_uidx ON "QingLong3PluginPackageLifecycleReceipts" (receipt_digest)`,
|
||||
`CREATE INDEX ql3_plugin_package_lifecycle_receipt_snapshot_idx ON "QingLong3PluginPackageLifecycleReceipts" (project_id, current_active_vector_digest, event_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageLifecycleTasks" (
|
||||
event_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
previous_revision INTEGER NOT NULL,
|
||||
current_revision INTEGER NOT NULL,
|
||||
previous_content_digest TEXT NOT NULL,
|
||||
current_content_digest TEXT NOT NULL,
|
||||
previous_enabled INTEGER NOT NULL,
|
||||
current_enabled INTEGER NOT NULL,
|
||||
PRIMARY KEY (event_digest, task_id),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_task_receipt_fk
|
||||
FOREIGN KEY (event_digest)
|
||||
REFERENCES "QingLong3PluginPackageLifecycleReceipts" (event_digest)
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_task_previous_fk
|
||||
FOREIGN KEY (project_id, task_id, previous_revision)
|
||||
REFERENCES "QingLong3TaskDefinitionRevisions" (
|
||||
project_id, task_id, revision
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_task_current_fk
|
||||
FOREIGN KEY (project_id, task_id, current_revision)
|
||||
REFERENCES "QingLong3TaskDefinitionRevisions" (
|
||||
project_id, task_id, revision
|
||||
) ON DELETE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_task_transition_check CHECK (
|
||||
current_revision = previous_revision + 1 AND
|
||||
previous_enabled IN (0, 1) AND current_enabled IN (0, 1) AND
|
||||
previous_enabled <> current_enabled
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_lifecycle_task_digest_check CHECK (
|
||||
length(previous_content_digest) = 64 AND
|
||||
previous_content_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(current_content_digest) = 64 AND
|
||||
current_content_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE INDEX ql3_plugin_package_lifecycle_task_idx ON "QingLong3PluginPackageLifecycleTasks" (project_id, task_id, event_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V38 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1}';
|
||||
const CAPABILITIES_V39 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1}';
|
||||
|
||||
export const local0078CapabilityV39Migration = defineLocalSqliteMigration({
|
||||
id: '0078-capability-v39',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 39,
|
||||
migration_id = '0077-plugin-package-lifecycle',
|
||||
capabilities = '${CAPABILITIES_V39}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 38
|
||||
AND migration_id = '0075-security-audit-compactions'
|
||||
AND capabilities = '${CAPABILITIES_V38}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0079PluginPackageAutomationPublicationsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0079-plugin-package-automation-publications',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageAutomationPublications" (
|
||||
publication_digest TEXT PRIMARY KEY NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
generation INTEGER NOT NULL,
|
||||
generation_digest TEXT NOT NULL,
|
||||
materialized_revision_digest TEXT NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
previous_publication_digest TEXT,
|
||||
lifecycle_event_digest TEXT,
|
||||
published_at_ms INTEGER NOT NULL,
|
||||
publication_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_revision_fk
|
||||
FOREIGN KEY (generation_digest)
|
||||
REFERENCES "QingLong3PluginPackageMaterializedRevisions" (
|
||||
generation_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_previous_fk
|
||||
FOREIGN KEY (previous_publication_digest)
|
||||
REFERENCES "QingLong3PluginPackageAutomationPublications" (
|
||||
publication_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_lifecycle_fk
|
||||
FOREIGN KEY (lifecycle_event_digest)
|
||||
REFERENCES "QingLong3PluginPackageLifecycleEvents" (event_digest)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_identity_check CHECK (
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
generation BETWEEN 1 AND 2147483647 AND
|
||||
state IN ('active','withdrawn','absent') AND
|
||||
version BETWEEN 1 AND 2147483647 AND
|
||||
published_at_ms >= 0 AND
|
||||
(
|
||||
version = 1 AND state IN ('active','absent') AND
|
||||
previous_publication_digest IS NULL AND
|
||||
lifecycle_event_digest IS NULL
|
||||
OR
|
||||
version > 1 AND previous_publication_digest IS NOT NULL
|
||||
) AND
|
||||
(state <> 'withdrawn' OR lifecycle_event_digest IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_digest_check CHECK (
|
||||
length(publication_digest) = 64 AND
|
||||
publication_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(materialized_revision_digest) = 64 AND
|
||||
materialized_revision_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
(
|
||||
previous_publication_digest IS NULL OR
|
||||
length(previous_publication_digest) = 64 AND
|
||||
previous_publication_digest NOT GLOB '*[^0-9a-f]*'
|
||||
) AND
|
||||
(
|
||||
lifecycle_event_digest IS NULL OR
|
||||
length(lifecycle_event_digest) = 64 AND
|
||||
lifecycle_event_digest NOT GLOB '*[^0-9a-f]*'
|
||||
)
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_json_check CHECK (
|
||||
length(CAST(publication_json AS BLOB)) BETWEEN 2 AND 12582912 AND
|
||||
json_valid(publication_json) AND
|
||||
json_type(publication_json) = 'object' AND
|
||||
json_extract(publication_json, '$.schema') =
|
||||
'qinglong/plugin-package-automation-publication@v1' AND
|
||||
json_extract(publication_json, '$.target.projectId') = project_id AND
|
||||
json_extract(publication_json, '$.target.packageName') = package_name AND
|
||||
json_extract(publication_json, '$.target.installationId') =
|
||||
installation_id AND
|
||||
json_extract(publication_json, '$.target.lockDigest') = lock_digest AND
|
||||
json_extract(publication_json, '$.target.generation') = generation AND
|
||||
json_extract(publication_json, '$.target.generationDigest') =
|
||||
generation_digest AND
|
||||
json_extract(publication_json, '$.target.materializedRevisionDigest') =
|
||||
materialized_revision_digest AND
|
||||
json_extract(publication_json, '$.state') = state AND
|
||||
json_extract(publication_json, '$.version') = version AND
|
||||
(
|
||||
previous_publication_digest IS NULL AND
|
||||
json_type(publication_json, '$.previousPublicationDigest') = 'null'
|
||||
OR
|
||||
json_extract(publication_json, '$.previousPublicationDigest') =
|
||||
previous_publication_digest
|
||||
) AND
|
||||
(
|
||||
lifecycle_event_digest IS NULL AND
|
||||
json_type(publication_json, '$.lifecycleEventDigest') = 'null'
|
||||
OR
|
||||
json_extract(publication_json, '$.lifecycleEventDigest') =
|
||||
lifecycle_event_digest
|
||||
) AND
|
||||
json_extract(publication_json, '$.publishedAtMs') = published_at_ms AND
|
||||
json_extract(publication_json, '$.publicationDigest') =
|
||||
publication_digest AND
|
||||
json_type(publication_json, '$.definitions.workflows') = 'array' AND
|
||||
json_type(publication_json, '$.definitions.prompts') = 'array' AND
|
||||
(
|
||||
state = 'absent' AND
|
||||
json_array_length(
|
||||
json_extract(publication_json, '$.definitions.workflows')
|
||||
) + json_array_length(
|
||||
json_extract(publication_json, '$.definitions.prompts')
|
||||
) = 0
|
||||
OR
|
||||
state <> 'absent' AND
|
||||
json_array_length(
|
||||
json_extract(publication_json, '$.definitions.workflows')
|
||||
) + json_array_length(
|
||||
json_extract(publication_json, '$.definitions.prompts')
|
||||
) > 0
|
||||
)
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_automation_publication_version_uidx ON "QingLong3PluginPackageAutomationPublications" (project_id, package_name, version)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_automation_publication_previous_uidx ON "QingLong3PluginPackageAutomationPublications" (previous_publication_digest) WHERE previous_publication_digest IS NOT NULL`,
|
||||
`CREATE INDEX ql3_plugin_package_automation_publication_generation_idx ON "QingLong3PluginPackageAutomationPublications" (generation_digest, publication_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageAutomationPublicationHeads" (
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
publication_digest TEXT NOT NULL,
|
||||
generation_digest TEXT NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
PRIMARY KEY (project_id, package_name),
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_head_publication_fk
|
||||
FOREIGN KEY (publication_digest)
|
||||
REFERENCES "QingLong3PluginPackageAutomationPublications" (
|
||||
publication_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_automation_publication_head_state_check CHECK (
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
length(publication_digest) = 64 AND
|
||||
publication_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
state IN ('active','withdrawn','absent') AND
|
||||
version BETWEEN 1 AND 2147483647 AND
|
||||
updated_at_ms >= 0
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_automation_publication_head_digest_uidx ON "QingLong3PluginPackageAutomationPublicationHeads" (publication_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V39 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1}';
|
||||
const CAPABILITIES_V40 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1,"plugin_package_automation_publication":1}';
|
||||
|
||||
export const local0080CapabilityV40Migration = defineLocalSqliteMigration({
|
||||
id: '0080-capability-v40',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 40,
|
||||
migration_id = '0079-plugin-package-automation-publications',
|
||||
capabilities = '${CAPABILITIES_V40}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 39
|
||||
AND migration_id = '0077-plugin-package-lifecycle'
|
||||
AND capabilities = '${CAPABILITIES_V39}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,174 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0081PluginPackageWorkflowAdmissionsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0081-plugin-package-workflow-admissions',
|
||||
statements: [
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageWorkflowAdmissions" (
|
||||
plan_digest TEXT PRIMARY KEY NOT NULL,
|
||||
plan_id TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
installation_id TEXT NOT NULL,
|
||||
lock_digest TEXT NOT NULL,
|
||||
generation INTEGER NOT NULL,
|
||||
generation_digest TEXT NOT NULL,
|
||||
materialized_revision_digest TEXT NOT NULL,
|
||||
publication_digest TEXT NOT NULL,
|
||||
workflow_id TEXT NOT NULL,
|
||||
workflow_definition_digest TEXT NOT NULL,
|
||||
step_count INTEGER NOT NULL,
|
||||
admitted_at_ms INTEGER NOT NULL,
|
||||
final_run_version INTEGER NOT NULL,
|
||||
final_run_event_sequence INTEGER NOT NULL,
|
||||
receipt_digest TEXT NOT NULL,
|
||||
plan_json TEXT NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_run_fk
|
||||
FOREIGN KEY (run_id) REFERENCES "Runs" (id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_publication_fk
|
||||
FOREIGN KEY (publication_digest)
|
||||
REFERENCES "QingLong3PluginPackageAutomationPublications" (
|
||||
publication_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_identity_check CHECK (
|
||||
length(plan_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(package_name) BETWEEN 1 AND 63 AND
|
||||
length(installation_id) BETWEEN 1 AND 128 AND
|
||||
length(workflow_id) BETWEEN 1 AND 63 AND
|
||||
generation BETWEEN 1 AND 2147483647 AND
|
||||
step_count BETWEEN 1 AND 128 AND
|
||||
admitted_at_ms >= 0 AND
|
||||
final_run_version = step_count + 1 AND
|
||||
final_run_event_sequence = step_count + 1
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_digest_check CHECK (
|
||||
length(plan_digest) = 64 AND
|
||||
plan_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(lock_digest) = 64 AND
|
||||
lock_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(materialized_revision_digest) = 64 AND
|
||||
materialized_revision_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(publication_digest) = 64 AND
|
||||
publication_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(workflow_definition_digest) = 64 AND
|
||||
workflow_definition_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(receipt_digest) = 64 AND
|
||||
receipt_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_plan_json_check CHECK (
|
||||
length(CAST(plan_json AS BLOB)) BETWEEN 2 AND 262144 AND
|
||||
json_valid(plan_json) AND json_type(plan_json) = 'object' AND
|
||||
json_extract(plan_json, '$.schema') =
|
||||
'qinglong/plugin-package-workflow-execution-plan@v1' AND
|
||||
json_extract(plan_json, '$.planId') = plan_id AND
|
||||
json_extract(plan_json, '$.planDigest') = plan_digest AND
|
||||
json_extract(plan_json, '$.runId') = run_id AND
|
||||
json_extract(plan_json, '$.target.projectId') = project_id AND
|
||||
json_extract(plan_json, '$.target.packageName') = package_name AND
|
||||
json_extract(plan_json, '$.target.installationId') = installation_id AND
|
||||
json_extract(plan_json, '$.target.lockDigest') = lock_digest AND
|
||||
json_extract(plan_json, '$.target.generation') = generation AND
|
||||
json_extract(plan_json, '$.target.generationDigest') =
|
||||
generation_digest AND
|
||||
json_extract(plan_json, '$.target.materializedRevisionDigest') =
|
||||
materialized_revision_digest AND
|
||||
json_extract(plan_json, '$.target.publicationDigest') =
|
||||
publication_digest AND
|
||||
json_extract(plan_json, '$.target.workflowId') = workflow_id AND
|
||||
json_extract(plan_json, '$.target.workflowDefinitionDigest') =
|
||||
workflow_definition_digest AND
|
||||
json_extract(plan_json, '$.plannedAtMs') = admitted_at_ms AND
|
||||
json_array_length(json_extract(plan_json, '$.steps')) = step_count
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_receipt_json_check CHECK (
|
||||
length(CAST(receipt_json AS BLOB)) BETWEEN 2 AND 262144 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/plugin-package-workflow-admission-receipt@v1' AND
|
||||
json_extract(receipt_json, '$.planId') = plan_id AND
|
||||
json_extract(receipt_json, '$.planDigest') = plan_digest AND
|
||||
json_extract(receipt_json, '$.runId') = run_id AND
|
||||
json_extract(receipt_json, '$.publicationDigest') =
|
||||
publication_digest AND
|
||||
json_extract(receipt_json, '$.workflowId') = workflow_id AND
|
||||
json_extract(receipt_json, '$.admittedAtMs') = admitted_at_ms AND
|
||||
json_extract(receipt_json, '$.finalRunVersion') =
|
||||
final_run_version AND
|
||||
json_extract(receipt_json, '$.finalRunEventSequence') =
|
||||
final_run_event_sequence AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest AND
|
||||
json_array_length(json_extract(receipt_json, '$.steps')) = step_count
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_plan_uidx ON "QingLong3PluginPackageWorkflowAdmissions" (plan_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_run_uidx ON "QingLong3PluginPackageWorkflowAdmissions" (run_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_receipt_uidx ON "QingLong3PluginPackageWorkflowAdmissions" (receipt_digest)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_plan_run_uidx ON "QingLong3PluginPackageWorkflowAdmissions" (plan_digest, run_id)`,
|
||||
`CREATE INDEX ql3_plugin_package_workflow_admission_target_idx ON "QingLong3PluginPackageWorkflowAdmissions" (project_id, package_name, admitted_at_ms, plan_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageWorkflowAdmissionSteps" (
|
||||
plan_digest TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_key TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
task_definition_ref TEXT NOT NULL,
|
||||
task_definition_digest TEXT NOT NULL,
|
||||
needs_json TEXT NOT NULL,
|
||||
initial_status TEXT NOT NULL,
|
||||
mutation_id TEXT NOT NULL,
|
||||
event_id TEXT NOT NULL,
|
||||
PRIMARY KEY (plan_digest, step_key),
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_admission_fk
|
||||
FOREIGN KEY (plan_digest, run_id)
|
||||
REFERENCES "QingLong3PluginPackageWorkflowAdmissions" (
|
||||
plan_digest, run_id
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_run_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_mutation_fk
|
||||
FOREIGN KEY (mutation_id) REFERENCES "StepRunMutations" (mutation_id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_event_fk
|
||||
FOREIGN KEY (event_id) REFERENCES "RunEvents" (id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_identity_check CHECK (
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_key) BETWEEN 1 AND 63 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(task_id) BETWEEN 1 AND 63 AND
|
||||
length(CAST(task_definition_ref AS BLOB)) BETWEEN 1 AND 512 AND
|
||||
length(mutation_id) BETWEEN 1 AND 128 AND
|
||||
length(event_id) BETWEEN 1 AND 128 AND
|
||||
initial_status IN ('pending','ready')
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_digest_check CHECK (
|
||||
length(plan_digest) = 64 AND
|
||||
plan_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(task_definition_digest) = 64 AND
|
||||
task_definition_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_admission_step_needs_check CHECK (
|
||||
length(CAST(needs_json AS BLOB)) BETWEEN 2 AND 8192 AND
|
||||
json_valid(needs_json) AND json_type(needs_json) = 'array' AND
|
||||
json_array_length(needs_json) BETWEEN 0 AND 127
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_step_run_uidx ON "QingLong3PluginPackageWorkflowAdmissionSteps" (step_run_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_step_mutation_uidx ON "QingLong3PluginPackageWorkflowAdmissionSteps" (mutation_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_admission_step_event_uidx ON "QingLong3PluginPackageWorkflowAdmissionSteps" (event_id)`,
|
||||
`CREATE INDEX ql3_plugin_package_workflow_admission_step_task_idx ON "QingLong3PluginPackageWorkflowAdmissionSteps" (task_id, task_definition_digest, plan_digest)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V40 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1,"plugin_package_automation_publication":1}';
|
||||
const CAPABILITIES_V41 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1,"plugin_package_automation_publication":1,"plugin_package_workflow_admission":1}';
|
||||
|
||||
export const local0082CapabilityV41Migration = defineLocalSqliteMigration({
|
||||
id: '0082-capability-v41',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 41,
|
||||
migration_id = '0081-plugin-package-workflow-admissions',
|
||||
capabilities = '${CAPABILITIES_V41}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 40
|
||||
AND migration_id = '0079-plugin-package-automation-publications'
|
||||
AND capabilities = '${CAPABILITIES_V40}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0083PluginPackageWorkflowTaskAttemptAdmissionsMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0083-plugin-package-workflow-task-attempt-admissions',
|
||||
statements: [
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_task_reconciliation_receipt_uidx ON "QingLong3PluginPackageTaskReconciliations" (generation_digest, receipt_digest)`,
|
||||
`
|
||||
CREATE TABLE "QingLong3PluginPackageWorkflowTaskAttemptAdmissions" (
|
||||
receipt_digest TEXT PRIMARY KEY NOT NULL,
|
||||
attempt_id TEXT NOT NULL,
|
||||
plan_digest TEXT NOT NULL,
|
||||
run_id TEXT NOT NULL,
|
||||
step_run_id TEXT NOT NULL,
|
||||
step_run_version INTEGER NOT NULL,
|
||||
step_run_digest TEXT NOT NULL,
|
||||
generation_digest TEXT NOT NULL,
|
||||
resource_task_id TEXT NOT NULL,
|
||||
task_reconciliation_receipt_digest TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
task_revision TEXT NOT NULL,
|
||||
task_definition_digest TEXT NOT NULL,
|
||||
executor_type TEXT NOT NULL,
|
||||
execution_digest TEXT NOT NULL,
|
||||
attempt_number INTEGER NOT NULL,
|
||||
event_id TEXT NOT NULL,
|
||||
run_version INTEGER NOT NULL,
|
||||
run_event_sequence INTEGER NOT NULL,
|
||||
admitted_at_ms INTEGER NOT NULL,
|
||||
receipt_json TEXT NOT NULL,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_plan_fk
|
||||
FOREIGN KEY (plan_digest, run_id)
|
||||
REFERENCES "QingLong3PluginPackageWorkflowAdmissions" (
|
||||
plan_digest, run_id
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_step_fk
|
||||
FOREIGN KEY (run_id, step_run_id)
|
||||
REFERENCES "StepRuns" (run_id, id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_attempt_fk
|
||||
FOREIGN KEY (attempt_id) REFERENCES "RunAttempts" (id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_event_fk
|
||||
FOREIGN KEY (event_id) REFERENCES "RunEvents" (id)
|
||||
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_reconciliation_fk
|
||||
FOREIGN KEY (
|
||||
generation_digest, task_reconciliation_receipt_digest
|
||||
) REFERENCES "QingLong3PluginPackageTaskReconciliations" (
|
||||
generation_digest, receipt_digest
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_execution_fk
|
||||
FOREIGN KEY (project_id, task_id, task_revision)
|
||||
REFERENCES "QingLong3LocalTaskExecutionRevisions" (
|
||||
project_id, task_id, task_revision
|
||||
) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_identity_check
|
||||
CHECK (
|
||||
length(attempt_id) BETWEEN 1 AND 128 AND
|
||||
length(run_id) BETWEEN 1 AND 128 AND
|
||||
length(step_run_id) BETWEEN 1 AND 128 AND
|
||||
length(resource_task_id) BETWEEN 1 AND 128 AND
|
||||
length(project_id) BETWEEN 1 AND 128 AND
|
||||
length(task_id) BETWEEN 1 AND 128 AND
|
||||
length(task_revision) BETWEEN 1 AND 128 AND
|
||||
length(event_id) BETWEEN 1 AND 128 AND
|
||||
executor_type = 'local_process'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_counter_check
|
||||
CHECK (
|
||||
step_run_version BETWEEN 1 AND 2147483647 AND
|
||||
attempt_number BETWEEN 1 AND 8192 AND
|
||||
run_version BETWEEN 1 AND 2147483647 AND
|
||||
run_event_sequence = run_version AND
|
||||
admitted_at_ms >= 0
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_digest_check
|
||||
CHECK (
|
||||
length(receipt_digest) = 64 AND
|
||||
receipt_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(plan_digest) = 64 AND
|
||||
plan_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(step_run_digest) = 64 AND
|
||||
step_run_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(generation_digest) = 64 AND
|
||||
generation_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(task_reconciliation_receipt_digest) = 64 AND
|
||||
task_reconciliation_receipt_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(task_definition_digest) = 64 AND
|
||||
task_definition_digest NOT GLOB '*[^0-9a-f]*' AND
|
||||
length(execution_digest) = 64 AND
|
||||
execution_digest NOT GLOB '*[^0-9a-f]*'
|
||||
),
|
||||
CONSTRAINT ql3_plugin_package_workflow_task_attempt_admission_json_check
|
||||
CHECK (
|
||||
length(CAST(receipt_json AS BLOB)) BETWEEN 2 AND 16384 AND
|
||||
json_valid(receipt_json) AND json_type(receipt_json) = 'object' AND
|
||||
json_extract(receipt_json, '$.schema') =
|
||||
'qinglong/plugin-package-workflow-task-attempt-admission@v1' AND
|
||||
json_extract(receipt_json, '$.receiptDigest') = receipt_digest AND
|
||||
json_extract(receipt_json, '$.attemptId') = attempt_id AND
|
||||
json_extract(receipt_json, '$.planDigest') = plan_digest AND
|
||||
json_extract(receipt_json, '$.runId') = run_id AND
|
||||
json_extract(receipt_json, '$.stepRunId') = step_run_id AND
|
||||
json_extract(receipt_json, '$.stepRunVersion') = step_run_version AND
|
||||
json_extract(receipt_json, '$.stepRunDigest') = step_run_digest AND
|
||||
json_extract(receipt_json, '$.resourceTaskId') = resource_task_id AND
|
||||
json_extract(
|
||||
receipt_json, '$.taskReconciliationReceiptDigest'
|
||||
) = task_reconciliation_receipt_digest AND
|
||||
json_extract(receipt_json, '$.taskId') = task_id AND
|
||||
json_extract(receipt_json, '$.taskRevision') = task_revision AND
|
||||
json_extract(receipt_json, '$.taskDefinitionDigest') =
|
||||
task_definition_digest AND
|
||||
json_extract(receipt_json, '$.executorType') = executor_type AND
|
||||
json_extract(receipt_json, '$.executionDigest') = execution_digest AND
|
||||
json_extract(receipt_json, '$.attemptNumber') = attempt_number AND
|
||||
json_extract(receipt_json, '$.eventId') = event_id AND
|
||||
json_extract(receipt_json, '$.runVersion') = run_version AND
|
||||
json_extract(receipt_json, '$.runEventSequence') =
|
||||
run_event_sequence AND
|
||||
json_extract(receipt_json, '$.admittedAtMs') = admitted_at_ms
|
||||
)
|
||||
)
|
||||
`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_task_attempt_admission_attempt_uidx ON "QingLong3PluginPackageWorkflowTaskAttemptAdmissions" (attempt_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_task_attempt_admission_event_uidx ON "QingLong3PluginPackageWorkflowTaskAttemptAdmissions" (event_id)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_task_attempt_admission_epoch_uidx ON "QingLong3PluginPackageWorkflowTaskAttemptAdmissions" (run_id, step_run_id, step_run_version)`,
|
||||
`CREATE UNIQUE INDEX ql3_plugin_package_workflow_task_attempt_admission_number_uidx ON "QingLong3PluginPackageWorkflowTaskAttemptAdmissions" (run_id, attempt_number)`,
|
||||
`CREATE INDEX ql3_plugin_package_workflow_task_attempt_admission_candidate_idx ON "QingLong3PluginPackageWorkflowTaskAttemptAdmissions" (run_id, step_run_id, admitted_at_ms)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
const CAPABILITIES_V41 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1,"plugin_package_automation_publication":1,"plugin_package_workflow_admission":1}';
|
||||
export const CAPABILITIES_V42 =
|
||||
'{"run_core":1,"run_retry_policy":1,"completion_receipt_journal":1,"local_dispatch_plan":1,"local_secret_envelope":1,"local_project_policy":1,"local_project_administration":1,"local_security_audit":1,"local_security_audit_compaction":1,"local_secret_authorized_mutation":1,"local_identity":1,"local_api_credential":1,"local_identity_provisioning":1,"local_identity_credential_administration":1,"local_owner_bootstrap":1,"local_owner_delivery_acknowledgement":1,"api_credential_pepper_binding":1,"local_owner_pepper_catalog":1,"local_owner_credential_recovery":1,"local_owner_pepper_reference_inspection":1,"local_owner_pepper_material_gc":1,"local_owner_delivery_acknowledgement_gc":1,"task_definition":1,"local_execution_revision_digest":1,"trigger_definition":1,"legacy_adoption_ledger":1,"local_scheduler_admission":1,"plugin_package_install":1,"approved_action":1,"plugin_package_admission":1,"approved_action_execution":1,"plugin_package_proposal":1,"plugin_package_materialized_revision":1,"plugin_package_task_reconciliation":1,"project_tool_definition_snapshot":1,"step_run":1,"tool_execution_evidence":1,"tool_execution_start_barrier":1,"tool_invocation_artifact":1,"tool_execution_artifact_binding":1,"tool_execution_completion":1,"tool_execution_failure_completion":1,"tool_result_key_catalog":1,"tool_result_rekey":1,"plugin_package_quarantine":1,"plugin_package_lifecycle":1,"plugin_package_automation_publication":1,"plugin_package_workflow_admission":1,"plugin_package_workflow_task_attempt_admission":1}';
|
||||
|
||||
export const local0084CapabilityV42Migration = defineLocalSqliteMigration({
|
||||
id: '0084-capability-v42',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 42,
|
||||
migration_id = '0083-plugin-package-workflow-task-attempt-admissions',
|
||||
capabilities = '${CAPABILITIES_V42}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 41
|
||||
AND migration_id = '0081-plugin-package-workflow-admissions'
|
||||
AND capabilities = '${CAPABILITIES_V41}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const local0085PluginPackageWorkflowRunListIndexMigration =
|
||||
defineLocalSqliteMigration({
|
||||
id: '0085-plugin-package-workflow-run-list-index',
|
||||
statements: [
|
||||
`CREATE INDEX ql3_plugin_package_workflow_admission_workflow_history_idx ON "QingLong3PluginPackageWorkflowAdmissions" (project_id, package_name, workflow_id, admitted_at_ms, run_id)`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { CAPABILITIES_V42 } from './0084-capability-v42';
|
||||
import { defineLocalSqliteMigration } from './sqlMigration';
|
||||
|
||||
export const CAPABILITIES_V43 = CAPABILITIES_V42.replace(
|
||||
'"plugin_package_workflow_admission":1,',
|
||||
'"plugin_package_workflow_admission":1,"plugin_package_workflow_run_list":1,',
|
||||
);
|
||||
|
||||
export const local0086CapabilityV43Migration = defineLocalSqliteMigration({
|
||||
id: '0086-capability-v43',
|
||||
statements: [
|
||||
`
|
||||
UPDATE "QingLong3SchemaCapabilities"
|
||||
SET contract_version = 43,
|
||||
migration_id = '0085-plugin-package-workflow-run-list-index',
|
||||
capabilities = '${CAPABILITIES_V43}',
|
||||
updated_at_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER)
|
||||
WHERE contract_name = 'local-control-core'
|
||||
AND contract_version = 42
|
||||
AND migration_id = '0083-plugin-package-workflow-task-attempt-admissions'
|
||||
AND capabilities = '${CAPABILITIES_V42}'
|
||||
`,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import type { MigrationStreamStep } from '@qinglong/runtime-core/migration-stream';
|
||||
import type { DatabaseSync } from 'node:sqlite';
|
||||
|
||||
export interface LocalSqliteMigrationContext {
|
||||
readonly client: DatabaseSync;
|
||||
}
|
||||
|
||||
export function defineLocalSqliteMigration(options: {
|
||||
readonly id: string;
|
||||
readonly statements: readonly string[];
|
||||
}): MigrationStreamStep<LocalSqliteMigrationContext> {
|
||||
const statements = Object.freeze(
|
||||
options.statements.map((statement) => statement.trim()),
|
||||
);
|
||||
if (
|
||||
statements.length === 0 ||
|
||||
statements.length > 64 ||
|
||||
statements.some(
|
||||
(statement) => statement.length === 0 || statement.length > 64 * 1024,
|
||||
)
|
||||
) {
|
||||
throw new TypeError('Local SQLite migration statements are invalid');
|
||||
}
|
||||
const checksum = createHash('sha256')
|
||||
.update(statements.join('\n-- ql3-statement-boundary --\n'))
|
||||
.digest('hex');
|
||||
return Object.freeze({
|
||||
id: options.id,
|
||||
checksum,
|
||||
async up(context: LocalSqliteMigrationContext) {
|
||||
for (const statement of statements) context.client.exec(statement);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a reviewed migration whose bounded row transformation cannot be
|
||||
* expressed by SQLite alone. `program` is the immutable audit description
|
||||
* covered by the migration checksum and must change with transformation
|
||||
* semantics as well as with schema SQL.
|
||||
*/
|
||||
export function defineLocalSqliteProgrammaticMigration(options: {
|
||||
readonly id: string;
|
||||
readonly program: readonly string[];
|
||||
readonly up: (
|
||||
context: LocalSqliteMigrationContext,
|
||||
) => void | Promise<void>;
|
||||
}): MigrationStreamStep<LocalSqliteMigrationContext> {
|
||||
const program = Object.freeze(
|
||||
options.program.map((instruction) => instruction.trim()),
|
||||
);
|
||||
if (
|
||||
program.length === 0 ||
|
||||
program.length > 64 ||
|
||||
program.some(
|
||||
(instruction) =>
|
||||
instruction.length === 0 || instruction.length > 64 * 1024,
|
||||
) ||
|
||||
typeof options.up !== 'function'
|
||||
) {
|
||||
throw new TypeError('Local SQLite migration program is invalid');
|
||||
}
|
||||
const checksum = createHash('sha256')
|
||||
.update('ql3-local-sqlite-programmatic-migration-v1\0', 'utf8')
|
||||
.update(program.join('\n-- ql3-program-boundary --\n'), 'utf8')
|
||||
.digest('hex');
|
||||
return Object.freeze({
|
||||
id: options.id,
|
||||
checksum,
|
||||
async up(context: LocalSqliteMigrationContext) {
|
||||
await options.up(context);
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user