-- Self-hosted runner daemon: single-use registration tokens, rotating runner credentials and fork policy. CREATE TABLE runner_registration_tokens ( token_hash TEXT PRIMARY KEY, repo_id TEXT REFERENCES repos(id) ON DELETE CASCADE, owner_id TEXT REFERENCES accounts(id) ON DELETE CASCADE, created_by TEXT NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, labels TEXT NOT NULL DEFAULT '[]', expires_at INTEGER NOT NULL, used_at INTEGER, created_at INTEGER NOT NULL, CHECK ((repo_id IS NULL) != (owner_id IS NULL)) ); CREATE INDEX runner_registration_tokens_expiry ON runner_registration_tokens(expires_at); CREATE INDEX runner_registration_tokens_repo ON runner_registration_tokens(repo_id); CREATE INDEX runner_registration_tokens_owner ON runner_registration_tokens(owner_id); ALTER TABLE runners ADD COLUMN os TEXT NOT NULL DEFAULT ''; ALTER TABLE runners ADD COLUMN arch TEXT NOT NULL DEFAULT ''; ALTER TABLE runners ADD COLUMN version TEXT NOT NULL DEFAULT ''; ALTER TABLE runners ADD COLUMN isolation TEXT NOT NULL DEFAULT 'none'; ALTER TABLE runners ADD COLUMN max_jobs INTEGER NOT NULL DEFAULT 1; ALTER TABLE runners ADD COLUMN previous_token_hash TEXT; ALTER TABLE runners ADD COLUMN previous_token_expires_at INTEGER; ALTER TABLE runners ADD COLUMN token_rotated_at INTEGER; -- Rotation is two-phase: the previous credential stays valid until the new one is first used. ALTER TABLE runners ADD COLUMN token_confirmed INTEGER NOT NULL DEFAULT 1; CREATE INDEX runners_previous_token ON runners(previous_token_hash); CREATE INDEX runners_repo ON runners(repo_id); CREATE INDEX runners_owner ON runners(owner_id); CREATE INDEX workflow_jobs_runner ON workflow_jobs(runner_id, status); -- Fork pull request (untrusted) runs never reach self-hosted runners unless a repo admin opts in. CREATE TABLE runner_policies ( repo_id TEXT PRIMARY KEY REFERENCES repos(id) ON DELETE CASCADE, allow_fork_pull_requests INTEGER NOT NULL DEFAULT 0, updated_by TEXT REFERENCES accounts(id) ON DELETE SET NULL, updated_at INTEGER NOT NULL );