fix: keep the harness admin password out of the docker exec argv

This commit is contained in:
Latte committed 2026-10-14 16:11:46 +02:00
1 parent 517c675048
commit 72462105f5
2 files changed
+44 -13

No files matched your search

+20 -13
View File
@@ -38,6 +38,7 @@ NAME_PREFIX = "aegis-it-"
GITEA_PORT = 3000 GITEA_PORT = 3000
ADMIN_LOGIN = "aegis-admin" ADMIN_LOGIN = "aegis-admin"
ADMIN_EMAIL = "aegis-admin@example.test" ADMIN_EMAIL = "aegis-admin@example.test"
ADMIN_PASSWORD_ENV = "GITEA_ADMIN_PASSWORD"
READY_TIMEOUT_SECONDS = 90.0 READY_TIMEOUT_SECONDS = 90.0
NETWORK_MODE_ENV = "AEGIS_IT_NETWORK_MODE" NETWORK_MODE_ENV = "AEGIS_IT_NETWORK_MODE"
HTTP_TIMEOUT_SECONDS = 30.0 HTTP_TIMEOUT_SECONDS = 30.0
@@ -53,12 +54,16 @@ class HarnessError(RuntimeError):
def run_docker( def run_docker(
*args: str, check: bool = True, timeout: float = 120.0 *args: str,
check: bool = True,
timeout: float = 120.0,
env: Mapping[str, str] | None = None,
) -> subprocess.CompletedProcess[str]: ) -> subprocess.CompletedProcess[str]:
"""Run ``docker <args>`` and return the completed process. """Run ``docker <args>`` and return the completed process.
On failure the error names only the first two arguments (never the full Secrets must not go into ``args`` (argv is visible to every local user): pass them
argv, which may carry a password) plus the command's stderr. in ``env`` and forward them with ``docker exec -e NAME``. On failure the error names
only the first two arguments plus the command's stderr.
""" """
try: try:
proc = subprocess.run( proc = subprocess.run(
@@ -67,6 +72,7 @@ def run_docker(
text=True, text=True,
timeout=timeout, timeout=timeout,
check=False, check=False,
env={**os.environ, **env} if env else None,
) )
except (FileNotFoundError, PermissionError) as exc: except (FileNotFoundError, PermissionError) as exc:
raise HarnessError("the 'docker' CLI was not found or is not executable") from exc raise HarnessError("the 'docker' CLI was not found or is not executable") from exc
@@ -480,23 +486,24 @@ def start_gitea() -> GiteaInstance:
res.attached_container = job_container res.attached_container = job_container
_wait_ready(base_url, res.container) _wait_ready(base_url, res.container)
admin_password = secrets.token_urlsafe(24) admin_password = secrets.token_urlsafe(24)
# The password travels in the environment of the docker CLI process and is forwarded
# with ``-e NAME`` (no value), so it never appears in any argv on the host. Inside
# the container it is read from the shell environment, not from the command line.
run_docker( run_docker(
"exec", "exec",
"-e",
ADMIN_PASSWORD_ENV,
"-u", "-u",
"git", "git",
res.container, res.container,
"gitea", "sh",
"admin", "-c",
"user", 'exec gitea admin user create --admin --username "$1" --email "$2" '
"create", f'--password "${ADMIN_PASSWORD_ENV}" --must-change-password=false',
"--admin", "sh",
"--username",
ADMIN_LOGIN, ADMIN_LOGIN,
"--password",
admin_password,
"--email",
ADMIN_EMAIL, ADMIN_EMAIL,
"--must-change-password=false", env={ADMIN_PASSWORD_ENV: admin_password},
) )
instance = GiteaInstance( instance = GiteaInstance(
base_url=base_url, base_url=base_url,
+24
View File
@@ -157,3 +157,27 @@ def test_container_id_candidates_fall_back_to_proc(tmp_path: Path) -> None:
def test_container_id_candidates_tolerate_missing_files(tmp_path: Path) -> None: def test_container_id_candidates_tolerate_missing_files(tmp_path: Path) -> None:
assert harness.container_id_candidates({}, proc_root=tmp_path) == [] assert harness.container_id_candidates({}, proc_root=tmp_path) == []
def test_run_docker_passes_secrets_through_the_environment_not_argv(
monkeypatch: pytest.MonkeyPatch,
) -> None:
seen: dict[str, object] = {}
def fake_run(argv: list[str], **kwargs: object) -> object:
seen["argv"] = argv
seen["env"] = kwargs.get("env")
class Done:
returncode = 0
stdout = ""
stderr = ""
return Done()
monkeypatch.setattr(harness.subprocess, "run", fake_run)
harness.run_docker("exec", "-e", "SECRET_VAR", "box", env={"SECRET_VAR": "s3cret-value"})
assert "s3cret-value" not in " ".join(seen["argv"]) # type: ignore[call-overload]
assert seen["env"]["SECRET_VAR"] == "s3cret-value" # type: ignore[index]
assert "PATH" in seen["env"] # type: ignore[operator]