tenseleyflow/shithub / 4bc243b

Browse files

migration 0046: workflow_runners + runner_tokens (S41a)

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
4bc243b22c6510a6a28205d31003ffff6b272ab1
Parents
5955d17
Tree
c22260f

1 changed file

StatusFile+-
A internal/migrationsfs/migrations/0046_workflow_runners.sql 79 0
internal/migrationsfs/migrations/0046_workflow_runners.sqladded
@@ -0,0 +1,79 @@
1
+-- SPDX-License-Identifier: AGPL-3.0-or-later
2
+--
3
+-- S41a workflow runners + per-runner registration tokens.
4
+--
5
+-- workflow_runners — one row per registered runner (operator runs
6
+-- `shithubd admin runner register --name foo --labels self-hosted,linux`).
7
+-- The labels[] array is what `runs-on:` matches against. last_heartbeat_at
8
+-- is updated by the runner's heartbeat endpoint (S41c); rows where
9
+-- last_heartbeat_at is older than `runner.heartbeat_timeout` (config,
10
+-- default 60s) are considered offline.
11
+--
12
+-- runner_tokens — registration tokens minted at admin-register time.
13
+-- The plaintext token is shown to the operator once and never persisted;
14
+-- token_hash is what we store + compare on heartbeat. expires_at NULL
15
+-- means the registration token doesn't expire (long-lived); when set,
16
+-- the token is rejected after that point. revoked_at is the operator's
17
+-- revoke knob (`shithubd admin runner revoke --id N`).
18
+--
19
+-- The per-job JWT (15-min, single-use, scoped to one workflow_jobs.id)
20
+-- is a separate construct minted in-memory and validated against
21
+-- runner_jwt_used (S41c migration); it does NOT live in this table.
22
+
23
+-- +goose Up
24
+
25
+CREATE TYPE workflow_runner_status AS ENUM ('idle', 'busy', 'offline');
26
+
27
+CREATE TABLE workflow_runners (
28
+    id                       bigserial               PRIMARY KEY,
29
+    name                     text                    NOT NULL,
30
+    labels                   text[]                  NOT NULL DEFAULT ARRAY[]::text[],
31
+    capacity                 integer                 NOT NULL DEFAULT 1,
32
+    status                   workflow_runner_status  NOT NULL DEFAULT 'offline',
33
+    last_heartbeat_at        timestamptz,
34
+    registered_by_user_id    bigint                  REFERENCES users(id) ON DELETE SET NULL,
35
+    created_at               timestamptz             NOT NULL DEFAULT now(),
36
+    updated_at               timestamptz             NOT NULL DEFAULT now(),
37
+
38
+    CONSTRAINT workflow_runners_name_length CHECK (char_length(name) BETWEEN 1 AND 100),
39
+    CONSTRAINT workflow_runners_name_format CHECK (name ~ '^[A-Za-z0-9_-]+$'),
40
+    CONSTRAINT workflow_runners_capacity_range CHECK (capacity BETWEEN 1 AND 64)
41
+);
42
+
43
+CREATE UNIQUE INDEX workflow_runners_name_idx ON workflow_runners (name);
44
+CREATE INDEX workflow_runners_status_idx      ON workflow_runners (status);
45
+CREATE INDEX workflow_runners_labels_idx      ON workflow_runners USING GIN (labels);
46
+
47
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON workflow_runners
48
+    FOR EACH ROW EXECUTE FUNCTION tg_set_updated_at();
49
+
50
+
51
+CREATE TABLE runner_tokens (
52
+    id          bigserial   PRIMARY KEY,
53
+    runner_id   bigint      NOT NULL REFERENCES workflow_runners(id) ON DELETE CASCADE,
54
+    token_hash  bytea       NOT NULL,
55
+    expires_at  timestamptz,
56
+    revoked_at  timestamptz,
57
+    created_at  timestamptz NOT NULL DEFAULT now(),
58
+
59
+    CONSTRAINT runner_tokens_token_hash_length CHECK (octet_length(token_hash) = 32)
60
+);
61
+
62
+CREATE UNIQUE INDEX runner_tokens_hash_idx ON runner_tokens (token_hash);
63
+CREATE INDEX runner_tokens_runner_idx     ON runner_tokens (runner_id);
64
+
65
+
66
+-- The forward reference from workflow_jobs.runner_id to workflow_runners.id
67
+-- couldn't be expressed in 0043 because that table didn't exist yet.
68
+-- Add the FK now that both tables are in place.
69
+ALTER TABLE workflow_jobs
70
+    ADD CONSTRAINT workflow_jobs_runner_id_fkey
71
+        FOREIGN KEY (runner_id) REFERENCES workflow_runners(id) ON DELETE SET NULL;
72
+
73
+
74
+-- +goose Down
75
+ALTER TABLE workflow_jobs
76
+    DROP CONSTRAINT IF EXISTS workflow_jobs_runner_id_fkey;
77
+DROP TABLE IF EXISTS runner_tokens;
78
+DROP TABLE IF EXISTS workflow_runners;
79
+DROP TYPE IF EXISTS workflow_runner_status;