Publish curated Unraid-AppOps-Gateway source from 4f99d8f6ea4fb8ae105b83570344b25fa05c31fd
This commit is contained in:
1 parent
27a33107a3
commit
f50d6e8c2c
14 files changed
+1178
-21
No files matched your search
@@ -264,6 +264,107 @@ def test_previous_private_tls_is_validated_from_the_attested_config_snapshot(
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_staged_config_checks_run_new_artifact_with_copied_config_and_bounded_output(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
stage_root = tmp_path / "source"
|
||||
stage_root.mkdir(mode=0o700)
|
||||
release_tree = (
|
||||
{
|
||||
"status_server.py": (b"new status server", 0o644),
|
||||
"controller-release.json": (b"new release identity", 0o644),
|
||||
},
|
||||
{"": 0o755},
|
||||
)
|
||||
config_tree = (
|
||||
{
|
||||
"projects.json": (b"{\"repo\":{}}", 0o600),
|
||||
"broker-token": (b"private broker token", 0o600),
|
||||
"gitea-validation.json": (b"{}", 0o600),
|
||||
"gitea-validation-token": (b"private validation token", 0o600),
|
||||
"private-tls.json": (b"private TLS config", 0o600),
|
||||
"webhook-secrets/repo": (b"private webhook secret", 0o600),
|
||||
},
|
||||
{"": 0o755, "webhook-secrets": 0o700},
|
||||
)
|
||||
calls = []
|
||||
validation_root = stage_root / "validation"
|
||||
|
||||
def run(arguments, *, data=None, max_output=module.MAX_BYTES):
|
||||
calls.append((arguments, max_output))
|
||||
assert (validation_root / "status_server.py").read_bytes() == b"new status server"
|
||||
assert (validation_root / "projects.json").read_bytes() == b"{\"repo\":{}}"
|
||||
assert (validation_root / "broker-token").read_bytes() == b"private broker token"
|
||||
assert (validation_root / "webhook-secrets" / "repo").read_bytes() == b"private webhook secret"
|
||||
return b"validated"
|
||||
|
||||
monkeypatch.setattr(module, "_write_private_tree", _write_test_tree)
|
||||
monkeypatch.setattr(module, "_run", run)
|
||||
|
||||
validator = getattr(module, "_validate_staged_configuration", None)
|
||||
assert callable(validator), "staged configuration validation helper is required"
|
||||
validator(stage_root, release_tree, config_tree)
|
||||
|
||||
assert calls == [
|
||||
(["python3", str(validation_root / "status_server.py"), "--check-artifact"], 4096),
|
||||
(["python3", str(validation_root / "status_server.py"), "--check-config"], 4096),
|
||||
(["python3", str(validation_root / "status_server.py"), "--check-validation-config"], 4096),
|
||||
(["python3", str(validation_root / "status_server.py"), "--check-validation-api"], 4096),
|
||||
(["python3", str(validation_root / "status_server.py"), "--check-private-tls-config"], 4096),
|
||||
]
|
||||
assert not validation_root.exists()
|
||||
|
||||
|
||||
def test_staged_config_check_failure_is_sanitized_and_cleans_private_validation_tree(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
stage_root = tmp_path / "source"
|
||||
stage_root.mkdir(mode=0o700)
|
||||
release_tree = (
|
||||
{
|
||||
"status_server.py": (b"new status server", 0o644),
|
||||
"controller-release.json": (b"new release identity", 0o644),
|
||||
},
|
||||
{"": 0o755},
|
||||
)
|
||||
config_tree = (
|
||||
{
|
||||
"projects.json": (b"{}", 0o600),
|
||||
"broker-token": (b"top-secret-broker", 0o600),
|
||||
"gitea-validation.json": (b"{}", 0o600),
|
||||
"gitea-validation-token": (b"top-secret-validation", 0o600),
|
||||
},
|
||||
{"": 0o755},
|
||||
)
|
||||
|
||||
class FailedProcess:
|
||||
returncode = 1
|
||||
stdout = b"token=top-secret-validation"
|
||||
stderr = b"secret=top-secret-broker"
|
||||
|
||||
monkeypatch.setattr(module, "_write_private_tree", _write_test_tree)
|
||||
monkeypatch.setattr(module.subprocess, "run", lambda *args, **kwargs: FailedProcess())
|
||||
|
||||
validator = getattr(module, "_validate_staged_configuration", None)
|
||||
assert callable(validator), "staged configuration validation helper is required"
|
||||
with pytest.raises(module.VolumeTransitionError, match="command_failed") as error:
|
||||
validator(stage_root, release_tree, config_tree)
|
||||
|
||||
assert "top-secret" not in str(error.value)
|
||||
assert not (stage_root / "validation").exists()
|
||||
|
||||
|
||||
def _write_test_tree(path, entries, directories):
|
||||
path.mkdir(mode=0o700)
|
||||
for relative, _mode in sorted(directories.items(), key=lambda item: item[0].count("/")):
|
||||
if relative:
|
||||
(path / relative).mkdir(parents=True, exist_ok=True)
|
||||
for relative, (contents, _mode) in entries.items():
|
||||
destination = path / relative
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
destination.write_bytes(contents)
|
||||
|
||||
|
||||
@pytest.mark.skipif(os.name == "nt", reason="private TLS snapshot guard requires POSIX symlink semantics")
|
||||
def test_previous_private_tls_rejects_symlinked_snapshot(tmp_path):
|
||||
previous = tmp_path / "previous-controller"
|
||||
@@ -298,12 +399,67 @@ def test_promoted_compose_actions_use_only_stdin_and_fixed_service(compose):
|
||||
module.compose_action(rendered, "stop")
|
||||
module.compose_action(rendered, "up")
|
||||
assert calls[-2][0][-2:] == ["stop", module.SERVICE]
|
||||
assert calls[-1][0][-5:] == ["up", "-d", "--force-recreate", "--pull", "never", module.SERVICE][-5:]
|
||||
up_index = calls[-1][0].index("up")
|
||||
assert calls[-1][0][up_index:] == [
|
||||
"up", "-d", "--force-recreate", "--pull", "never", "--no-deps", module.SERVICE
|
||||
]
|
||||
assert calls[-2][1] == rendered
|
||||
assert calls[-1][1] == rendered
|
||||
assert baseline["name"] == "gitea-deploy-runners"
|
||||
|
||||
|
||||
def test_rollback_uses_no_dependencies_when_recreating_prior_controller(compose, tmp_path, monkeypatch):
|
||||
_baseline, calls = compose
|
||||
previous = REVISION
|
||||
target = "c" * 40
|
||||
previous_compose = module.rendered_model(ORIGINAL_COMPOSE, previous, IMAGE_ID)
|
||||
target_compose = module.rendered_model(ORIGINAL_COMPOSE, target, IMAGE_ID)
|
||||
receipt = {
|
||||
"phase": "activated",
|
||||
"imageId": IMAGE_ID,
|
||||
"previousRevision": previous,
|
||||
"sourceRevision": target,
|
||||
}
|
||||
values = {
|
||||
"controller-before.tar": module._release_tar_bytes(
|
||||
previous,
|
||||
({"controller-release.json": (b"previous release", 0o644)}, {"": 0o755}),
|
||||
),
|
||||
"controller-after.tar": b"unused by isolated rollback test",
|
||||
"mirror-before.tar": b"unused by isolated rollback test",
|
||||
"compose-rollback.json": previous_compose,
|
||||
"compose-after.json": target_compose,
|
||||
}
|
||||
current = {
|
||||
"Mounts": [{
|
||||
"Destination": module.EXECUTABLE_TARGET,
|
||||
"Source": module._expected_revision_path(previous).as_posix(),
|
||||
}]
|
||||
}
|
||||
monkeypatch.setattr(module, "_load_transaction", lambda _backup: (1, receipt, values))
|
||||
monkeypatch.setattr(module.os, "close", lambda _descriptor: None)
|
||||
monkeypatch.setattr(module, "_controller_image_inspect", lambda *args, **kwargs: current)
|
||||
monkeypatch.setattr(module, "_verify_release_leaf", lambda *args, **kwargs: True)
|
||||
monkeypatch.setattr(module, "_stop_current_controller", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(module, "_sync_controller_mirror", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(module, "_ensure_root_compose", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(module, "_verify_compose_image", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(module, "_verify_active_mount", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(module, "_set_promotion_phase", lambda *args, **kwargs: None)
|
||||
|
||||
module.rollback_promotion(tmp_path / "backup")
|
||||
|
||||
up_calls = [
|
||||
arguments for arguments, _data in calls
|
||||
if arguments[:2] == ["docker", "compose"] and "up" in arguments
|
||||
]
|
||||
assert len(up_calls) == 1
|
||||
up_index = up_calls[0].index("up")
|
||||
assert up_calls[0][up_index:] == [
|
||||
"up", "-d", "--force-recreate", "--pull", "never", "--no-deps", module.SERVICE
|
||||
]
|
||||
|
||||
|
||||
def test_installer_has_no_shared_executable_stage_or_compose_path():
|
||||
source = (ROOT / "scripts/upgrade_deployment_controller.sh").read_text(encoding="utf-8")
|
||||
assert "mktemp -d -p /tmp \"itworx-controller-upgrade-" in source
|
||||
@@ -476,6 +632,11 @@ def test_source_compose_preflight_rejects_unresolvable_alias_keys():
|
||||
module._preflight_source_compose(source)
|
||||
|
||||
|
||||
def test_source_compose_preflight_bounds_recursive_list_aliases():
|
||||
source = b"services: {app: {image: fixed}}\nx-loop: &a [*a]\n"
|
||||
module._preflight_source_compose(source)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source",
|
||||
[
|
||||
|
||||
Reference in new issue
Block a user