Extracted admin endpoints from chain_vault.py (2,178 lines) into
wallet_admin.py (768 lines). chain_vault.py is now 1,469 lines.
What moved to wallet_admin.py (29 routes):
- API keys: /api-keys, /api-keys/revoke
- Alerts: /alerts, /alerts/delete
- Webhooks: /webhooks, /webhooks/{id}, /webhooks/{id}/test,
/webhooks/{id}/retry, /webhooks/deliveries
- Audit trail: /audit-trail
- Bulk ops: /bulk/filter, /bulk/delete, /bulk/export, /export
- 2FA: /admin/2fa/{setup,verify-setup,disable,status}
- Config: /config
- Proof of Generation: /proof/{commit,provenance,verify,roots,stats}
What stayed in chain_vault.py (32 routes):
- Chain metadata: /chains, /stats, /healthz, /health-score
- RPC config: /rpc-chains
- Wallet gen: /generate, /generate/batch, /generate/all,
/import, /from-mnemonic, /derive-address, /hd-wallet
- Vault CRUD: /vault, /vault/{id}, /vault/{id}/full, DELETE
- Wallet ops: /tree, /cluster, /rotate, /rotate-sweep, /rotations,
/distribute, /sweep, /escrow, /escrow/release, /paper-wallet, /tx
- Validation: /validate/{chain}/{address}, /validate/all
- Balances: /balances, /balances/snapshot
- PDF: /paper-wallet/{id}/pdf, /wallet/{id}/birth-certificate
Helpers extracted to _persistent_store.py:
- _PersistentStore class (webhooks/alerts/payments SQLite store)
P3-7 fix: removed dead _webhooks global references in test/retry
endpoints — now uses _PersistentStore.all('webhooks')
Added to wallet_admin.py:
- _require_totp() helper (also kept in chain_vault.py for the
/vault/{id}/full endpoint that needs it)
- WebhookCreateRequest, BulkFilterRequest, BulkDeleteRequest models
(these were inlined in original chain_vault.py body — now in
the request schemas section)
P3-10 — WP plugin supported_chains() rewritten
Plugin used to advertise chains the backend doesn't support
('bitcoin' vs backend 'btc', 'ethereum' vs 'eth', etc.). Rewrote
to use correct backend keys + added a 'backend' field for clarity.
Now matches ADDRESS_GENERATION.md truth table.
main.py: updated import + include_router for wallet_admin.router.
Test results: 80 passed, 5 skipped (no regressions).
Refs: AUDIT.md P2-16, P3-7, P3-10, P3-17
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
"""Alembic migration environment for WalletPress.
|
|
|
|
The app uses raw sqlite3 (not SQLAlchemy). Migrations use raw SQL
|
|
via op.execute(). This keeps the app free of SQLAlchemy overhead
|
|
while still benefiting from Alembic's migration management.
|
|
|
|
The sqlalchemy.url in alembic.ini is the fallback. This env.py
|
|
resolves cfg.db_path at runtime so migrations hit the same DB
|
|
the app uses (respecting WP_DATA_DIR).
|
|
|
|
Usage:
|
|
alembic revision --autogenerate -m "description"
|
|
alembic upgrade head
|
|
alembic downgrade -1
|
|
"""
|
|
|
|
from logging.config import fileConfig
|
|
from pathlib import Path
|
|
|
|
from alembic import context
|
|
from sqlalchemy import create_engine, pool
|
|
|
|
config = context.config
|
|
if config.config_file_name is not None:
|
|
fileConfig(config.config_file_name)
|
|
|
|
# Resolve the actual database path from app config at runtime.
|
|
# Fall back to alembic.ini value if import fails (offline/CI).
|
|
try:
|
|
from core.config import cfg
|
|
db_url = f"sqlite:///{cfg.db_path}"
|
|
except Exception:
|
|
db_url = config.get_main_option("sqlalchemy.url")
|
|
|
|
|
|
def run_migrations_offline() -> None:
|
|
context.configure(url=db_url, literal_binds=True, dialect_opts={"paramstyle": "named"})
|
|
with context.begin_transaction():
|
|
context.run_migrations()
|
|
|
|
|
|
def run_migrations_online() -> None:
|
|
# Ensure the parent directory exists (SQLAlchemy won't create it)
|
|
db_file = db_url.replace("sqlite:///", "")
|
|
Path(db_file).parent.mkdir(parents=True, exist_ok=True)
|
|
connectable = create_engine(db_url, poolclass=pool.NullPool)
|
|
with connectable.connect() as connection:
|
|
context.configure(connection=connection)
|
|
with context.begin_transaction():
|
|
context.run_migrations()
|
|
|
|
|
|
if context.is_offline_mode():
|
|
run_migrations_offline()
|
|
else:
|
|
run_migrations_online()
|