brain / scripts /migrate_legacy_credentials.py
Leon4gr45's picture
Deploy complete BrainAPI source d15a5889e878
2f1e7ff verified
Raw History Blame Contribute Delete
2.46 kB
"""Report legacy credential status or atomically replace plaintext with a hash.
No credential plaintext is emitted. Migration retains the existing secret during
the compatibility window; operators must subsequently issue named replacements,
update agents, and revoke the migrated credential, particularly after log exposure.
"""
import argparse
import json
from uuid import uuid4
from src.services.auth import token_digest
from src.services.credentials import token_repository
from src.services.brain_identity import validate_brain_id
from src.services.data.main import data_adapter
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--migrate", metavar="BRAIN_ID", help="Move one legacy PAT to the hash-only registry (PostgreSQL)")
args = parser.parse_args()
if not args.migrate:
for brain in data_adapter.get_brains_list():
print(json.dumps({"brain_id": brain.name_key, "legacy_plaintext_present": bool(brain.pat),
"rotation_required": bool(brain.pat)}))
return
from src.config import config
if config.data_db != "postgresql":
parser.error("Atomic legacy migration requires the PostgreSQL data backend")
brain_id = validate_brain_id(args.migrate)
token_repository.initialize()
# Lock the source and migrate both representations in ONE system transaction.
with token_repository.connection() as conn:
with conn.cursor() as cur:
cur.execute("SELECT id,pat FROM data_brains WHERE name_key=%s FOR UPDATE", (brain_id,))
row = cur.fetchone()
if row is None:
parser.error("Brain not found")
if row[1]:
cur.execute("""INSERT INTO access_tokens
(id,label,brain_id,brain_resource_id,token_prefix,token_hash,permissions,legacy,created_by)
VALUES (%s,%s,%s,%s,%s,%s,%s,TRUE,'legacy-migration')
ON CONFLICT (token_hash) DO NOTHING""",
(str(uuid4()), 'migrated-legacy', brain_id, row[0], 'legacy', token_digest(row[1]),
['memory:read', 'memory:write', 'brain:read']))
cur.execute("UPDATE data_brains SET pat='',document=document-'pat' WHERE name_key=%s", (brain_id,))
conn.commit()
print(json.dumps({"brain_id": brain_id, "status": "hash-only", "rotation_required": True}))
if __name__ == "__main__":
main()