diff --git a/core/src/castle_core/deploy.py b/core/src/castle_core/deploy.py index fdf81e0..2093ff7 100644 --- a/core/src/castle_core/deploy.py +++ b/core/src/castle_core/deploy.py @@ -745,15 +745,21 @@ def _env_context( 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. Keeps secrets out of the generated unit file and the process argv: systemd loads it via ``EnvironmentFile=`` and docker via ``--env-file``. Returns the 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. + + ``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: path.unlink(missing_ok=True) return None @@ -899,7 +905,7 @@ def _build_deployed( } ) 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. # `python` launchers run in place via `uv run` (below) — no tool venv.