core: write job secret env files with the -job unit suffix

A job's systemd unit is castle-<name>-job.service and its EnvironmentFile points
at castle-<name>-job.service.env, but _write_secret_env_file wrote
castle-<name>.service.env (kind defaulted to 'service'). Every secret-using job
failed to start (Failed to load environment files). Thread the deployment kind
through to secret_env_path so the filename matches the unit.
This commit is contained in:
2026-07-16 21:25:47 -07:00
parent afc623ec58
commit 25d7a522cc

View File

@@ -745,15 +745,21 @@ def _env_context(
return ctx return ctx
def _write_secret_env_file(name: str, secret_env: dict[str, str]) -> Path | None: def _write_secret_env_file(
name: str, secret_env: dict[str, str], kind: str = "service"
) -> Path | None:
"""Write a deployment's resolved secrets to a mode-0600 env file. """Write a deployment's resolved secrets to a mode-0600 env file.
Keeps secrets out of the generated unit file and the process argv: systemd Keeps secrets out of the generated unit file and the process argv: systemd
loads it via ``EnvironmentFile=`` and docker via ``--env-file``. Returns the loads it via ``EnvironmentFile=`` and docker via ``--env-file``. Returns the
path, or ``None`` (after removing any stale file) when there are no secrets, path, or ``None`` (after removing any stale file) when there are no secrets,
so a service that drops its last secret doesn't leave a dangling file. so a service that drops its last secret doesn't leave a dangling file.
``kind`` must match the unit's kind so the filename lines up with the unit's
``EnvironmentFile=`` (jobs carry a ``-job`` marker); otherwise systemd looks
for a file that was never written and the unit fails to start.
""" """
path = secret_env_path(name) path = secret_env_path(name, kind)
if not secret_env: if not secret_env:
path.unlink(missing_ok=True) path.unlink(missing_ok=True)
return None return None
@@ -899,7 +905,7 @@ def _build_deployed(
} }
) )
env, secret_env = resolve_env_split(raw_env, ctx) env, secret_env = resolve_env_split(raw_env, ctx)
secret_env_file = _write_secret_env_file(name, secret_env) secret_env_file = _write_secret_env_file(name, secret_env, kind)
# `command` launchers resolve a tool on PATH → ensure it's installed. # `command` launchers resolve a tool on PATH → ensure it's installed.
# `python` launchers run in place via `uv run` (below) — no tool venv. # `python` launchers run in place via `uv run` (below) — no tool venv.