Publish curated Unraid-AppOps-Gateway source from b6d6a3e1657000c6e0a482c8056a3fbebbafd711

This commit is contained in:
Public Source Publisher committed 2026-10-09 15:30:32 +00:00
1 parent 2d50064a8f
commit d825f5045d
11 files changed
+438 -43

No files matched your search

+1 -1
View File
@@ -1,3 +1,3 @@
# Public source export
This source snapshot was generated from the private canonical repository at revision `28831bd43867347a132f1c2b0f388632b9cb561e`. It contains no private Git history or operational evidence. Changes are published from the canonical repository.
This source snapshot was generated from the private canonical repository at revision `b6d6a3e1657000c6e0a482c8056a3fbebbafd711`. It contains no private Git history or operational evidence. Changes are published from the canonical repository.
+23 -13
View File
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"sourceRevision": "28831bd43867347a132f1c2b0f388632b9cb561e",
"sourceRevision": "b6d6a3e1657000c6e0a482c8056a3fbebbafd711",
"files": [
{
"path": ".dockerignore",
@@ -524,7 +524,7 @@
},
{
"path": "backend/app/services/controller_artifact_helper_spec.py",
"sha256": "dc456d0005b7181098d99028fa8ea110fb53b037aac1c031c98a9101a61183bd",
"sha256": "b6340734fcba86a341b2c29e7930ed30016d19352acd4a015d1e194c415655ac",
"bytes": 6029
},
{
@@ -872,6 +872,11 @@
"sha256": "fa4f78d15225f1d0e3dad8f1cd7283dfbe17b411d5158ade8effb0111ff7efa7",
"bytes": 1072
},
{
"path": "backend/tests/fixtures/controller_artifact_helper_spec_2_1_14.txt",
"sha256": "1da47a3f061ef0b89158c9f646bb7018ce88b81c0687d8b27abe65b74df67fea",
"bytes": 4948
},
{
"path": "backend/tests/test_ai_remediation_planner.py",
"sha256": "784b83960cdff238e0ee25caaf83cfd1cb7c3cfc40976036b28bd256f6626e44",
@@ -922,6 +927,11 @@
"sha256": "447788187bb37bcaac7d99df8fdbe8caa76c0e71acea3c5c8f86faf3972d572d",
"bytes": 16611
},
{
"path": "backend/tests/test_appops_staged_source_recovery.py",
"sha256": "9c420f0d2355edee8232b420f322b60f69b701b68da22213e9207d98ca030611",
"bytes": 13283
},
{
"path": "backend/tests/test_authentik_connector.py",
"sha256": "54b24a90e7238aaed22d0dfbae70d9772006d20cdb9dbd43d781af48892dcd94",
@@ -939,22 +949,22 @@
},
{
"path": "backend/tests/test_controller_artifact_bootstrap.py",
"sha256": "3389f7cc8225ff2f03b46aa79a3a70dae7a6198d1ab52fd0879638bcf4c92f83",
"bytes": 80172
"sha256": "d9acae805eedcf50e90222ce52f3a43ad101e558d7c1b49d4f55968b208e957f",
"bytes": 82161
},
{
"path": "backend/tests/test_controller_artifact_bootstrap_created_child_recovery.py",
"sha256": "a9613e4bad2d66cdf51a840b96674b857b6b82ef125a11345ab9fa2a61735ffd",
"bytes": 21205
"sha256": "8be4fabde7f2092e6b8f98fb35d96055acab207716466a85baf8f844ae1a7869",
"bytes": 21192
},
{
"path": "backend/tests/test_controller_artifact_bootstrap_failed_child_recovery.py",
"sha256": "5da80eed7ef420bee44cec4e20fe45bd4918245c6236a4481aeffe71c939d82f",
"bytes": 18314
"sha256": "7bc8baa74edffb086b4f3dccf9f69184aaf62761a43b57e7912966d786ad32dd",
"bytes": 18295
},
{
"path": "backend/tests/test_controller_artifact_promoter.py",
"sha256": "8eee2bdaf60422824f605637b1820c431fdacea305e1b68b3618fffa0dc000ee",
"sha256": "e1f987217790868228daba95ab564b4fb9e44798a80070e6c1d76d0b1ab6fe0a",
"bytes": 7570
},
{
@@ -994,8 +1004,8 @@
},
{
"path": "backend/tests/test_controller_state_reconciliation.py",
"sha256": "b6b5e82f7818fbfa7cc2faf44dad0aaa23e812fbfa9f09f3e738c80cd74237e1",
"bytes": 11300
"sha256": "bbe33d1faf84f4a230be6d2e2cb65a8d6d81dde4abb91663aac37ef3ef7fe24a",
"bytes": 11387
},
{
"path": "backend/tests/test_deluge_connector.py",
@@ -1084,8 +1094,8 @@
},
{
"path": "backend/tests/test_forge_database_credentials.py",
"sha256": "fdab22c57d546a7a1bd912abc63777ca4a1e03c3826ddcebb9301553130c42a3",
"bytes": 17599
"sha256": "b28732574a2d53891208b6f192f5ce5da51fb3975ae642834d37d3eb489550da",
"bytes": 17826
},
{
"path": "backend/tests/test_forge_first_install_controller.py",
@@ -5,7 +5,7 @@ from typing import Any
SOURCE_REPOSITORY = "jens/unraid-appops-gateway"
HELPER_NAME = "itworx-controller-artifact-promoter-modern"
CONTROLLER_VERSION = "2.1.14"
CONTROLLER_VERSION = "2.1.17"
HELPER_LABEL = "itworx.controller.promoter"
_REVISION = re.compile(r"^[0-9a-f]{40}$")
_IMAGE_ID = re.compile(r"^sha256:[0-9a-f]{64}$")
@@ -0,0 +1,128 @@
from __future__ import annotations
import re
from typing import Any
SOURCE_REPOSITORY = "jens/unraid-appops-gateway"
HELPER_NAME = "itworx-controller-artifact-promoter-modern"
CONTROLLER_VERSION = "2.1.14"
HELPER_LABEL = "itworx.controller.promoter"
_REVISION = re.compile(r"^[0-9a-f]{40}$")
_IMAGE_ID = re.compile(r"^sha256:[0-9a-f]{64}$")
_CONTAINER_ID = re.compile(r"^[0-9a-f]{64}$")
_VERSION = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][0-9A-Za-z.-]+)?$")
def helper_container_spec(
*,
revision: str,
image_id: str,
current_controller_id: str | None = None,
current_controller_revision: str | None = None,
current_controller_tree: str | None = None,
current_controller_version: str | None = None,
) -> dict[str, Any]:
if not _REVISION.fullmatch(revision):
raise ValueError("controller_promoter_revision_invalid")
if not _IMAGE_ID.fullmatch(image_id):
raise ValueError("controller_promoter_image_invalid")
bootstrap_values = (
current_controller_id,
current_controller_revision,
current_controller_tree,
current_controller_version,
)
if any(value is not None for value in bootstrap_values):
if (
not _CONTAINER_ID.fullmatch(current_controller_id or "")
or not _REVISION.fullmatch(current_controller_revision or "")
or not _REVISION.fullmatch(current_controller_tree or "")
or not _VERSION.fullmatch(current_controller_version or "")
):
raise ValueError("controller_promoter_bootstrap_binding_invalid")
command = f"""set -Eeuo pipefail
umask 077
revision='{revision}'
version='{CONTROLLER_VERSION}'
image_id='{image_id}'
repo='/gitea-repositories/jens/unraid-appops-gateway.git'
[[ \"$(stat -c '%a:%u:%g' /tmp)\" == '1777:0:0' ]]
work=\"$(mktemp -d -p /tmp itworx-controller-artifact-promoter-{revision[:12]}.XXXXXX)\"
[[ -d \"$work\" && ! -L \"$work\" && \"$(stat -c '%u:%a' \"$work\")\" == '0:700' ]]
cleanup() {{ rm -rf -- \"$work\"; }}
trap cleanup EXIT
command -v git >/dev/null
command -v docker >/dev/null
docker compose version >/dev/null
command -v python3 >/dev/null
command -v tar >/dev/null
command -v curl >/dev/null
git --git-dir=\"$repo\" cat-file -e \"$revision^{{commit}}\"
tree=\"$(git --git-dir=\"$repo\" rev-parse \"$revision^{{tree}}\")\"
git --git-dir=\"$repo\" archive --format=tar \"$revision\" \\
ops/gitea-deploy-broker \\
scripts/prepare_controller_artifact.py \\
scripts/reconcile_controller_state.py \\
scripts/prepare_controller_hub_release_volume.py \\
scripts/vendor \\
scripts/run_repopulse_adoption.py \
scripts/upgrade_deployment_controller.sh > \"$work/controller.tar\"
chmod 0600 \"$work/controller.tar\"
archive_sha=\"$(sha256sum \"$work/controller.tar\" | cut -d ' ' -f 1)\"
git --git-dir=\"$repo\" show \"$revision:scripts/upgrade_deployment_controller.sh\" > \"$work/upgrade.sh\"
chmod 0700 \"$work/upgrade.sh\"
bash \"$work/upgrade.sh\" \\
--archive \"$work/controller.tar\" \\
--archive-sha256 \"$archive_sha\" \\
--source-repository '{SOURCE_REPOSITORY}' \\
--source-revision \"$revision\" \\
--source-tree \"$tree\" \\
--controller-version \"$version\" \\
--image-id \"$image_id\" \\
--confirm UPGRADE_DEPLOYMENT_CONTROLLER_V2
"""
labels = {
HELPER_LABEL: "true",
"itworx.source.repository": SOURCE_REPOSITORY,
"itworx.source.revision": revision,
"itworx.controller.version": CONTROLLER_VERSION,
}
if current_controller_id is not None:
labels.update(
{
"itworx.controller.bootstrap.target.id": current_controller_id,
"itworx.controller.bootstrap.target.image": image_id,
"itworx.controller.bootstrap.target.revision": current_controller_revision or "",
"itworx.controller.bootstrap.target.tree": current_controller_tree or "",
"itworx.controller.bootstrap.target.version": current_controller_version or "",
}
)
return {
"Image": image_id,
"User": "0:0",
"Cmd": ["/bin/bash", "-lc", command],
"Labels": labels,
"HostConfig": {
"Binds": [
"/mnt/cache:/mnt/cache",
"/mnt/user:/mnt/user",
"/var/lib/docker:/var/lib/docker:ro",
"/srv/example/appdata/gitea/git/repositories:/gitea-repositories:ro",
"/var/run/docker.sock:/var/run/docker.sock",
],
"NetworkMode": "host",
"Privileged": False,
"ReadonlyRootfs": True,
"CpuPeriod": 100000,
"CpuQuota": 100000,
"Memory": 1024 * 1024 * 1024,
"PidsLimit": 128,
"Tmpfs": {"/tmp": "rw,nosuid,nodev,size=268435456,mode=1777"},
"SecurityOpt": ["no-new-privileges:true"],
"RestartPolicy": {"Name": "no"},
},
}
@@ -0,0 +1,225 @@
from __future__ import annotations
import copy
import importlib.util
import os
import sys
from pathlib import Path
from types import SimpleNamespace
import pytest
ROOT = Path(__file__).resolve().parents[2]
BROKER = ROOT / "ops/gitea-deploy-broker"
REPOSITORY = "jens/unraid-appops-gateway"
REVISION = "c" * 40
SOURCE = "/srv/example/appdata/unraid-appops-gateway/source"
@pytest.fixture
def recovery(monkeypatch):
monkeypatch.syspath_prepend(str(BROKER))
if "fcntl" not in sys.modules:
monkeypatch.setitem(sys.modules, "fcntl", SimpleNamespace(LOCK_EX=2, LOCK_UN=8, flock=lambda *_: None))
spec = importlib.util.spec_from_file_location("staged_source_deploy_test", BROKER / "deploy.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
pointer = {"revision": module.APPOPS_LEGACY_OLD_REVISION, "liveRecordSha256": "f" * 64}
active = {"pointer": pointer, "live": {"containerId": "1" * 64,
"runtimeFingerprint": "2" * 64, "sourceFingerprint": "3" * 64}}
snapshot = {"revision": module.APPOPS_LEGACY_OLD_REVISION, "legacy_provenance": True,
"receipt": {}, "appops_runtime_model": pointer, "appops_data_backup": {"safe": True}}
metadata = {"builtAt": "2026-10-09T00:00:00.000Z"}
payload = {"kind": "followup", "repository": REPOSITORY, "revision": REVISION,
"phase": "source_staged", "expectedStateSha256": "4" * 64,
"priorModelPointer": pointer, "priorSnapshot": snapshot, "registryFingerprint": "5" * 64,
"preMutationRuntimeFingerprint": "2" * 64, "preMutationRuntimeSha256": "6" * 64,
"sourceFingerprint": "3" * 64, "metadata": metadata}
pending = {"sha256": "7" * 64, "payload": payload}
identity = {"revision": module.APPOPS_LEGACY_OLD_REVISION, "containerId": "1" * 64,
"runtimeFingerprint": "2" * 64, "runtimeCasSha256": "6" * 64}
state = {"live_status": "healthy"}
facts = {"stateSha": "4" * 64, "registry": "5" * 64, "source": "8" * 64,
"postSource": "3" * 64, "active": active, "identity": identity}
calls = []
reader = SimpleNamespace(
PROJECTS_PATH=Path("registry"),
_self_upgrade_pending_model_transaction=lambda: pending,
_self_upgrade_active_compose_model=lambda *_args, **_kwargs: facts["active"],
_self_upgrade_verify_rollback_model=lambda *_: True,
_self_upgrade_read_fixed_file=lambda *_args, **_kwargs: b"registry",
_self_upgrade_secret=lambda: b"private-key",
_self_upgrade_mac=lambda *_: facts["registry"],
_self_upgrade_model_runtime_identity=lambda *_: facts["identity"],
_self_upgrade_source_fingerprint=lambda *_: facts["source"],
_self_upgrade_source_is_exact_legacy=lambda *_: facts["postSource"],
)
monkeypatch.setattr(module, "require_host_root", lambda: None)
monkeypatch.setattr(module, "_appops_status_reader", lambda: reader)
monkeypatch.setattr(module, "read_appops_state_preimage", lambda _: (state, b"state", facts["stateSha"]))
monkeypatch.setattr(module, "validate_commit", lambda *_: REVISION)
monkeypatch.setattr(module, "deployment_metadata", lambda *_args, **_kwargs: metadata)
monkeypatch.setattr(module, "verify_appops_data_backup", lambda *_: calls.append("backup-verified"))
monkeypatch.setattr(module, "_verify_appops_staged_source", lambda *_: calls.append("candidate-verified"))
monkeypatch.setattr(module, "_appops_source_untracked_fingerprint", lambda *_: "9" * 64)
monkeypatch.setattr(module, "tracked_files", lambda *_: [])
monkeypatch.setattr(module, "write_source_metadata", lambda *_: None)
monkeypatch.setattr(module, "sync_source", lambda _repo, _revision, _root, _slug, paths, **_kwargs: calls.append(("restore", copy.deepcopy(paths))))
monkeypatch.setattr(module, "inspect_container", lambda _: {"Id": "1" * 64})
monkeypatch.setattr(module, "_appops_update_model_transaction", lambda _project, phase, bindings: calls.append((phase, bindings)))
project = {"slug": "unraid-appops-gateway", "source_dir": SOURCE, "clean_untracked_paths": ["backend"]}
return module, project, pending, facts, calls, reader
def test_signed_staged_source_restores_without_runtime_or_state_writes(recovery):
module, project, pending, _facts, calls, _reader = recovery
_, fingerprint = module.inspect_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION)
result = module.resume_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION, fingerprint)
assert result["status"] == "source-restored"
phases = [item[0] for item in calls if isinstance(item, tuple)]
assert phases == ["rolling_back", "restore", "rolled_back"]
restored = next(item[1] for item in calls if isinstance(item, tuple) and item[0] == "restore")
assert restored == []
assert project["clean_untracked_paths"] == ["backend"]
assert calls[-1][1] == {"restoredLiveReference": pending["payload"]["priorModelPointer"]}
@pytest.mark.parametrize("drift", ["target", "kind", "revision", "phase", "imageSeal", "state", "registry",
"container", "runtime", "runtimeCas", "priorModel", "sourceAuthority", "sourceUnsafe"])
def test_staged_source_recovery_rejects_drift_before_any_write(recovery, drift):
module, project, pending, facts, calls, _reader = recovery
payload = pending["payload"]
if drift == "target":
project["source_dir"] = "/other"
elif drift in {"kind", "revision", "phase"}:
payload[drift] = "foreign"
elif drift == "imageSeal":
payload["candidateImageId"] = "sha256:" + "a" * 64
elif drift in {"state", "registry"}:
facts["stateSha" if drift == "state" else "registry"] = "a" * 64
elif drift in {"container", "runtime", "runtimeCas"}:
facts["identity"][{"container": "containerId", "runtime": "runtimeFingerprint", "runtimeCas": "runtimeCasSha256"}[drift]] = "a" * 64
elif drift == "priorModel":
payload["priorModelPointer"] = {"foreign": True}
elif drift == "sourceAuthority":
payload["sourceFingerprint"] = "a" * 64
else:
facts["source"] = None
with pytest.raises(module.DeployError):
module.inspect_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION)
assert not any(isinstance(item, tuple) for item in calls)
def test_source_rollback_requires_fresh_preflight(recovery):
module, project, _pending, _facts, calls, _reader = recovery
with pytest.raises(module.DeployError, match="preflight changed"):
module.resume_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION, "0" * 64)
assert not any(isinstance(item, tuple) for item in calls)
def test_source_rollback_never_seals_failed_source_restoration(recovery):
module, project, _pending, facts, calls, _reader = recovery
_, fingerprint = module.inspect_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION)
facts["postSource"] = "0" * 64
with pytest.raises(module.DeployError, match="signed unchanged preimage"):
module.resume_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION, fingerprint)
assert not any(isinstance(item, tuple) and item[0] == "rolled_back" for item in calls)
def test_source_rollback_reconciles_crash_after_exact_source_restore(recovery):
module, project, pending, facts, calls, _reader = recovery
pending["payload"].update(phase="rolling_back", failureCode="staged_source_restore", sourceRestoreIntent={"safe": True})
facts["source"] = "3" * 64
_, fingerprint = module.inspect_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION)
module.resume_appops_staged_source_rollback(project, REPOSITORY, Path("git"), REVISION, fingerprint)
assert "candidate-verified" not in calls
assert [item[0] for item in calls if isinstance(item, tuple)] == ["restore", "rolled_back"]
def test_staged_source_verifier_rejects_edited_tracked_file_and_unknown_files(recovery, monkeypatch, tmp_path):
_module, _project, _pending, _facts, _calls, _reader = recovery
# Restore the real verifier instead of the orchestration fixture adapter.
spec = importlib.util.spec_from_file_location("staged_source_real_verifier", BROKER / "deploy.py")
real = importlib.util.module_from_spec(spec)
spec.loader.exec_module(real)
source = tmp_path / "source"
(source / ".gitea-deploy").mkdir(parents=True)
(source / ".gitea-deploy/revision").write_text(REVISION + "\n")
(source / ".gitea-deploy/tracked-files.txt").write_text("tracked.py\n")
(source / "tracked.py").write_bytes(b"committed")
def extract(_repo, _revision, target):
(target / "tracked.py").write_bytes(b"committed")
monkeypatch.setattr(real, "tracked_files", lambda *_: ["tracked.py"])
monkeypatch.setattr(real, "extract_revision", extract)
project = {"source_dir": str(source)}
real._verify_appops_staged_source(Path("git"), project, REVISION)
(source / "tracked.py").write_bytes(b"altered!!")
with pytest.raises(real.DeployError, match="committed source changed"):
real._verify_appops_staged_source(Path("git"), project, REVISION)
(source / "tracked.py").write_bytes(b"committed")
(source / "unknown.txt").write_bytes(b"foreign")
with pytest.raises(real.DeployError, match="unknown file"):
real._verify_appops_staged_source(Path("git"), project, REVISION)
def test_controller_promotion_holds_nonblocking_production_lock_before_stop():
script = (ROOT / "scripts/upgrade_deployment_controller.sh").read_text()
assert script.index('flock -n -x "$deployment_lock_fd"') < script.index('"${work}/${PREPARER_NAME}" prepare')
assert script.index('flock -n -x "$deployment_lock_fd"') < script.index('"${work}/${PREPARER_NAME}" ensure')
assert script.index('flock -n -x "$promotion_lock_fd"') < script.index('"${work}/${PREPARER_NAME}" ensure')
assert script.index('flock -n -x "$deployment_lock_fd"') < script.index('stop --backup "$backup"')
assert "production deployment is active; controller promotion refused" in script
@pytest.mark.skipif(os.name == "nt" or getattr(os, "geteuid", lambda: -1)() != 0,
reason="real controller manifest ownership requires root POSIX validation")
@pytest.mark.parametrize("interruption", ["after_delete", "during_extract", "between_manifests", "foreign_bytes", "foreign_file"])
def test_partial_own_source_restore_accepts_only_known_git_states(recovery, monkeypatch, tmp_path, interruption):
module, _project, _pending, _facts, _calls, reader = recovery
root = tmp_path / "source"
root.mkdir()
(root / ".gitea-deploy").mkdir()
candidate = {"same.py": b"candidate contents", "candidate-only.py": b"candidate only"}
old = {"same.py": b"old contents", "old-only.py": b"old only"}
candidate_files, old_files = sorted(candidate), sorted(old)
def files(_repo, revision):
return candidate_files if revision == REVISION else old_files
def extract(_repo, revision, target):
for name, raw in (candidate if revision == REVISION else old).items():
(target / name).write_bytes(raw)
(target / name).chmod(0o644)
monkeypatch.setattr(module, "tracked_files", files)
monkeypatch.setattr(module, "extract_revision", extract)
extract(Path("git"), REVISION, root)
manifests = root / ".gitea-deploy"
(manifests / "revision").write_text(REVISION + "\n")
(manifests / "tracked-files.txt").write_text("\n".join(candidate_files) + "\n")
for path in manifests.iterdir():
path.chmod(0o644)
os.chown(path, 100, 101)
(root / "candidate-only.py").unlink()
if interruption == "during_extract":
(root / "same.py").write_bytes(b"old con")
elif interruption == "between_manifests":
(root / "same.py").write_bytes(old["same.py"])
(root / "old-only.py").write_bytes(old["old-only.py"])
(manifests / "tracked-files.txt").write_text("old-on")
elif interruption == "foreign_bytes":
(root / "same.py").write_bytes(b"foreign mutation")
elif interruption == "foreign_file":
(root / "extra.py").write_bytes(b"unknown")
intent = {"trackedOwners": {name: [0, 0] for name in candidate_files}, "untrackedFingerprint": "9" * 64}
args = (Path("git"), {"source_dir": str(root)}, REVISION, intent, reader, b"private-key")
if interruption.startswith("foreign"):
with pytest.raises(module.DeployError):
module._verify_appops_partial_source_restore(*args)
else:
module._verify_appops_partial_source_restore(*args)
def test_partial_source_restore_rejects_untracked_secret_drift(recovery, monkeypatch):
module, project, _pending, _facts, _calls, reader = recovery
monkeypatch.setattr(module, "_appops_source_untracked_fingerprint", lambda *_: "a" * 64)
with pytest.raises(module.DeployError, match="untracked files changed"):
module._verify_appops_partial_source_restore(Path("git"), project, REVISION,
{"untrackedFingerprint": "9" * 64}, reader, b"private-key")
@@ -37,6 +37,7 @@ CALLER_ID = "c" * 64
MODERN_HELPER_ID = "f" * 64
RETIRED_HELPER_ID = bootstrap.RETIRED_FAILED_MODERN_HELPER_ID
HOST_HOSTNAME = "Tower"
RETIRED_MODERN_HELPER_SOURCE = (ROOT / "backend/tests/fixtures/controller_artifact_helper_spec_2_1_14.txt").read_text(encoding="utf-8")
LEGACY_HELPER_SOURCE_FIXTURE = '''
@@ -570,6 +571,8 @@ class FakeProtectedGit:
self.blobs_read.append((revision, path))
if revision not in {self.revision, bootstrap.RETIRED_FAILED_MODERN_REVISION} or path != "backend/app/services/controller_artifact_helper_spec.py":
raise bootstrap.BootstrapError("controller_promoter_source_blob_invalid")
if revision == bootstrap.RETIRED_FAILED_MODERN_REVISION:
return RETIRED_MODERN_HELPER_SOURCE.encode("utf-8")
return self.helper_source.encode("utf-8")
def read_legacy_blob(self, revision: str, path: str) -> bytes:
@@ -586,7 +589,7 @@ def _health(
*,
revision: str = REVISION,
tree: str = TREE,
version: str = "2.1.14",
version: str = "2.1.17",
artifact_sha256: str = "1" * 64,
) -> dict[str, Any]:
return {
@@ -829,15 +832,16 @@ def test_controller_source_provenance_failure_precedes_health_and_side_effects()
assert docker.started == []
def _retired_failed_child(helper_source: str) -> dict[str, Any]:
def _retired_failed_child() -> dict[str, Any]:
spec = bootstrap.render_modern_helper_spec(
helper_source,
RETIRED_MODERN_HELPER_SOURCE,
revision=bootstrap.RETIRED_FAILED_MODERN_REVISION,
image_id=CONTROLLER_IMAGE_ID,
current_controller_id=CONTROLLER_CONTAINER_ID,
current_controller_revision=CONTROLLER_REVISION,
current_controller_tree=CONTROLLER_TREE,
current_controller_version="2.1.12",
helper_version="2.1.14",
)
child = _inspect_from_spec(
"itworx-controller-artifact-promoter-modern",
@@ -1295,7 +1299,7 @@ def test_exact_failed_historical_child_is_removed_before_current_helper_launch()
version="2.1.12",
artifact_sha256=bootstrap.LEGACY_CONTROLLER_ARTIFACT_SHA256,
)
failed_child = _retired_failed_child(helper_source)
failed_child = _retired_failed_child()
docker = FakeDocker(_legacy_helper_spec(), existing_child=failed_child)
git = FakeProtectedGit(helper_source)
@@ -1343,7 +1347,7 @@ def test_current_214_baseline_is_verified_and_bound_to_new_helper():
"itworx.controller.promoter": "true",
"itworx.source.repository": "jens/unraid-appops-gateway",
"itworx.source.revision": REVISION,
"itworx.controller.version": "2.1.14",
"itworx.controller.version": "2.1.17",
"itworx.controller.bootstrap.target.id": MODERN_CONTROLLER_CONTAINER_ID,
"itworx.controller.bootstrap.target.image": CONTROLLER_IMAGE_ID,
"itworx.controller.bootstrap.target.revision": MODERN_CONTROLLER_REVISION,
@@ -1356,7 +1360,7 @@ def test_retired_failed_child_is_removed_only_after_current_214_profile_rechecks
helper_source = (ROOT / "backend/app/services/controller_artifact_helper_spec.py").read_text(
encoding="utf-8"
)
failed_child = _retired_failed_child(helper_source)
failed_child = _retired_failed_child()
docker = FakeDocker(_legacy_helper_spec(), existing_child=failed_child)
docker.containers["gitea-deploy-control"] = _modern_controller_source_inspect(
MODERN_CONTROLLER_REVISION
@@ -1417,7 +1421,7 @@ def test_retired_cleanup_refuses_any_current_214_identity_or_topology_drift(muta
helper_source = (ROOT / "backend/app/services/controller_artifact_helper_spec.py").read_text(
encoding="utf-8"
)
failed_child = _retired_failed_child(helper_source)
failed_child = _retired_failed_child()
docker = FakeDocker(_legacy_helper_spec(), existing_child=failed_child)
controller = _modern_controller_source_inspect(MODERN_CONTROLLER_REVISION)
health = _modern_baseline_health()
@@ -1515,7 +1519,7 @@ def test_retired_helper_cleanup_fails_closed_on_any_identity_or_state_drift(muta
helper_source = (ROOT / "backend/app/services/controller_artifact_helper_spec.py").read_text(
encoding="utf-8"
)
failed_child = _retired_failed_child(helper_source)
failed_child = _retired_failed_child()
docker = FakeDocker(_legacy_helper_spec(), existing_child=failed_child)
git = FakeProtectedGit(helper_source)
if mutation == "running":
@@ -1614,7 +1618,7 @@ def test_same_failed_source_revision_is_never_retried_or_removed():
)
docker = FakeDocker(
_legacy_helper_spec(bootstrap.RETIRED_FAILED_MODERN_REVISION),
existing_child=_retired_failed_child(helper_source),
existing_child=_retired_failed_child(),
)
git = FakeProtectedGit(helper_source)
git.revision = bootstrap.RETIRED_FAILED_MODERN_REVISION
@@ -1626,16 +1630,14 @@ def test_same_failed_source_revision_is_never_retried_or_removed():
artifact_sha256=bootstrap.LEGACY_CONTROLLER_ARTIFACT_SHA256,
)
result = _run_bootstrap(
docker,
git,
health_sequence=[legacy_health],
source_revision=git.revision,
source_tree=git.tree,
)
assert result["status"] == "failed"
assert result["exitCode"] == 1
with pytest.raises(bootstrap.BootstrapError, match="controller_promoter_retired_helper_retry_refused"):
_run_bootstrap(
docker,
git,
health_sequence=[legacy_health],
source_revision=git.revision,
source_tree=git.tree,
)
assert docker.removed == []
assert docker.created == []
@@ -1824,7 +1826,7 @@ def test_successful_child_requires_exact_source_tree_version_and_health():
assert result["status"] == "promoted"
assert result["revision"] == REVISION
assert result["controllerVersion"] == "2.1.14"
assert result["controllerVersion"] == "2.1.17"
assert result["artifactSha256"] == "1" * 64
assert docker.started == [MODERN_HELPER_ID]
assert docker.created[0]["Image"] == CONTROLLER_IMAGE_ID
@@ -2079,3 +2081,29 @@ def test_modern_upgrade_path_still_requires_private_archive_and_image_id(
assert "archive is outside the helper private temporary directory" in result.stderr
if modern_call == "missing-image":
assert "image ID" in result.stderr
def test_current_helper_version_is_distinct_from_fixed_controller_baselines():
source = (ROOT / "backend/app/services/controller_artifact_helper_spec.py").read_bytes()
namespace = bootstrap._safe_modern_spec_namespace(source)
assert namespace["CONTROLLER_VERSION"] == "2.1.17"
assert bootstrap._verified_historical_helper_version(source) == "2.1.17"
assert [baseline.version for baseline in bootstrap.CONTROLLER_BASELINES] == ["2.1.12", "2.1.14"]
with pytest.raises(bootstrap.BootstrapError, match="controller_promoter_modern_spec_identity_invalid"):
bootstrap._safe_modern_spec_namespace(RETIRED_MODERN_HELPER_SOURCE.encode("utf-8"))
assert bootstrap._verified_historical_helper_version(RETIRED_MODERN_HELPER_SOURCE.encode("utf-8")) == "2.1.14"
@pytest.mark.parametrize("version", ["2.1.16", "2.1.18", "9.9.9"])
def test_current_and_historical_helper_reject_unreviewed_target_versions(version):
source = (ROOT / "backend/app/services/controller_artifact_helper_spec.py").read_bytes()
foreign = source.replace(b'CONTROLLER_VERSION = "2.1.17"', f'CONTROLLER_VERSION = "{version}"'.encode())
with pytest.raises(bootstrap.BootstrapError, match="controller_promoter_modern_spec_identity_invalid"):
bootstrap._safe_modern_spec_namespace(foreign)
with pytest.raises(bootstrap.BootstrapError, match="controller_promoter_modern_spec_identity_invalid"):
bootstrap._verified_historical_helper_version(foreign)
@pytest.mark.parametrize("version", ["2.1.14", "2.1.16", "2.1.18"])
def test_promoted_health_cannot_substitute_a_baseline_or_unknown_version(version):
assert not bootstrap._health_matches(_health(version=version), REVISION, TREE)
@@ -173,7 +173,7 @@ def _inputs(*, current_child: bool) -> tuple[Docker, Git, dict[str, Any], str]:
current_controller_tree=baseline.tree,
current_controller_version=baseline.version,
)
child = original._retired_failed_child(helper_source)
child = original._retired_failed_child()
child["Id"] = child_id
child["Image"] = baseline.image_id
child["State"] = _created_state()
@@ -48,7 +48,7 @@ class Docker(original.FakeDocker):
def inputs():
source = (original.ROOT / bootstrap.MODERN_HELPER_SOURCE_PATH).read_text()
child = original._retired_failed_child(source)
child = original._retired_failed_child()
baseline = bootstrap.MODERN_CONTROLLER_BASELINE
spec = bootstrap.render_modern_helper_spec(
source,
@@ -212,7 +212,7 @@ def historical_inputs():
helper_source = (
original.ROOT / "backend/app/services/controller_artifact_helper_spec.py"
).read_text(encoding="utf-8")
child = original._retired_failed_child(helper_source)
child = original._retired_failed_child()
docker = original.FakeDocker(
original._legacy_helper_spec(), existing_child=child
)
@@ -46,7 +46,7 @@ def test_controller_promoter_helper_spec_is_fixed_and_bounded():
spec = helper_container_spec(revision=revision, image_id=image_id)
assert HELPER_NAME == "itworx-controller-artifact-promoter-modern"
assert CONTROLLER_VERSION == "2.1.14"
assert CONTROLLER_VERSION == "2.1.17"
assert re.fullmatch(r"2\.1\.\d+", CONTROLLER_VERSION)
assert spec["Image"] == image_id
assert spec["HostConfig"]["Privileged"] is False
@@ -79,7 +79,7 @@ def test_controller_promoter_helper_spec_is_fixed_and_bounded():
assert revision in command
assert "--image-id" in command
assert CONTROLLER_VERSION in command
assert "version='2.1.14'" in command
assert "version='2.1.17'" in command
assert "/gitea-repositories/jens/unraid-appops-gateway.git" in command
archive_start = command.index('git --git-dir="$repo" archive')
archive_end = command.index('> "$work/controller.tar"', archive_start)
@@ -110,7 +110,7 @@ def test_controller_promoter_bootstrap_child_spec_binds_legacy_target_identity()
"itworx.controller.promoter": "true",
"itworx.source.repository": "jens/unraid-appops-gateway",
"itworx.source.revision": revision,
"itworx.controller.version": "2.1.14",
"itworx.controller.version": "2.1.17",
"itworx.controller.bootstrap.target.id": target_id,
"itworx.controller.bootstrap.target.image": image_id,
"itworx.controller.bootstrap.target.revision": target_revision,
@@ -197,7 +197,8 @@ def test_upgrade_prepares_before_stop_and_reconciles_between_stop_and_activation
assert script.index(prepare) < script.index(stop)
assert script.index(stop) < script.index(reconcile)
assert script.index(reconcile) < script.index(activate)
assert 'flock -x "$promotion_lock_fd"' in script
assert 'flock -n -x "$promotion_lock_fd"' in script
assert script.index('flock -n -x "$promotion_lock_fd"') < script.index(prepare)
assert 'mv -- "$CONTROLLER_DIR"' not in script
assert 'cp -a -- "$CONTROLLER_DIR"' not in script
@@ -95,6 +95,7 @@ def _install_fake_docker(
"if behavior == 'echo-received':\n"
" os.write(2, first.encode() + b'\\n')\n"
"if behavior == 'exit-after-first':\n"
" open(marker, 'a').write('first-input-validated\\n')\n"
" raise SystemExit(8)\n"
"os.write(2, b'Enter it again: ')\n"
"second = sys.stdin.readline().rstrip('\\r\\n')\n"
@@ -288,7 +289,8 @@ def test_any_password_input_without_success_becomes_unknown(
states, calls, journal = _journal(
{module.RUNTIME_ROLE: "pending", module.MIGRATOR_ROLE: "pending"}
)
monkeypatch.setattr(module, "PROMPT_TIMEOUT_SECONDS", 0.15)
# Prove the post-input branch, rather than timing out Python startup under load.
monkeypatch.setattr(module, "PROMPT_TIMEOUT_SECONDS", 2.0)
monkeypatch.setattr(module, "REMOTE_TIMEOUT_SECONDS", 1)
monkeypatch.setattr(module, "REMOTE_KILL_AFTER_SECONDS", 1)
monkeypatch.setattr(module, "REMOTE_TERMINATION_MARGIN_SECONDS", 0.1)
@@ -296,6 +298,7 @@ def test_any_password_input_without_success_becomes_unknown(
result = _run(module, tmp_path, journal)
assert marker.read_text(encoding="utf-8") == "first-input-validated\n"
assert result["status"] == "outcome_unknown"
assert result["reason"] == "psql_result_uncertain"
assert states[module.RUNTIME_ROLE] == "unknown"