Files
rpa_vision_v3/tests/unit/test_wpc_migration.py
Dom f7f6926410 feat(wp-c): migration colonnes token par poste (patch 1, inerte)
Ajoute token_hash + token_issued_at à enrolled_agents via ALTER TABLE
idempotent (_init_db). Colonnes inertes : aucun branchement auth, runtime
inchangé (tests WP-B verts). Base du token par poste (WP-C, cf DETTE-015).

TDD: tests/unit/test_wpc_migration.py (présence, idempotence, préservation
des données d'une base existante). 3 tests + non-régression WP-B = 9 passed.

refs DETTE-015

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 21:04:18 +02:00

93 lines
3.0 KiB
Python

"""WP-C Patch 1 — migration additive idempotente des colonnes « token par poste ».
Ajoute `token_hash` et `token_issued_at` à la table `enrolled_agents`, sans
casser les bases existantes ni perdre de données. Comportement runtime inchangé :
les colonnes restent inertes tant que l'auth par poste n'est pas branchée
(patchs WP-C ultérieurs). Voir DETTE-015 / PLAN-WPC-TDD-EXECUTABLE.
"""
from __future__ import annotations
import sqlite3
from agent_v0.server_v1.agent_registry import AgentRegistry
def _columns(db_path) -> set[str]:
conn = sqlite3.connect(str(db_path))
try:
rows = conn.execute("PRAGMA table_info(enrolled_agents)").fetchall()
return {r[1] for r in rows}
finally:
conn.close()
def test_token_columns_present_after_init(tmp_path):
"""Une base neuve doit contenir les colonnes token dès l'init."""
db = tmp_path / "fleet.db"
AgentRegistry(db_path=db)
cols = _columns(db)
assert "token_hash" in cols
assert "token_issued_at" in cols
def test_token_columns_idempotent(tmp_path):
"""Ré-initialiser plusieurs fois ne doit jamais lever (migration idempotente)."""
db = tmp_path / "fleet.db"
AgentRegistry(db_path=db)
AgentRegistry(db_path=db)
AgentRegistry(db_path=db)
cols = _columns(db)
assert "token_hash" in cols
assert "token_issued_at" in cols
def test_migration_preserves_existing_rows(tmp_path):
"""Une base ancienne (sans les colonnes) est migrée sans perte de données."""
db = tmp_path / "fleet.db"
# Ancien schéma, sans les colonnes token, avec une ligne existante.
conn = sqlite3.connect(str(db))
conn.execute(
"""
CREATE TABLE enrolled_agents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
machine_id TEXT NOT NULL UNIQUE,
user_name TEXT,
user_email TEXT,
user_id TEXT,
hostname TEXT,
os_info TEXT,
version TEXT,
status TEXT NOT NULL DEFAULT 'active',
enrolled_at TEXT NOT NULL,
last_seen_at TEXT,
uninstalled_at TEXT,
uninstall_reason TEXT
)
"""
)
conn.execute(
"INSERT INTO enrolled_agents (machine_id, status, enrolled_at) "
"VALUES ('PC-LEGACY', 'active', '2026-01-01T00:00:00+00:00')"
)
conn.commit()
conn.close()
# Le démarrage du registry doit migrer la base existante.
AgentRegistry(db_path=db)
cols = _columns(db)
assert "token_hash" in cols
assert "token_issued_at" in cols
conn = sqlite3.connect(str(db))
try:
row = conn.execute(
"SELECT machine_id, token_hash FROM enrolled_agents "
"WHERE machine_id = 'PC-LEGACY'"
).fetchone()
finally:
conn.close()
assert row is not None
assert row[0] == "PC-LEGACY"
assert row[1] is None # colonne ajoutée, NULL par défaut