ENGINE: Adjusted Persistent Assets

This commit is contained in:
2025-10-29 19:33:28 -06:00
parent 99e7e914ba
commit e68b52ef5a
12 changed files with 496 additions and 12 deletions

View File

@@ -1432,15 +1432,46 @@ switch ($choice) {
New-Item -Path $engineDataRoot -ItemType Directory -Force | Out-Null New-Item -Path $engineDataRoot -ItemType Directory -Force | Out-Null
} }
if (Test-Path (Join-Path $scriptDir $engineDataDestination)) { $engineDataAbsolute = Join-Path $scriptDir $engineDataDestination
Remove-Item (Join-Path $scriptDir $engineDataDestination) -Recurse -Force -ErrorAction SilentlyContinue
$runtimeAssemblies = Join-Path $scriptDir 'Engine\Assemblies'
$sourceAssemblies = Join-Path $engineSourceAbsolute 'Assemblies'
$runtimeDatabase = Join-Path $scriptDir 'Engine\database.db'
$runtimeAuthTokens = Join-Path $scriptDir 'Engine\Auth_Tokens'
if (Test-Path $engineDataAbsolute) {
Remove-Item $engineDataAbsolute -Recurse -Force -ErrorAction SilentlyContinue
} }
New-Item -Path (Join-Path $scriptDir $engineDataDestination) -ItemType Directory -Force | Out-Null New-Item -Path $engineDataAbsolute -ItemType Directory -Force | Out-Null
if (-not (Test-Path $engineSourceAbsolute)) { if (-not (Test-Path $engineSourceAbsolute)) {
throw "Engine source directory '$engineSourceAbsolute' not found." throw "Engine source directory '$engineSourceAbsolute' not found."
} }
Copy-Item (Join-Path $engineSourceAbsolute '*') (Join-Path $scriptDir $engineDataDestination) -Recurse -Force Get-ChildItem -Path $engineSourceAbsolute -Force | ForEach-Object {
if ($_.Name -ieq 'Assemblies') {
return
}
Copy-Item -Path $_.FullName -Destination $engineDataAbsolute -Recurse -Force
}
if (-not (Test-Path $runtimeAssemblies) -and (Test-Path $sourceAssemblies)) {
Copy-Item -Path $sourceAssemblies -Destination $runtimeAssemblies -Recurse -Force
} elseif (-not (Test-Path $runtimeAssemblies)) {
New-Item -Path $runtimeAssemblies -ItemType Directory -Force | Out-Null
}
if (-not (Test-Path $runtimeAuthTokens)) {
New-Item -Path $runtimeAuthTokens -ItemType Directory -Force | Out-Null
}
if (-not (Test-Path $runtimeDatabase)) {
$runtimeDatabaseDir = Split-Path -Path $runtimeDatabase -Parent
if (-not (Test-Path $runtimeDatabaseDir)) {
New-Item -Path $runtimeDatabaseDir -ItemType Directory -Force | Out-Null
}
}
. (Join-Path $venvFolder 'Scripts\Activate') . (Join-Path $venvFolder 'Scripts\Activate')
} }

View File

@@ -69,6 +69,21 @@ CREATE TABLE IF NOT EXISTS enrollment_install_codes (
use_count INTEGER, use_count INTEGER,
last_used_at TEXT last_used_at TEXT
); );
CREATE TABLE IF NOT EXISTS enrollment_install_codes_persistent (
id TEXT PRIMARY KEY,
code TEXT UNIQUE,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
created_by_user_id TEXT,
used_at TEXT,
used_by_guid TEXT,
max_uses INTEGER NOT NULL DEFAULT 1,
last_known_use_count INTEGER NOT NULL DEFAULT 0,
last_used_at TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
archived_at TEXT,
consumed_at TEXT
);
CREATE TABLE IF NOT EXISTS device_approvals ( CREATE TABLE IF NOT EXISTS device_approvals (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
approval_reference TEXT UNIQUE, approval_reference TEXT UNIQUE,

View File

@@ -18,6 +18,7 @@ from cryptography.hazmat.primitives.asymmetric import ed25519
from flask.testing import FlaskClient from flask.testing import FlaskClient
from Data.Engine.crypto import keys as crypto_keys from Data.Engine.crypto import keys as crypto_keys
from Data.Engine.database import initialise_engine_database
from .conftest import EngineTestHarness from .conftest import EngineTestHarness
@@ -32,7 +33,9 @@ def _iso(dt: datetime) -> str:
def _seed_install_code(db_path: os.PathLike[str], code: str) -> str: def _seed_install_code(db_path: os.PathLike[str], code: str) -> str:
record_id = str(uuid.uuid4()) record_id = str(uuid.uuid4())
expires_at = _iso(_now() + timedelta(days=1)) baseline = _now()
issued_at = _iso(baseline)
expires_at = _iso(baseline + timedelta(days=1))
with sqlite3.connect(str(db_path)) as conn: with sqlite3.connect(str(db_path)) as conn:
conn.execute( conn.execute(
""" """
@@ -42,6 +45,40 @@ def _seed_install_code(db_path: os.PathLike[str], code: str) -> str:
""", """,
(record_id, code, expires_at, None, None, 1, 0, None), (record_id, code, expires_at, None, None, 1, 0, None),
) )
conn.execute(
"""
INSERT INTO enrollment_install_codes_persistent (
id,
code,
created_at,
expires_at,
created_by_user_id,
used_at,
used_by_guid,
max_uses,
last_known_use_count,
last_used_at,
is_active,
archived_at,
consumed_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
record_id,
code,
issued_at,
expires_at,
"test-suite",
None,
None,
1,
0,
None,
1,
None,
None,
),
)
conn.commit() conn.commit()
return record_id return record_id
@@ -193,6 +230,15 @@ def test_enrollment_poll_finalizes_when_approved(engine_harness: EngineTestHarne
(final_guid,), (final_guid,),
) )
key_count = cur.fetchone()[0] key_count = cur.fetchone()[0]
cur.execute(
"""
SELECT is_active, last_known_use_count, used_by_guid, consumed_at
FROM enrollment_install_codes_persistent
WHERE id = ?
""",
(install_code_id,),
)
persistent_row = cur.fetchone()
assert approval_row is not None assert approval_row is not None
approval_guid, approval_status = approval_row approval_guid, approval_status = approval_row
@@ -211,3 +257,75 @@ def test_enrollment_poll_finalizes_when_approved(engine_harness: EngineTestHarne
assert use_count == 1 assert use_count == 1
assert used_by_guid == final_guid assert used_by_guid == final_guid
assert key_count == 1 assert key_count == 1
assert persistent_row is not None
is_active, last_known_use_count, persistent_guid, consumed_at = persistent_row
assert is_active == 0
assert last_known_use_count == 1
assert persistent_guid == final_guid
assert consumed_at is not None
def test_persistent_enrollment_codes_restore_active_table(engine_harness: EngineTestHarness) -> None:
harness = engine_harness
code_id = str(uuid.uuid4())
baseline = _now()
issued_iso = _iso(baseline)
expires_iso = _iso(baseline + timedelta(hours=4))
with sqlite3.connect(str(harness.db_path)) as conn:
conn.execute("DELETE FROM enrollment_install_codes")
conn.execute(
"""
INSERT OR REPLACE INTO enrollment_install_codes_persistent (
id,
code,
created_at,
expires_at,
created_by_user_id,
used_at,
used_by_guid,
max_uses,
last_known_use_count,
last_used_at,
is_active,
archived_at,
consumed_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
code_id,
"RESTORE-CODE-001",
issued_iso,
expires_iso,
"restorer",
None,
None,
3,
0,
None,
1,
None,
None,
),
)
conn.commit()
initialise_engine_database(str(harness.db_path))
with sqlite3.connect(str(harness.db_path)) as conn:
cur = conn.execute(
"""
SELECT code, expires_at, max_uses, use_count
FROM enrollment_install_codes
WHERE id = ?
""",
(code_id,),
)
row = cur.fetchone()
assert row is not None
restored_code, restored_expires, restored_max_uses, restored_use_count = row
assert restored_code == "RESTORE-CODE-001"
assert restored_expires == expires_iso
assert restored_max_uses == 3
assert restored_use_count == 0

View File

@@ -1,6 +1,6 @@
# ====================================================== # ======================================================
# Data\Engine\auth\jwt_service.py # Data\Engine\auth\jwt_service.py
# Description: Engine-native JWT access-token helpers with signing key storage under Engine/Data/Auth_Tokens. # Description: Engine-native JWT access-token helpers with signing key storage under Engine/Auth_Tokens.
# #
# API Endpoints (if applicable): None # API Endpoints (if applicable): None
# ====================================================== # ======================================================
@@ -53,7 +53,7 @@ def _token_root() -> Path:
if env: if env:
env.mkdir(parents=True, exist_ok=True) env.mkdir(parents=True, exist_ok=True)
return env return env
root = _engine_runtime_root() / "Data" / "Auth_Tokens" root = _engine_runtime_root() / "Auth_Tokens"
root.mkdir(parents=True, exist_ok=True) root.mkdir(parents=True, exist_ok=True)
return root return root

View File

@@ -24,7 +24,7 @@ environment variables prefixed with ``BOREALIS_``, and finally built-in
defaults that mirror the legacy server runtime. Key environment variables are defaults that mirror the legacy server runtime. Key environment variables are
``BOREALIS_DATABASE_PATH`` path to the SQLite database file. Defaults to ``BOREALIS_DATABASE_PATH`` path to the SQLite database file. Defaults to
the Engine runtime copy under ``<ProjectRoot>/Engine/Data/Engine/database.db``. ``<ProjectRoot>/Engine/database.db`` so data persists across Engine redeploys.
``BOREALIS_CORS_ORIGINS`` comma separated list of allowed origins for CORS. ``BOREALIS_CORS_ORIGINS`` comma separated list of allowed origins for CORS.
``BOREALIS_SECRET`` Flask session secret key. ``BOREALIS_SECRET`` Flask session secret key.
``BOREALIS_COOKIE_*`` Session cookie policies (``SAMESITE``, ``SECURE``, ``BOREALIS_COOKIE_*`` Session cookie policies (``SAMESITE``, ``SECURE``,
@@ -72,7 +72,7 @@ def _discover_project_root() -> Path:
PROJECT_ROOT = _discover_project_root() PROJECT_ROOT = _discover_project_root()
DEFAULT_DATABASE_PATH = PROJECT_ROOT / "Engine" / "Data" / "Engine" / "database.db" DEFAULT_DATABASE_PATH = PROJECT_ROOT / "Engine" / "database.db"
LOG_ROOT = PROJECT_ROOT / "Engine" / "Logs" LOG_ROOT = PROJECT_ROOT / "Engine" / "Logs"
LOG_FILE_PATH = LOG_ROOT / "engine.log" LOG_FILE_PATH = LOG_ROOT / "engine.log"
ERROR_LOG_FILE_PATH = LOG_ROOT / "error.log" ERROR_LOG_FILE_PATH = LOG_ROOT / "error.log"

View File

@@ -45,6 +45,7 @@ def initialise_engine_database(database_path: str, *, logger: Optional[logging.L
conn = sqlite3.connect(str(path)) conn = sqlite3.connect(str(path))
try: try:
_apply_legacy_migrations(conn, logger=logger) _apply_legacy_migrations(conn, logger=logger)
_restore_persisted_enrollment_codes(conn, logger=logger)
_ensure_activity_history(conn, logger=logger) _ensure_activity_history(conn, logger=logger)
_ensure_device_list_views(conn, logger=logger) _ensure_device_list_views(conn, logger=logger)
_ensure_sites(conn, logger=logger) _ensure_sites(conn, logger=logger)
@@ -79,6 +80,58 @@ def _apply_legacy_migrations(conn: sqlite3.Connection, *, logger: Optional[loggi
raise raise
def _restore_persisted_enrollment_codes(conn: sqlite3.Connection, *, logger: Optional[logging.Logger]) -> None:
cur = conn.cursor()
try:
cur.execute(
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='enrollment_install_codes_persistent'"
)
if cur.fetchone() is None:
return
cur.execute(
"""
INSERT INTO enrollment_install_codes (
id,
code,
expires_at,
created_by_user_id,
used_at,
used_by_guid,
max_uses,
use_count,
last_used_at
)
SELECT
p.id,
p.code,
p.expires_at,
p.created_by_user_id,
p.used_at,
p.used_by_guid,
p.max_uses,
p.last_known_use_count,
p.last_used_at
FROM enrollment_install_codes_persistent AS p
WHERE p.is_active = 1
ON CONFLICT(id) DO UPDATE
SET code = excluded.code,
expires_at = excluded.expires_at,
created_by_user_id = excluded.created_by_user_id,
used_at = excluded.used_at,
used_by_guid = excluded.used_by_guid,
max_uses = excluded.max_uses,
use_count = excluded.use_count,
last_used_at = excluded.last_used_at
"""
)
conn.commit()
except Exception as exc:
if logger:
logger.error("Failed to restore enrollment codes from persistence: %s", exc, exc_info=True)
finally:
cur.close()
def _ensure_activity_history(conn: sqlite3.Connection, *, logger: Optional[logging.Logger]) -> None: def _ensure_activity_history(conn: sqlite3.Connection, *, logger: Optional[logging.Logger]) -> None:
cur = conn.cursor() cur = conn.cursor()
try: try:

View File

@@ -244,7 +244,8 @@ class AdminDeviceService:
cur = conn.cursor() cur = conn.cursor()
created_by = self._lookup_user_id(cur, username) or username or "system" created_by = self._lookup_user_id(cur, username) or username or "system"
code_value = _generate_install_code() code_value = _generate_install_code()
expires_at = _now() + timedelta(hours=ttl_hours) issued_at = _now()
expires_at = issued_at + timedelta(hours=ttl_hours)
record_id = str(uuid.uuid4()) record_id = str(uuid.uuid4())
cur.execute( cur.execute(
""" """
@@ -255,6 +256,40 @@ class AdminDeviceService:
""", """,
(record_id, code_value, _iso(expires_at), created_by, max_uses), (record_id, code_value, _iso(expires_at), created_by, max_uses),
) )
cur.execute(
"""
INSERT INTO enrollment_install_codes_persistent (
id,
code,
created_at,
expires_at,
created_by_user_id,
used_at,
used_by_guid,
max_uses,
last_known_use_count,
last_used_at,
is_active,
archived_at,
consumed_at
)
VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, 0, NULL, 1, NULL, NULL)
ON CONFLICT(id) DO UPDATE
SET code = excluded.code,
created_at = excluded.created_at,
expires_at = excluded.expires_at,
created_by_user_id = excluded.created_by_user_id,
max_uses = excluded.max_uses,
last_known_use_count = 0,
used_at = NULL,
used_by_guid = NULL,
last_used_at = NULL,
is_active = 1,
archived_at = NULL,
consumed_at = NULL
""",
(record_id, code_value, _iso(issued_at), _iso(expires_at), created_by, max_uses),
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()
@@ -284,6 +319,17 @@ class AdminDeviceService:
(code_id,), (code_id,),
) )
deleted = cur.rowcount deleted = cur.rowcount
if deleted:
archive_ts = _iso(_now())
cur.execute(
"""
UPDATE enrollment_install_codes_persistent
SET is_active = 0,
archived_at = COALESCE(archived_at, ?)
WHERE id = ?
""",
(archive_ts, code_id),
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()

View File

@@ -681,6 +681,32 @@ def register(
enrollment_code_id, enrollment_code_id,
), ),
) )
cur.execute(
"""
UPDATE enrollment_install_codes_persistent
SET last_known_use_count = ?,
used_by_guid = ?,
last_used_at = ?,
used_at = CASE WHEN ? THEN ? ELSE used_at END,
is_active = CASE WHEN ? THEN 0 ELSE is_active END,
consumed_at = CASE WHEN ? THEN COALESCE(consumed_at, ?) ELSE consumed_at END,
archived_at = CASE WHEN ? THEN COALESCE(archived_at, ?) ELSE archived_at END
WHERE id = ?
""",
(
new_count,
effective_guid,
now_iso,
1 if consumed else 0,
now_iso,
1 if consumed else 0,
1 if consumed else 0,
now_iso,
1 if consumed else 0,
now_iso,
enrollment_code_id,
),
)
# Update approval record with final state # Update approval record with final state
cur.execute( cur.execute(

View File

@@ -195,7 +195,8 @@ def register(
cur = conn.cursor() cur = conn.cursor()
created_by = _lookup_user_id(cur, username) or username or "system" created_by = _lookup_user_id(cur, username) or username or "system"
code_value = _generate_install_code() code_value = _generate_install_code()
expires_at = _now() + timedelta(hours=ttl_hours) issued_at = _now()
expires_at = issued_at + timedelta(hours=ttl_hours)
record_id = str(uuid.uuid4()) record_id = str(uuid.uuid4())
cur.execute( cur.execute(
""" """
@@ -206,6 +207,40 @@ def register(
""", """,
(record_id, code_value, _iso(expires_at), created_by, max_uses), (record_id, code_value, _iso(expires_at), created_by, max_uses),
) )
cur.execute(
"""
INSERT INTO enrollment_install_codes_persistent (
id,
code,
created_at,
expires_at,
created_by_user_id,
used_at,
used_by_guid,
max_uses,
last_known_use_count,
last_used_at,
is_active,
archived_at,
consumed_at
)
VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, 0, NULL, 1, NULL, NULL)
ON CONFLICT(id) DO UPDATE
SET code = excluded.code,
created_at = excluded.created_at,
expires_at = excluded.expires_at,
created_by_user_id = excluded.created_by_user_id,
max_uses = excluded.max_uses,
last_known_use_count = 0,
used_at = NULL,
used_by_guid = NULL,
last_used_at = NULL,
is_active = 1,
archived_at = NULL,
consumed_at = NULL
""",
(record_id, code_value, _iso(issued_at), _iso(expires_at), created_by, max_uses),
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()
@@ -235,6 +270,17 @@ def register(
(code_id,), (code_id,),
) )
deleted = cur.rowcount deleted = cur.rowcount
if deleted:
archive_ts = _iso(_now())
cur.execute(
"""
UPDATE enrollment_install_codes_persistent
SET is_active = 0,
archived_at = COALESCE(archived_at, ?)
WHERE id = ?
""",
(archive_ts, code_id),
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()

View File

@@ -27,6 +27,7 @@ def apply_all(conn: sqlite3.Connection) -> None:
_ensure_device_aux_tables(conn) _ensure_device_aux_tables(conn)
_ensure_refresh_token_table(conn) _ensure_refresh_token_table(conn)
_ensure_install_code_table(conn) _ensure_install_code_table(conn)
_ensure_install_code_persistence_table(conn)
_ensure_device_approval_table(conn) _ensure_device_approval_table(conn)
conn.commit() conn.commit()
@@ -190,6 +191,92 @@ def _ensure_install_code_table(conn: sqlite3.Connection) -> None:
) )
def _ensure_install_code_persistence_table(conn: sqlite3.Connection) -> None:
cur = conn.cursor()
cur.execute(
"""
CREATE TABLE IF NOT EXISTS enrollment_install_codes_persistent (
id TEXT PRIMARY KEY,
code TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
created_by_user_id TEXT,
used_at TEXT,
used_by_guid TEXT,
max_uses INTEGER NOT NULL DEFAULT 1,
last_known_use_count INTEGER NOT NULL DEFAULT 0,
last_used_at TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
archived_at TEXT,
consumed_at TEXT
)
"""
)
cur.execute(
"""
CREATE INDEX IF NOT EXISTS idx_eicp_active
ON enrollment_install_codes_persistent(is_active, expires_at)
"""
)
cur.execute(
"""
CREATE UNIQUE INDEX IF NOT EXISTS uq_eicp_code
ON enrollment_install_codes_persistent(code)
"""
)
columns = {row[1] for row in _table_info(cur, "enrollment_install_codes_persistent")}
if "last_known_use_count" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN last_known_use_count INTEGER NOT NULL DEFAULT 0
"""
)
if "archived_at" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN archived_at TEXT
"""
)
if "consumed_at" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN consumed_at TEXT
"""
)
if "is_active" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN is_active INTEGER NOT NULL DEFAULT 1
"""
)
if "used_at" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN used_at TEXT
"""
)
if "used_by_guid" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN used_by_guid TEXT
"""
)
if "last_used_at" not in columns:
cur.execute(
"""
ALTER TABLE enrollment_install_codes_persistent
ADD COLUMN last_used_at TEXT
"""
)
def _ensure_device_approval_table(conn: sqlite3.Connection) -> None: def _ensure_device_approval_table(conn: sqlite3.Connection) -> None:
cur = conn.cursor() cur = conn.cursor()
cur.execute( cur.execute(

View File

@@ -671,6 +671,32 @@ def register(
enrollment_code_id, enrollment_code_id,
), ),
) )
cur.execute(
"""
UPDATE enrollment_install_codes_persistent
SET last_known_use_count = ?,
used_by_guid = ?,
last_used_at = ?,
used_at = CASE WHEN ? THEN ? ELSE used_at END,
is_active = CASE WHEN ? THEN 0 ELSE is_active END,
consumed_at = CASE WHEN ? THEN COALESCE(consumed_at, ?) ELSE consumed_at END,
archived_at = CASE WHEN ? THEN COALESCE(archived_at, ?) ELSE archived_at END
WHERE id = ?
""",
(
new_count,
effective_guid,
now_iso,
1 if consumed else 0,
now_iso,
1 if consumed else 0,
1 if consumed else 0,
now_iso,
1 if consumed else 0,
now_iso,
enrollment_code_id,
),
)
# Update approval record with final state # Update approval record with final state
cur.execute( cur.execute(

View File

@@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import Callable, Optional from typing import Callable, List, Optional
import eventlet import eventlet
from flask_socketio import SocketIO from flask_socketio import SocketIO
@@ -31,6 +31,27 @@ def _run_once(db_conn_factory: Callable[[], any], log: Callable[[str, str, Optio
conn = db_conn_factory() conn = db_conn_factory()
try: try:
cur = conn.cursor() cur = conn.cursor()
persistent_table_exists = False
try:
cur.execute(
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='enrollment_install_codes_persistent'"
)
persistent_table_exists = cur.fetchone() is not None
except Exception:
persistent_table_exists = False
expired_ids: List[str] = []
if persistent_table_exists:
cur.execute(
"""
SELECT id
FROM enrollment_install_codes
WHERE use_count = 0
AND expires_at < ?
""",
(now_iso,),
)
expired_ids = [str(row[0]) for row in cur.fetchall() if row and row[0]]
cur.execute( cur.execute(
""" """
DELETE FROM enrollment_install_codes DELETE FROM enrollment_install_codes
@@ -40,6 +61,21 @@ def _run_once(db_conn_factory: Callable[[], any], log: Callable[[str, str, Optio
(now_iso,), (now_iso,),
) )
codes_pruned = cur.rowcount or 0 codes_pruned = cur.rowcount or 0
if expired_ids:
placeholders = ",".join("?" for _ in expired_ids)
try:
cur.execute(
f"""
UPDATE enrollment_install_codes_persistent
SET is_active = 0,
archived_at = COALESCE(archived_at, ?)
WHERE id IN ({placeholders})
""",
(now_iso, *expired_ids),
)
except Exception:
# Best-effort archival; continue if the persistence table is absent.
pass
cur.execute( cur.execute(
""" """