Files
app/backend/scripts/rotate_secret_key.py
stroblmeandClaude Opus 5 60d7ec81c0 Rename the import package app to fluksio
A wheel whose top-level module is `app` collides with anything else in a
user's venv, so the package that is about to be published takes the name
it is published under. Only the Python package moves; the repo, the
Docker WORKDIR and the compose project keep theirs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 21:48:05 +02:00

43 lines
1.3 KiB
Python

"""Re-encrypt the secrets store after SECRET_KEY was rotated.
The store's encryption key is derived from SECRET_KEY, so a new key leaves
``secrets.enc`` unreadable. Put the new key in `.env` first, then hand this
script the previous one:
uv run python scripts/rotate_secret_key.py <old-secret-key>
"""
import logging
import sys
from fluksio.core.config import settings
from fluksio.flow.secrets import SecretsStore, SecretsUnreadable
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def main(old_key: str) -> None:
path = settings.SECRETS_FILE
if not path.exists():
sys.exit(f"No secrets store at {path} — nothing to re-encrypt.")
if old_key == settings.SECRET_KEY:
sys.exit("Old and new key are identical — set the new SECRET_KEY first.")
# The store has no bulk export; reading and writing it whole is the point.
try:
data = SecretsStore(path, old_key)._read()
except SecretsUnreadable:
sys.exit(f"{path} does not decrypt with that key — refusing to overwrite it.")
SecretsStore(path, settings.SECRET_KEY)._write(data)
logger.info(
"Re-encrypted %d secret(s) in %s with the current SECRET_KEY", len(data), path
)
if __name__ == "__main__":
if len(sys.argv) != 2:
sys.exit("usage: rotate_secret_key.py <old-secret-key>")
main(sys.argv[1])