7Runtime migration for auth_events v0.3.1.
11Rebuild ``auth_events`` so unknown-key failures can be recorded with a NULL
12``hmac_key_id`` while successful auth rows still require a credential key.
16- Preserve existing auth event rows.
17- Keep the FK to ``agent_credentials`` for non-NULL key ids.
18- Bump SQLite ``user_version`` to 31.
24 L2 - migration lifecycle
25 L3 - schema version decisions
26 L4 - table definition checks
30- Callers own transaction boundaries.
31- The migration is idempotent.
35- sqlite3 (migration connection)
36- oc_diagnostics (structured debug logging via _dbg)
38from __future__
import annotations
42from oc_diagnostics
import _dbg
44_dbg(
"OC_CHAT.MAIN",
"module",
"loaded", 4)
46AUTH_EVENTS_SCHEMA_VERSION = 31
47AUTH_EVENTS_SCHEMA_DESCRIPTION =
"auth_events REGISTRY_SCHEMA_V0_3_1"
49AUTH_EVENTS_CHECK =
"auth_ok = 0 OR hmac_key_id IS NOT NULL"
53 """Return SQLite's integer schema user version."""
55 return int(conn.execute(
"PRAGMA user_version").fetchone()[0])
58def apply(conn: sqlite3.Connection) ->
None:
59 """Apply the auth_events v0.3.1 rebuild if needed."""
62 conn.execute(f
"PRAGMA user_version = {AUTH_EVENTS_SCHEMA_VERSION}")
65 conn.execute(f
"PRAGMA user_version = {AUTH_EVENTS_SCHEMA_VERSION}")
69 """Reset user_version for tests; table shape remains backward-compatible."""
71 conn.execute(
"PRAGMA user_version = 3")
73 "DELETE FROM schema_migrations WHERE version = ?",
74 (AUTH_EVENTS_SCHEMA_VERSION,),
79 """Return True when the auth_events CHECK is present."""
83 "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'auth_events'"
89 except (TypeError, IndexError):
91 return AUTH_EVENTS_CHECK
in str(sql)
95 """Return SQL used when building a fresh schema in one executescript call."""
97 return _REBUILD_SQL + f
"\nPRAGMA user_version = {AUTH_EVENTS_SCHEMA_VERSION};\n"
101 conn.executescript(_REBUILD_SQL)
106ALTER TABLE auth_events RENAME TO auth_events_old;
108CREATE TABLE auth_events (
109 id INTEGER PRIMARY KEY AUTOINCREMENT,
112 hmac_key_id TEXT REFERENCES agent_credentials(hmac_key_id),
113 command TEXT NOT NULL,
115 auth_ok INTEGER NOT NULL CHECK(auth_ok IN (0,1)),
117 CHECK(failure_reason IN
118 ('bad_signature','expired_ts','unknown_slot','no_credential',
119 'revoked_key','malformed_payload','clock_skew','missing_secrets_file')),
120 remote_hint TEXT CHECK(remote_hint IS NULL OR length(remote_hint) <= 255),
122 (auth_ok = 1 AND failure_reason IS NULL) OR
123 (auth_ok = 0 AND failure_reason IS NOT NULL)
125 CHECK (auth_ok = 0 OR hmac_key_id IS NOT NULL)
128INSERT INTO auth_events(
129 id, ts, attempted_slot, hmac_key_id, command, payload_sha256,
130 auth_ok, failure_reason, remote_hint
133 id, ts, attempted_slot, hmac_key_id, command, payload_sha256,
134 auth_ok, failure_reason, remote_hint
137DROP TABLE auth_events_old;
139CREATE INDEX idx_auth_events_ts ON auth_events(ts);
140CREATE INDEX idx_auth_events_slot ON auth_events(attempted_slot, ts);
141CREATE INDEX idx_auth_events_slot_failure
142 ON auth_events(attempted_slot, failure_reason, ts)
None rollback(sqlite3.Connection conn)
bool is_applied(sqlite3.Connection conn)
int current_user_version(sqlite3.Connection conn)
None apply(sqlite3.Connection conn)
None _rebuild_auth_events(sqlite3.Connection conn)