sec(updater): harden tarball extraction and verify sha256 before extract
Reject symlinks, hardlinks, device nodes and FIFOs in update tarballs; validate each member's resolved path stays under dest after symlink resolution; cap uncompressed size at 256 MiB to bound gzip-bomb damage; strip setuid/setgid bits from extracted modes. Add an optional sha256 form field to /update and /update-self; the master client computes and sends it on every push, the executor refuses to extract on mismatch. mTLS already authenticates the master, so this is defence-in-depth against in-transit corruption and gives operators a way to pin "exactly these bytes" for vetted releases.
This commit is contained in:
@@ -51,7 +51,7 @@ def test_health_returns_role_and_releases(client: TestClient, monkeypatch: pytes
|
||||
def test_update_happy_path(client: TestClient, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
ex, "run_update",
|
||||
lambda data, sha, install_dir, agent_dir: {"status": "updated", "release": {"slot": "active", "sha": sha}, "probe": "ok"},
|
||||
lambda data, sha, install_dir, agent_dir, expected_sha256=None: {"status": "updated", "release": {"slot": "active", "sha": sha}, "probe": "ok"},
|
||||
)
|
||||
r = client.post(
|
||||
"/update",
|
||||
@@ -97,7 +97,7 @@ def test_update_self_requires_confirm(client: TestClient) -> None:
|
||||
def test_update_self_happy_path(client: TestClient, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
ex, "run_update_self",
|
||||
lambda data, sha, updater_install_dir: {"status": "self_update_queued", "argv": ["python", "-m", "decnet", "updater"]},
|
||||
lambda data, sha, updater_install_dir, expected_sha256=None: {"status": "self_update_queued", "argv": ["python", "-m", "decnet", "updater"]},
|
||||
)
|
||||
r = client.post(
|
||||
"/update-self",
|
||||
|
||||
Reference in New Issue
Block a user