Publish curated Unraid-AppOps-Gateway source from 451646fee806a47e3256731766980a05a262dcdd
This commit is contained in:
1 parent
532f3d9f26
commit
0a82153d95
43 files changed
+17722
-93
No files matched your search
@@ -0,0 +1,863 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import http.client
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import types
|
||||
import uuid
|
||||
from http.server import ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
BROKER = ROOT / "ops" / "gitea-deploy-broker"
|
||||
KEY = b"forge-delivery-test-hmac-key-32bytes"
|
||||
OIDC_SECRET = b"oidc-client-secret-sentinel-1234567890"
|
||||
READ_TOKEN = b"authentik-read-token-sentinel-1234567890"
|
||||
ARTIFACT = {
|
||||
"controllerVersion": "1.2.3",
|
||||
"sourceRepository": "jens/unraid-appops-gateway",
|
||||
"sourceRevision": "1" * 40,
|
||||
"sourceTree": "2" * 40,
|
||||
"artifactSha256": "3" * 64,
|
||||
"builtAt": "2026-10-03T10:00:00Z",
|
||||
}
|
||||
PROFILE = {
|
||||
"api_version": "itworx.forge-bootstrap-preflight/v1",
|
||||
"revision": "a" * 40,
|
||||
"workspace_image_digest": "sha256:" + "b" * 64,
|
||||
"frontdoor_image_digest": "sha256:" + "c" * 64,
|
||||
}
|
||||
|
||||
|
||||
def _load_status_module():
|
||||
try:
|
||||
import fcntl # noqa: F401 - use the real Linux flock implementation in tests.
|
||||
except ImportError: # pragma: no cover - Windows-only import shim.
|
||||
fcntl = types.ModuleType("fcntl")
|
||||
fcntl.LOCK_EX = 2
|
||||
fcntl.LOCK_UN = 8
|
||||
fcntl.flock = lambda *_args: None
|
||||
sys.modules["fcntl"] = fcntl
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"forge_secret_delivery_status_test", BROKER / "status_server.py"
|
||||
)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def status_module():
|
||||
return _load_status_module()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def endpoint(status_module):
|
||||
server = ThreadingHTTPServer(("127.0.0.1", 0), status_module.Handler)
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
try:
|
||||
yield server.server_address
|
||||
finally:
|
||||
server.shutdown()
|
||||
server.server_close()
|
||||
thread.join(timeout=2)
|
||||
|
||||
|
||||
def _config(**overrides: str) -> bytes:
|
||||
value = {
|
||||
"schema": "itworx.forge-first-install-config/v4",
|
||||
"issuer": "https://auth.example-host.com/application/o/itworx-forge/",
|
||||
"audience": "itworx-forge",
|
||||
"client_id": "itworx-forge",
|
||||
"authentik_api_url": "https://auth.example-host.com",
|
||||
"launch_url": "https://forge.example.com",
|
||||
"authorization_flow": "default-provider-authorization-implicit-consent",
|
||||
"invalidation_flow": "default-provider-invalidation-flow",
|
||||
"authentik_openid_mapping_id": "01234567-89ab-4cde-8fab-0123456789ab",
|
||||
"authentik_email_mapping_id": "21234567-89ab-4cde-8fab-0123456789ab",
|
||||
"authentik_profile_mapping_id": "31234567-89ab-4cde-8fab-0123456789ab",
|
||||
"authentik_provider_id": "1234567890",
|
||||
"authentik_signing_key_id": "11234567-89ab-4cde-8fab-0123456789ab",
|
||||
"private_package_owner": "itworx-forge-private",
|
||||
}
|
||||
value.update(overrides)
|
||||
return json.dumps(value, sort_keys=True, separators=(",", ":")).encode()
|
||||
|
||||
|
||||
def _payload(status_module, *, config_bytes: bytes | None = None, **overrides):
|
||||
config_bytes = config_bytes if config_bytes is not None else _config()
|
||||
value = {
|
||||
"apiVersion": status_module.FORGE_SECRET_DELIVERY_API_VERSION,
|
||||
"target": status_module.FORGE_SECRET_DELIVERY_TARGET,
|
||||
"profile": dict(PROFILE),
|
||||
"configBase64": base64.b64encode(config_bytes).decode("ascii"),
|
||||
"oidcClientSecretBase64": base64.b64encode(OIDC_SECRET).decode("ascii"),
|
||||
"authentikReadTokenBase64": base64.b64encode(READ_TOKEN).decode("ascii"),
|
||||
}
|
||||
value.update(overrides)
|
||||
return value
|
||||
|
||||
|
||||
def _signed_headers(status_module, body: bytes, *, nonce: str | None = None):
|
||||
timestamp = str(int(time.time()))
|
||||
nonce = nonce or uuid.uuid4().hex
|
||||
signature = status_module._request_signature(
|
||||
KEY,
|
||||
method="POST",
|
||||
path=status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
timestamp=timestamp,
|
||||
nonce=nonce,
|
||||
raw_body=body,
|
||||
)
|
||||
return {
|
||||
"Content-Type": "application/json",
|
||||
"X-ITWorx-Deployment-Timestamp": timestamp,
|
||||
"X-ITWorx-Deployment-Nonce": nonce,
|
||||
"X-ITWorx-Deployment-Signature": signature,
|
||||
}
|
||||
|
||||
|
||||
def _post(address, path: str, body: bytes, headers: dict[str, str]):
|
||||
connection = http.client.HTTPConnection(*address, timeout=3)
|
||||
try:
|
||||
connection.request("POST", path, body=body, headers=headers)
|
||||
response = connection.getresponse()
|
||||
return response.status, response.read()
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
def _install_hmac_test(monkeypatch, status_module):
|
||||
consumed: set[str] = set()
|
||||
monkeypatch.setattr(status_module, "_forge_first_install_secret", lambda: KEY)
|
||||
|
||||
def consume(_secret, nonce):
|
||||
if nonce in consumed:
|
||||
return False
|
||||
consumed.add(nonce)
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(status_module, "_consume_appops_nonce", consume)
|
||||
return consumed
|
||||
|
||||
|
||||
def _install_successful_prerequisites(monkeypatch, status_module, helper=None):
|
||||
counters = {"artifact": 0, "store": 0, "backup": 0, "runtime": 0}
|
||||
|
||||
def artifact():
|
||||
counters["artifact"] += 1
|
||||
return dict(ARTIFACT)
|
||||
|
||||
def store():
|
||||
counters["store"] += 1
|
||||
return ("/var/lib/docker", "itworx-controller-hub-releases", (1, 2), (1, 2))
|
||||
|
||||
def backup():
|
||||
counters["backup"] += 1
|
||||
return True
|
||||
|
||||
def runtime(profile, *, _held_candidate):
|
||||
counters["runtime"] += 1
|
||||
assert profile == PROFILE
|
||||
assert isinstance(_held_candidate, dict)
|
||||
return {"status": "bundle_prerequisites_passed"}
|
||||
|
||||
monkeypatch.setattr(status_module, "_forge_first_install_requests_are_absent", lambda: True)
|
||||
monkeypatch.setattr(status_module, "_forge_controller_artifact_identity", artifact)
|
||||
monkeypatch.setattr(status_module, "_forge_release_store_identity", store)
|
||||
monkeypatch.setattr(status_module, "_forge_fixed_backup_volume_is_ready", backup)
|
||||
monkeypatch.setattr(status_module, "_forge_bootstrap_runtime_checks", runtime)
|
||||
if helper is not None:
|
||||
monkeypatch.setattr(status_module, "_prepare_forge_secret_bundle", helper)
|
||||
return counters
|
||||
|
||||
|
||||
def test_candidate_parser_requires_canonical_config_and_secret_free_strings(status_module):
|
||||
parsed = status_module._forge_secret_delivery_candidate(_payload(status_module))
|
||||
assert parsed is not None
|
||||
profile, candidate = parsed
|
||||
assert profile == PROFILE
|
||||
assert candidate["config_bytes"] == _config()
|
||||
assert candidate["oidc_client_secret"] == OIDC_SECRET
|
||||
assert candidate["authentik_read_token"] == READ_TOKEN
|
||||
|
||||
pretty = json.dumps(json.loads(_config()), indent=2).encode()
|
||||
assert status_module._forge_secret_delivery_candidate(
|
||||
_payload(status_module, config_bytes=pretty)
|
||||
) is None
|
||||
secret_bearing_config = _config(authorization_flow=OIDC_SECRET.decode())
|
||||
assert status_module._forge_secret_delivery_candidate(
|
||||
_payload(status_module, config_bytes=secret_bearing_config)
|
||||
) is None
|
||||
noncanonical = _payload(status_module)
|
||||
noncanonical["oidcClientSecretBase64"] += "\n"
|
||||
assert status_module._forge_secret_delivery_candidate(noncanonical) is None
|
||||
|
||||
|
||||
def test_invalid_authentication_has_no_remote_or_bundle_side_effects(
|
||||
status_module, endpoint, monkeypatch
|
||||
):
|
||||
counters = {"runtime": 0, "bundle": 0}
|
||||
consumed = _install_hmac_test(monkeypatch, status_module)
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_forge_controller_artifact_identity",
|
||||
lambda: pytest.fail("unauthenticated input reached local gate"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_forge_release_store_identity",
|
||||
lambda: pytest.fail("unauthenticated input reached volume probe"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_forge_fixed_backup_volume_is_ready",
|
||||
lambda: pytest.fail("unauthenticated input reached backup probe"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_forge_bootstrap_runtime_checks",
|
||||
lambda *_args, **_kwargs: counters.__setitem__("runtime", counters["runtime"] + 1),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_prepare_forge_secret_bundle",
|
||||
lambda *_args, **_kwargs: counters.__setitem__("bundle", counters["bundle"] + 1),
|
||||
)
|
||||
body = json.dumps(_payload(status_module), separators=(",", ":")).encode()
|
||||
headers = _signed_headers(status_module, body)
|
||||
headers["X-ITWorx-Deployment-Signature"] = "0" * 64
|
||||
|
||||
status, response = _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
headers,
|
||||
)
|
||||
assert status == 403
|
||||
assert response == b'{"status":"authentication_rejected"}\n'
|
||||
assert counters == {"runtime": 0, "bundle": 0}
|
||||
assert consumed == set()
|
||||
|
||||
|
||||
def test_duplicate_json_key_is_rejected_before_auth_or_remote_checks(
|
||||
status_module, endpoint, monkeypatch
|
||||
):
|
||||
consumed = _install_hmac_test(monkeypatch, status_module)
|
||||
called = []
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_forge_prepare_secret_delivery_bundle",
|
||||
lambda *_args, **_kwargs: called.append(True),
|
||||
)
|
||||
body = b'{"apiVersion":"x","apiVersion":"y"}'
|
||||
status, response = _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
{
|
||||
"Content-Type": "application/json",
|
||||
"X-ITWorx-Deployment-Timestamp": str(int(time.time())),
|
||||
"X-ITWorx-Deployment-Nonce": uuid.uuid4().hex,
|
||||
"X-ITWorx-Deployment-Signature": "0" * 64,
|
||||
},
|
||||
)
|
||||
assert status == 400
|
||||
assert response == b'{"status":"invalid_json"}\n'
|
||||
assert called == []
|
||||
assert consumed == set()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("body", "content_type", "expected_status"),
|
||||
[
|
||||
(b"{}", "application/json; charset=utf-8", 400),
|
||||
(b"x" * 16_385, "application/json", 413),
|
||||
],
|
||||
)
|
||||
def test_body_limits_and_content_type_fail_before_auth(
|
||||
status_module, endpoint, monkeypatch, body, content_type, expected_status
|
||||
):
|
||||
consumed = _install_hmac_test(monkeypatch, status_module)
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"_forge_controller_artifact_identity",
|
||||
lambda: pytest.fail("invalid HTTP framing reached local gate"),
|
||||
)
|
||||
headers = {
|
||||
"Content-Type": content_type,
|
||||
"X-ITWorx-Deployment-Timestamp": str(int(time.time())),
|
||||
"X-ITWorx-Deployment-Nonce": uuid.uuid4().hex,
|
||||
"X-ITWorx-Deployment-Signature": "0" * 64,
|
||||
}
|
||||
status, _response = _post(
|
||||
endpoint, status_module.FORGE_SECRET_DELIVERY_PATH, body, headers
|
||||
)
|
||||
assert status == expected_status
|
||||
assert consumed == set()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("failed_gate", ["artifact", "store", "backup", "runtime"])
|
||||
def test_every_fixed_prerequisite_gate_precedes_bundle_writer(
|
||||
status_module, endpoint, monkeypatch, failed_gate
|
||||
):
|
||||
_install_hmac_test(monkeypatch, status_module)
|
||||
calls = {name: 0 for name in ("artifact", "store", "backup", "runtime", "helper")}
|
||||
|
||||
def artifact():
|
||||
calls["artifact"] += 1
|
||||
return None if failed_gate == "artifact" else dict(ARTIFACT)
|
||||
|
||||
def store():
|
||||
calls["store"] += 1
|
||||
return None if failed_gate == "store" else ("fixed", "volume", (1, 2), (1, 2))
|
||||
|
||||
def backup():
|
||||
calls["backup"] += 1
|
||||
return failed_gate != "backup"
|
||||
|
||||
def runtime(profile, *, _held_candidate):
|
||||
calls["runtime"] += 1
|
||||
return {
|
||||
"status": "bundle_prerequisites_blocked"
|
||||
if failed_gate == "runtime"
|
||||
else "bundle_prerequisites_passed"
|
||||
}
|
||||
|
||||
def helper(*_args, **_kwargs):
|
||||
calls["helper"] += 1
|
||||
return {
|
||||
"status": "bundle_ready",
|
||||
"secretFilesReady": 7,
|
||||
"masterKeyBackupVerified": True,
|
||||
"applyPreflight": "not_evaluated",
|
||||
}
|
||||
|
||||
monkeypatch.setattr(status_module, "_forge_first_install_requests_are_absent", lambda: True)
|
||||
monkeypatch.setattr(status_module, "_forge_controller_artifact_identity", artifact)
|
||||
monkeypatch.setattr(status_module, "_forge_release_store_identity", store)
|
||||
monkeypatch.setattr(status_module, "_forge_fixed_backup_volume_is_ready", backup)
|
||||
monkeypatch.setattr(status_module, "_forge_bootstrap_runtime_checks", runtime)
|
||||
monkeypatch.setattr(status_module, "_prepare_forge_secret_bundle", helper)
|
||||
body = json.dumps(_payload(status_module), separators=(",", ":")).encode()
|
||||
|
||||
status, _response = _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
_signed_headers(status_module, body),
|
||||
)
|
||||
assert status == 409
|
||||
assert calls["helper"] == 0
|
||||
if failed_gate in {"artifact", "store", "backup"}:
|
||||
assert calls["runtime"] == 0
|
||||
else:
|
||||
assert calls["runtime"] == 1
|
||||
|
||||
|
||||
def test_signed_route_returns_only_sanitized_bundle_readiness_and_replay_is_rejected(
|
||||
status_module, endpoint, monkeypatch
|
||||
):
|
||||
consumed = _install_hmac_test(monkeypatch, status_module)
|
||||
helper_calls = []
|
||||
|
||||
def helper(oidc_secret, read_token, config_bytes, *, validate_config):
|
||||
helper_calls.append((oidc_secret, read_token, config_bytes))
|
||||
assert oidc_secret == OIDC_SECRET
|
||||
assert read_token == READ_TOKEN
|
||||
assert validate_config(config_bytes) is True
|
||||
return {
|
||||
"status": "bundle_ready",
|
||||
"secretFilesReady": 7,
|
||||
"masterKeyBackupVerified": True,
|
||||
"applyPreflight": "not_evaluated",
|
||||
}
|
||||
|
||||
counters = _install_successful_prerequisites(monkeypatch, status_module, helper)
|
||||
monkeypatch.setattr(
|
||||
status_module._forge_first_install_controller,
|
||||
"remember_preflight",
|
||||
lambda *_args: pytest.fail("bundle readiness must not remember a preflight"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module._forge_first_install_controller,
|
||||
"apply",
|
||||
lambda *_args: pytest.fail("bundle readiness must not start first install"),
|
||||
)
|
||||
body = json.dumps(_payload(status_module), separators=(",", ":")).encode()
|
||||
headers = _signed_headers(status_module, body)
|
||||
nonce = headers["X-ITWorx-Deployment-Nonce"]
|
||||
status, response = _post(
|
||||
endpoint, status_module.FORGE_SECRET_DELIVERY_PATH, body, headers
|
||||
)
|
||||
assert status == 200
|
||||
decoded = json.loads(response)
|
||||
assert decoded == {
|
||||
"apiVersion": status_module.FORGE_SECRET_DELIVERY_API_VERSION,
|
||||
"target": "itworx-forge",
|
||||
"status": "bundle_ready",
|
||||
"profile": PROFILE,
|
||||
"controllerArtifact": {
|
||||
key: ARTIFACT[key]
|
||||
for key in (
|
||||
"controllerVersion",
|
||||
"sourceRepository",
|
||||
"sourceRevision",
|
||||
"sourceTree",
|
||||
"artifactSha256",
|
||||
)
|
||||
},
|
||||
"secretFilesReady": 7,
|
||||
"masterKeyBackupVerified": True,
|
||||
"applyPreflight": "not_evaluated",
|
||||
}
|
||||
assert "secretFilesReady" in decoded
|
||||
assert OIDC_SECRET.decode() not in response.decode()
|
||||
assert READ_TOKEN.decode() not in response.decode()
|
||||
assert base64.b64encode(OIDC_SECRET).decode() not in response.decode()
|
||||
assert base64.b64encode(READ_TOKEN).decode() not in response.decode()
|
||||
assert len(consumed) == 1 and nonce in consumed
|
||||
assert helper_calls == [(OIDC_SECRET, READ_TOKEN, _config())]
|
||||
assert counters == {"artifact": 2, "store": 2, "backup": 2, "runtime": 1}
|
||||
|
||||
status, replay_response = _post(
|
||||
endpoint, status_module.FORGE_SECRET_DELIVERY_PATH, body, headers
|
||||
)
|
||||
assert status == 403
|
||||
assert replay_response == b'{"status":"authentication_rejected"}\n'
|
||||
assert len(helper_calls) == 1
|
||||
assert counters == {"artifact": 2, "store": 2, "backup": 2, "runtime": 1}
|
||||
|
||||
|
||||
def test_new_nonce_retries_same_bundle_and_changed_input_is_rejected(
|
||||
status_module, endpoint, monkeypatch
|
||||
):
|
||||
_install_hmac_test(monkeypatch, status_module)
|
||||
from forge_secret_bundle import ForgeSecretBundleError
|
||||
|
||||
accepted_inputs = None
|
||||
helper_calls = []
|
||||
|
||||
def helper(oidc_secret, read_token, config_bytes, *, validate_config):
|
||||
nonlocal accepted_inputs
|
||||
inputs = (oidc_secret, read_token, config_bytes)
|
||||
helper_calls.append(inputs)
|
||||
assert validate_config(config_bytes) is True
|
||||
if accepted_inputs is None:
|
||||
accepted_inputs = inputs
|
||||
elif inputs != accepted_inputs:
|
||||
raise ForgeSecretBundleError("input_changed")
|
||||
return {
|
||||
"status": "bundle_ready",
|
||||
"secretFilesReady": 7,
|
||||
"masterKeyBackupVerified": True,
|
||||
"applyPreflight": "not_evaluated",
|
||||
}
|
||||
|
||||
_install_successful_prerequisites(monkeypatch, status_module, helper)
|
||||
|
||||
def send(payload):
|
||||
body = json.dumps(payload, separators=(",", ":")).encode()
|
||||
return _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
_signed_headers(status_module, body),
|
||||
)
|
||||
|
||||
assert send(_payload(status_module))[0] == 200
|
||||
assert send(_payload(status_module))[0] == 200
|
||||
changed = _payload(status_module)
|
||||
changed["oidcClientSecretBase64"] = base64.b64encode(b"x" * 40).decode("ascii")
|
||||
status, response = send(changed)
|
||||
assert status == 409
|
||||
assert json.loads(response) == {
|
||||
"status": "secret_bundle_failed",
|
||||
"code": "input_changed",
|
||||
}
|
||||
assert accepted_inputs == (OIDC_SECRET, READ_TOKEN, _config())
|
||||
assert helper_calls == [
|
||||
accepted_inputs,
|
||||
accepted_inputs,
|
||||
(b"x" * 40, READ_TOKEN, _config()),
|
||||
]
|
||||
assert OIDC_SECRET.decode() not in response.decode()
|
||||
assert READ_TOKEN.decode() not in response.decode()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.name != "posix" or getattr(os, "geteuid", lambda: 1)() != 0,
|
||||
reason="the real bundle helper requires POSIX root ownership",
|
||||
)
|
||||
def test_signed_http_delivery_uses_real_bundle_helper_and_never_rotates(
|
||||
status_module, endpoint, monkeypatch, tmp_path
|
||||
):
|
||||
_install_hmac_test(monkeypatch, status_module)
|
||||
import importlib
|
||||
|
||||
bundle_module = importlib.import_module("forge_secret_bundle")
|
||||
assert Path(bundle_module.__file__).resolve() == (
|
||||
BROKER / "forge_secret_bundle.py"
|
||||
).resolve()
|
||||
root = tmp_path / "real-bundle-root"
|
||||
root.mkdir(mode=0o700)
|
||||
root.chmod(0o700)
|
||||
roots = bundle_module._Roots.for_test(root)
|
||||
for path in (roots.config_root, roots.state_parent, roots.backup_root):
|
||||
path.mkdir(mode=0o700, exist_ok=True)
|
||||
path.chmod(0o700)
|
||||
monkeypatch.setattr(bundle_module, "_PRODUCTION_ROOTS", roots)
|
||||
|
||||
counters = _install_successful_prerequisites(
|
||||
monkeypatch, status_module
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module._forge_first_install_controller,
|
||||
"remember_preflight",
|
||||
lambda *_args: pytest.fail("bundle readiness must not persist a preflight"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
status_module._forge_first_install_controller,
|
||||
"apply",
|
||||
lambda *_args: pytest.fail("bundle readiness must not start first install"),
|
||||
)
|
||||
|
||||
def send(payload):
|
||||
body = json.dumps(payload, separators=(",", ":")).encode()
|
||||
return _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
_signed_headers(status_module, body),
|
||||
)
|
||||
|
||||
status, response = send(_payload(status_module))
|
||||
assert status == 200
|
||||
decoded = json.loads(response)
|
||||
assert decoded["status"] == "bundle_ready"
|
||||
assert decoded["secretFilesReady"] == 7
|
||||
assert decoded["masterKeyBackupVerified"] is True
|
||||
assert decoded["applyPreflight"] == "not_evaluated"
|
||||
assert OIDC_SECRET.decode() not in response.decode()
|
||||
assert READ_TOKEN.decode() not in response.decode()
|
||||
|
||||
secret_paths = sorted(roots.secrets_root.iterdir())
|
||||
assert {path.name for path in secret_paths} == {
|
||||
"postgres_bootstrap_password.secret",
|
||||
"runtime_database_url.secret",
|
||||
"migrator_database_url.secret",
|
||||
"oidc_client_secret.secret",
|
||||
"session_secret.secret",
|
||||
"master_key.secret",
|
||||
"authentik_read_token.secret",
|
||||
}
|
||||
assert (roots.secrets_root / "oidc_client_secret.secret").read_bytes() == OIDC_SECRET
|
||||
assert (roots.secrets_root / "authentik_read_token.secret").read_bytes() == READ_TOKEN
|
||||
assert roots.config_path.read_bytes() == _config()
|
||||
master_key = (roots.secrets_root / "master_key.secret").read_bytes()
|
||||
assert len(master_key) == 32
|
||||
backup_path = roots.backup_root / "master_key.backup"
|
||||
assert backup_path.read_bytes() == master_key
|
||||
|
||||
protected_paths = [*secret_paths, roots.config_path, backup_path]
|
||||
|
||||
def identities():
|
||||
return {
|
||||
path: (path.stat().st_ino, path.read_bytes())
|
||||
for path in protected_paths
|
||||
}
|
||||
|
||||
original = identities()
|
||||
status, retry_response = send(_payload(status_module))
|
||||
assert status == 200
|
||||
assert json.loads(retry_response)["status"] == "bundle_ready"
|
||||
assert identities() == original
|
||||
|
||||
changed = _payload(status_module)
|
||||
changed["authentikReadTokenBase64"] = base64.b64encode(
|
||||
b"different-authentik-read-token-value-12345"
|
||||
).decode("ascii")
|
||||
status, changed_response = send(changed)
|
||||
assert status == 409
|
||||
assert json.loads(changed_response) == {
|
||||
"status": "secret_bundle_failed",
|
||||
"code": "input_changed",
|
||||
}
|
||||
assert identities() == original
|
||||
assert OIDC_SECRET.decode() not in changed_response.decode()
|
||||
assert READ_TOKEN.decode() not in changed_response.decode()
|
||||
assert counters == {"artifact": 6, "store": 6, "backup": 6, "runtime": 3}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad_result",
|
||||
[
|
||||
{
|
||||
"status": "bundle_ready",
|
||||
"secretFilesReady": True,
|
||||
"masterKeyBackupVerified": True,
|
||||
"applyPreflight": "not_evaluated",
|
||||
},
|
||||
{
|
||||
"status": "bundle_ready",
|
||||
"secretFilesReady": 7,
|
||||
"masterKeyBackupVerified": 1,
|
||||
"applyPreflight": "not_evaluated",
|
||||
},
|
||||
{
|
||||
"status": "bundle_ready",
|
||||
"secretFilesReady": 7,
|
||||
"masterKeyBackupVerified": True,
|
||||
"applyPreflight": "not_evaluated",
|
||||
"unexpected": "must be rejected",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_malformed_core_helper_results_are_not_accepted(
|
||||
status_module, endpoint, monkeypatch, bad_result
|
||||
):
|
||||
_install_hmac_test(monkeypatch, status_module)
|
||||
_install_successful_prerequisites(
|
||||
monkeypatch, status_module, lambda *_args, **_kwargs: bad_result
|
||||
)
|
||||
body = json.dumps(_payload(status_module), separators=(",", ":")).encode()
|
||||
status, response = _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
_signed_headers(status_module, body),
|
||||
)
|
||||
assert status == 409
|
||||
assert json.loads(response) == {
|
||||
"status": "secret_bundle_failed",
|
||||
"code": "bundle_result_unverified",
|
||||
}
|
||||
|
||||
|
||||
def test_unrecognized_core_error_code_is_replaced_with_fixed_code(
|
||||
status_module, endpoint, monkeypatch
|
||||
):
|
||||
_install_hmac_test(monkeypatch, status_module)
|
||||
from forge_secret_bundle import ForgeSecretBundleError
|
||||
|
||||
private_error = "unapproved-" + OIDC_SECRET.decode()
|
||||
|
||||
def helper(*_args, **_kwargs):
|
||||
raise ForgeSecretBundleError(private_error)
|
||||
|
||||
_install_successful_prerequisites(monkeypatch, status_module, helper)
|
||||
body = json.dumps(_payload(status_module), separators=(",", ":")).encode()
|
||||
status, response = _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
_signed_headers(status_module, body),
|
||||
)
|
||||
assert status == 409
|
||||
assert json.loads(response) == {
|
||||
"status": "secret_bundle_failed",
|
||||
"code": "bundle_preparation_failed",
|
||||
}
|
||||
assert private_error.encode() not in response
|
||||
assert OIDC_SECRET.decode().encode() not in response
|
||||
|
||||
|
||||
def test_helper_error_text_is_never_returned(status_module, endpoint, monkeypatch):
|
||||
_install_hmac_test(monkeypatch, status_module)
|
||||
|
||||
def helper(*_args, **_kwargs):
|
||||
raise RuntimeError("disk failed: " + OIDC_SECRET.decode())
|
||||
|
||||
_install_successful_prerequisites(monkeypatch, status_module, helper)
|
||||
body = json.dumps(_payload(status_module), separators=(",", ":")).encode()
|
||||
status, response = _post(
|
||||
endpoint,
|
||||
status_module.FORGE_SECRET_DELIVERY_PATH,
|
||||
body,
|
||||
_signed_headers(status_module, body),
|
||||
)
|
||||
assert status == 409
|
||||
assert OIDC_SECRET.decode() not in response.decode()
|
||||
assert READ_TOKEN.decode() not in response.decode()
|
||||
assert b"disk failed" not in response
|
||||
|
||||
|
||||
def test_held_candidate_runtime_skips_destination_secrets_and_preflight_receipt(
|
||||
status_module, monkeypatch, tmp_path
|
||||
):
|
||||
parsed = status_module._forge_secret_delivery_candidate(_payload(status_module))
|
||||
assert parsed is not None
|
||||
profile, candidate = parsed
|
||||
app_root = tmp_path / "managed-appdata"
|
||||
postgres = app_root / "itworx-forge" / "postgres"
|
||||
postgres.mkdir(parents=True)
|
||||
postgres.chmod(0o700)
|
||||
os.chown(postgres, 70, 70)
|
||||
app_root.chmod(0o700)
|
||||
monkeypatch.setattr(status_module, "MANAGED_APPDATA_ROOT", app_root)
|
||||
monkeypatch.setattr(status_module, "_refresh_appdata_root_selection", lambda: app_root)
|
||||
monkeypatch.setattr(status_module, "appdata_root_is_safe", lambda _root: True)
|
||||
monkeypatch.setattr(status_module, "_forge_app_dir_metadata_is_safe", lambda _info: True)
|
||||
monkeypatch.setattr(status_module, "_forge_gitea_main_revision", lambda: profile["revision"])
|
||||
manifest = b"fixed compose bytes used by this unit test"
|
||||
monkeypatch.setattr(
|
||||
status_module,
|
||||
"FORGE_COMPOSE_SHA256",
|
||||
hashlib.sha256(manifest).hexdigest(),
|
||||
)
|
||||
calls = {"registry": 0, "oidc": 0, "secret_metadata": 0}
|
||||
|
||||
def registry(_profile, *, candidate_config):
|
||||
calls["registry"] += 1
|
||||
assert candidate_config is candidate["config"]
|
||||
return "passed", {"ownerVisibility": "private"}
|
||||
|
||||
def oidc(*, held_candidate):
|
||||
calls["oidc"] += 1
|
||||
assert held_candidate is candidate
|
||||
return "passed", {"clientSecretMatched": True}
|
||||
|
||||
def secret_metadata(*_args, **_kwargs):
|
||||
calls["secret_metadata"] += 1
|
||||
pytest.fail("held candidate must not read destination secret files")
|
||||
|
||||
monkeypatch.setattr(status_module, "_forge_image_registry_attestation", registry)
|
||||
monkeypatch.setattr(status_module, "_forge_oidc_attestation", oidc)
|
||||
monkeypatch.setattr(status_module, "_forge_secret_metadata", secret_metadata)
|
||||
monkeypatch.setattr(status_module, "_load_forge_bootstrap_config", lambda *_args: pytest.fail("held config fell back to disk"))
|
||||
monkeypatch.setattr(status_module, "_forge_push_validation_attestation", lambda _revision: ("passed", {"context": "fixed"}))
|
||||
monkeypatch.setattr(status_module, "_forge_local_image_present", lambda _image: None)
|
||||
monkeypatch.setattr(
|
||||
status_module._forge_first_install_controller,
|
||||
"remember_preflight",
|
||||
lambda *_args: pytest.fail("secret bundle readiness must not persist a preflight receipt"),
|
||||
)
|
||||
|
||||
def fake_run(arguments, **_kwargs):
|
||||
if arguments[:2] == ["git", "--git-dir"]:
|
||||
return subprocess.CompletedProcess(arguments, 0, stdout=manifest, stderr=b"")
|
||||
if arguments == ["docker", "network", "ls", "--format", "{{.Name}}"]:
|
||||
return subprocess.CompletedProcess(arguments, 0, stdout="itworx-mcp-hub-npm\n", stderr="")
|
||||
if arguments[:3] == ["docker", "network", "inspect"]:
|
||||
return subprocess.CompletedProcess(
|
||||
arguments,
|
||||
0,
|
||||
stdout=json.dumps({"Name": "itworx-mcp-hub-npm", "Driver": "bridge", "Scope": "local"}),
|
||||
stderr="",
|
||||
)
|
||||
if arguments == ["docker", "ps", "-a", "--format", "{{.Names}}"]:
|
||||
return subprocess.CompletedProcess(arguments, 0, stdout="", stderr="")
|
||||
pytest.fail(f"unexpected runtime command: {arguments}")
|
||||
|
||||
monkeypatch.setattr(status_module.subprocess, "run", fake_run)
|
||||
result = status_module._forge_bootstrap_runtime_checks(
|
||||
profile, _held_candidate=candidate
|
||||
)
|
||||
assert result["status"] == "bundle_prerequisites_passed"
|
||||
assert "secret_delivery" not in result["checks"]
|
||||
assert calls == {"registry": 1, "oidc": 1, "secret_metadata": 0}
|
||||
|
||||
|
||||
def test_release_store_proof_checks_fixed_volume_alias_and_pinned_identity(
|
||||
status_module, monkeypatch
|
||||
):
|
||||
release_store = status_module._mcp_hub_release_store
|
||||
document = {
|
||||
"Name": release_store.VOLUME_NAME,
|
||||
"Driver": "local",
|
||||
"Scope": "local",
|
||||
"Mountpoint": release_store.VOLUME_HOST_ROOT.as_posix(),
|
||||
"Options": None,
|
||||
"Labels": dict(release_store.EXPECTED_LABELS),
|
||||
}
|
||||
commands = []
|
||||
|
||||
def run_fixed(arguments, *, maximum_stdout, **_kwargs):
|
||||
commands.append((arguments, maximum_stdout))
|
||||
if arguments[:2] == ["docker", "info"]:
|
||||
return b"/var/lib/docker\n", b""
|
||||
if arguments[:3] == ["docker", "volume", "inspect"]:
|
||||
return json.dumps(document).encode(), b""
|
||||
pytest.fail(f"unexpected command {arguments}")
|
||||
|
||||
class _PinnedDirectory:
|
||||
def __init__(self, identity):
|
||||
self.value = identity
|
||||
|
||||
def identity(self):
|
||||
return self.value
|
||||
|
||||
class _Store:
|
||||
host = _PinnedDirectory((4, 5))
|
||||
logical = _PinnedDirectory((4, 5))
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *_args):
|
||||
return None
|
||||
|
||||
def assert_current(self):
|
||||
return None
|
||||
|
||||
opened = []
|
||||
|
||||
def open_fixed(metadata, docker_root_dir):
|
||||
opened.append((metadata, docker_root_dir))
|
||||
return _Store()
|
||||
|
||||
monkeypatch.setattr(status_module, "_forge_bounded_readonly_command", run_fixed)
|
||||
monkeypatch.setattr(status_module, "_repopulse_adoption_alias_mounts_ready", lambda: True)
|
||||
monkeypatch.setattr(
|
||||
status_module._repopulse_adoption_store,
|
||||
"capability_report",
|
||||
lambda: {"controllerAliasesReady": True},
|
||||
)
|
||||
monkeypatch.setattr(release_store, "open_fixed_release_store", open_fixed)
|
||||
identity = status_module._forge_release_store_identity()
|
||||
assert identity == (
|
||||
"/var/lib/docker",
|
||||
release_store.VOLUME_NAME,
|
||||
(4, 5),
|
||||
(4, 5),
|
||||
)
|
||||
assert opened == [(document, "/var/lib/docker")]
|
||||
assert [item[0] for item in commands] == [
|
||||
["docker", "info", "--format", "{{.DockerRootDir}}"],
|
||||
[
|
||||
"docker",
|
||||
"volume",
|
||||
"inspect",
|
||||
"--format",
|
||||
"{{json .}}",
|
||||
release_store.VOLUME_NAME,
|
||||
],
|
||||
]
|
||||
|
||||
opened.clear()
|
||||
document["Labels"] = {"itworx.purpose": "different-volume"}
|
||||
assert status_module._forge_release_store_identity() is None
|
||||
assert opened == []
|
||||
|
||||
|
||||
def test_backup_volume_verifier_requires_its_read_only_none_contract(
|
||||
status_module, monkeypatch
|
||||
):
|
||||
backup = types.ModuleType("forge_backup_paths")
|
||||
backup.validate_forge_backup_volume = lambda: None
|
||||
monkeypatch.setitem(sys.modules, "forge_backup_paths", backup)
|
||||
assert status_module._forge_fixed_backup_volume_is_ready() is True
|
||||
backup.validate_forge_backup_volume = lambda: True
|
||||
assert status_module._forge_fixed_backup_volume_is_ready() is False
|
||||
Reference in new issue
Block a user