Files
rar-autopass/app/schema.sql
Claude Agent fbb2695336 feat(creds): livrare creds per-cerere la worker (criptat efemer + sesiuni per-cont)
Plan sect.5: parola RAR vine per-cerere, stocata CRIPTATA in submission pana la
primul login reusit pe cont, apoi stearsa; JWT 30h acopera restul.

- app/crypto.py: Fernet, cheie din AUTOPASS_creds_key (nesetata -> efemera la
  runtime, creds nu supravietuiesc restartului). encrypt/decrypt_creds.
- schema + migrare: submissions.rar_creds_enc (creds criptate).
- ingestie: cripteaza rar_credentials, le lipeste de fiecare submission nou.
  Niciodata in clar in DB.
- worker: AccountSessions (login per-cont cu creds decriptate, cache JWT in
  memorie, sterge creds-urile contului dupa primul login + refresh nomenclator).
  401 creds gresite -> error fara retry; token expirat -> invalidare + requeue;
  fara creds (restart) -> requeue "indisponibile" (ROAAUTO re-trimite).
  claim_one intoarce account_id + creds_enc; recover_orphans filtrabil pe cont.
- requirements: cryptography==46.0.5.

Nota: refresh nomenclator e acum lazy la primul login per-cont (nu la pornire);
seed-ul fallback acopera editorul offline.

10 teste noi (tests/test_creds_delivery.py). 95 pass total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 20:16:16 +00:00

80 lines
3.7 KiB
SQL

-- Schema SQLite (WAL) pentru gateway RAR AUTOPASS.
-- Vezi plan.md sect. 5. NICIUN camp pentru parole RAR.
-- Validarea completa (T3) si criptarea PII (P2) vin ulterior; in schelet
-- payload-ul e stocat ca JSON text (camp payload_json), de inlocuit cu BLOB
-- criptat + purge_after cand se face T7/criptare.
PRAGMA journal_mode = WAL;
PRAGMA foreign_keys = ON;
-- Conturi ROAAUTO (clientii care folosesc gateway-ul).
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
cui TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Cont implicit (id=1): auth API-key (CORE) inca neimplementat, deci ingestiile vin
-- cu account_id NULL. Le atribuim contului default ca FK + UNIQUE(account_id,...) din
-- operations_mapping sa fie valide; cand auth livreaza, account_id real va curge natural.
INSERT OR IGNORE INTO accounts (id, name) VALUES (1, 'default');
-- Chei API per cont (separate de creds RAR). Stocam doar hash-ul.
CREATE TABLE IF NOT EXISTS api_keys (
id INTEGER PRIMARY KEY AUTOINCREMENT,
account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
key_hash TEXT NOT NULL UNIQUE,
active INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
revoked_at TEXT
);
-- Mapare operatie service -> codPrestatie RAR (← mapare_prestatii.DBF, T5).
CREATE TABLE IF NOT EXISTS operations_mapping (
id INTEGER PRIMARY KEY AUTOINCREMENT,
account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
cod_op_service TEXT NOT NULL,
cod_prestatie TEXT NOT NULL,
auto_send INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (account_id, cod_op_service)
);
-- Cache nomenclator RAR {codPrestatie, numePrestatie} (← prestatii_rar.DBF / live).
CREATE TABLE IF NOT EXISTS nomenclator_rar (
cod_prestatie TEXT PRIMARY KEY,
nume_prestatie TEXT NOT NULL,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Coada de prezentari catre RAR. Masina de stari: plan.md sect. 3.
CREATE TABLE IF NOT EXISTS submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
idempotency_key TEXT NOT NULL UNIQUE,
account_id INTEGER REFERENCES accounts(id) ON DELETE SET NULL,
status TEXT NOT NULL DEFAULT 'queued'
CHECK (status IN ('queued','sending','sent','needs_mapping','needs_data','error')),
payload_json TEXT NOT NULL, -- TODO(P2): inlocuit cu BLOB criptat
rar_creds_enc TEXT, -- creds RAR criptate (Fernet), sterse dupa primul login reusit (plan sect.5)
rar_status_code INTEGER,
rar_error TEXT,
id_prezentare INTEGER, -- data.id intors de RAR la succes
retry_count INTEGER NOT NULL DEFAULT 0,
next_attempt_at TEXT, -- backoff: randul nu se ia inainte de acest moment (T2)
sending_since TEXT, -- pentru lease/timeout pe randuri 'sending' orfane (T2)
purge_after TEXT, -- sent + 90z (P2)
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_submissions_status ON submissions(status);
-- Heartbeat worker (un singur rand, id=1). /healthz citeste de aici.
CREATE TABLE IF NOT EXISTS worker_heartbeat (
id INTEGER PRIMARY KEY CHECK (id = 1),
last_beat TEXT,
last_rar_login_ok TEXT,
detail TEXT
);
INSERT OR IGNORE INTO worker_heartbeat (id, last_beat, detail) VALUES (1, NULL, 'never started');