fix provision: use CURRENT superuser password from .env for auth
The derived POSTGRES_PASSWORD differs from the actual password in postgres (set during initial bootstrap). provision_postgres now accepts superuser_pw parameter; deploy.py reads the CURRENT password from .env to authenticate, then rotates roles to the NEW derived passwords. Also reads all current .env values before deriving so the deploy module has access to the actual running credentials.
This commit is contained in:
@@ -134,21 +134,30 @@ def deploy(
|
|||||||
values = derive_all(root_key, commit_sha)
|
values = derive_all(root_key, commit_sha)
|
||||||
log.info("Derived %d credentials for commit %s", len(values), commit_sha[:8])
|
log.info("Derived %d credentials for commit %s", len(values), commit_sha[:8])
|
||||||
|
|
||||||
# Read current GITEA_TOKEN from .env (the one that's actually valid)
|
# Read current secrets from .env — these are the passwords that
|
||||||
# The derived token is just a placeholder — real tokens come from the API
|
# backends actually have. The derived values are what we WANT them
|
||||||
|
# to be AFTER rotation. We need the current ones to authenticate.
|
||||||
|
current_env: dict[str, str] = {}
|
||||||
if env_path.exists():
|
if env_path.exists():
|
||||||
for line in env_path.read_text().splitlines():
|
for line in env_path.read_text().splitlines():
|
||||||
if line.startswith("GITEA_TOKEN="):
|
line = line.strip()
|
||||||
current_token = line.partition("=")[2].strip()
|
if line and not line.startswith("#") and "=" in line:
|
||||||
if current_token:
|
k, _, v = line.partition("=")
|
||||||
values["GITEA_TOKEN"] = current_token
|
current_env[k.strip()] = v.strip()
|
||||||
log.info("Using current GITEA_TOKEN from .env for rotation")
|
|
||||||
break
|
# Use current GITEA_TOKEN (derived one is just a hash placeholder)
|
||||||
|
if current_env.get("GITEA_TOKEN"):
|
||||||
|
values["GITEA_TOKEN"] = current_env["GITEA_TOKEN"]
|
||||||
|
log.info("Using current GITEA_TOKEN from .env")
|
||||||
|
|
||||||
# ── Phase 1: Rotate backends FIRST ────────────────────────
|
# ── Phase 1: Rotate backends FIRST ────────────────────────
|
||||||
# PostgreSQL
|
# PostgreSQL — authenticate with CURRENT superuser password,
|
||||||
|
# then ALTER ROLE to the NEW derived passwords
|
||||||
|
pg_auth_pw = current_env.get(
|
||||||
|
"POSTGRES_PASSWORD", values.get("POSTGRES_PASSWORD", "")
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
_retry(lambda: provision_postgres(values), "postgres")
|
_retry(lambda: provision_postgres(values, superuser_pw=pg_auth_pw), "postgres")
|
||||||
result.postgres = True
|
result.postgres = True
|
||||||
log.info("Phase 1: PostgreSQL passwords rotated")
|
log.info("Phase 1: PostgreSQL passwords rotated")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -105,13 +105,20 @@ def _retry(fn, label: str, retries: int = MAX_RETRIES):
|
|||||||
# ── PostgreSQL provisioning ─────────────────────────────────────
|
# ── PostgreSQL provisioning ─────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
def provision_postgres(values: dict[str, str], *, container: str = "postgres") -> None:
|
def provision_postgres(
|
||||||
|
values: dict[str, str],
|
||||||
|
*,
|
||||||
|
container: str = "postgres",
|
||||||
|
superuser_pw: str | None = None,
|
||||||
|
) -> None:
|
||||||
"""Rotate passwords for all managed PostgreSQL roles.
|
"""Rotate passwords for all managed PostgreSQL roles.
|
||||||
|
|
||||||
Uses psql -v variable binding so passwords never appear in SQL text.
|
Uses psql -v variable binding so passwords never appear in SQL text.
|
||||||
Authenticates as superuser using POSTGRES_PASSWORD from the values dict.
|
Pass superuser_pw to authenticate with the CURRENT password when
|
||||||
|
rotating to new derived passwords.
|
||||||
"""
|
"""
|
||||||
superuser_pw = values.get("POSTGRES_PASSWORD", "")
|
if superuser_pw is None:
|
||||||
|
superuser_pw = values.get("POSTGRES_PASSWORD", "")
|
||||||
for role, env_var in POSTGRES_ROLES.items():
|
for role, env_var in POSTGRES_ROLES.items():
|
||||||
pw = values[env_var]
|
pw = values[env_var]
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
|
|||||||
Reference in New Issue
Block a user