Publish curated Unraid-AppOps-Gateway source from ba66029223865607deddc234e283c11127324eb8

This commit is contained in:
Public Source Publisher committed 2026-10-07 01:56:22 +00:00
1 parent 820244dbb3
commit 8dd4b40252
52 files changed
+11814 -288

No files matched your search

@@ -26,6 +26,7 @@ import fcntl
import json
import os
from pathlib import Path
import re
import stat
import subprocess
import sys
@@ -36,6 +37,8 @@ host_path = Path("/controller-hub-releases/controller-config/projects.json")
lock_path = Path("/mnt/cache/appdata/gitea-deploy-runners/deploy.lock")
repository, revision, branch, raw_project = sys.argv[1:5]
project = json.loads(raw_project)
requested_project = project
strengthening_deadline = time.monotonic() + 20
def _validation_compatible(repository, validation):
expected_validation = {
@@ -58,6 +61,52 @@ def _validation_compatible(repository, validation):
"contexts": ["CI / gates (push)", "Managed validation / full (push)"],
}
def _source_verified_strengthening():
# Only an exact protected-main descriptor can strengthen an existing target.
# The controller reader uses fixed credential files and private stdin.
if branch != "main" or time.monotonic() >= strengthening_deadline:
return False
try:
fresh = git_run("rev-parse", "refs/heads/main")
if fresh.returncode or fresh.stdout.strip() != revision:
return False
result = git_run("show", f"{revision}:.itworx/deployment-target.json")
if result.returncode or len(result.stdout.encode("utf-8")) > 16384:
return False
def unique(pairs):
value = {}
for key, item in pairs:
if key in value:
raise ValueError("duplicate descriptor field")
value[key] = item
return value
descriptor = json.loads(result.stdout, object_pairs_hook=unique)
allowed = {"apiVersion", "applicationId", "composeFile", "composeProject",
"healthTimeout", "primaryService", "verifyOciRevision"}
if (not isinstance(descriptor, dict) or set(descriptor) - allowed
or descriptor.get("apiVersion") != "itworx.deployment-target/v1"
or descriptor.get("verifyOciRevision") is not True
or descriptor.get("composeFile") != compose_file
or descriptor.get("composeProject", descriptor.get("applicationId")) != requested_project["compose_project"]
or type(descriptor.get("healthTimeout", 180)) is not int
or descriptor.get("healthTimeout", 180) != requested_project["health_timeout"]
or not isinstance(descriptor.get("applicationId"), str)
or not re.fullmatch(r"[a-z0-9][a-z0-9-]{0,62}", descriptor["applicationId"])
or not isinstance(descriptor.get("primaryService", descriptor["applicationId"]), str)
or not re.fullmatch(r"[a-z0-9][a-z0-9-]{0,62}", descriptor.get("primaryService", descriptor["applicationId"]))):
return False
sys.path.insert(0, "/opt/gitea-deploy")
from status_server import _registered_legacy_api_reader
protected = _registered_legacy_api_reader(repository)(
f"/repos/{repository}/branches/main", query={},
)
return (time.monotonic() < strengthening_deadline
and isinstance(protected, dict) and protected.get("protected") is True
and isinstance(protected.get("commit"), dict)
and protected["commit"].get("id") == revision)
except Exception:
return False
for directory in (path.parent, host_path.parent, host_path.parent.parent):
info = directory.lstat()
if not stat.S_ISDIR(info.st_mode) or info.st_uid != 0 or info.st_mode & 0o022:
@@ -89,8 +138,16 @@ if not bare_repo.is_dir():
raise SystemExit(24)
def git_run(*args):
# Trust only this validated controller-owned mount, preserving Git's normal
# checks elsewhere. Always read original objects rather than replacement refs.
for directory in (bare_repo.parent.parent, bare_repo.parent, bare_repo):
info = directory.lstat()
if (not stat.S_ISDIR(info.st_mode) or info.st_uid not in {0, 1000}
or info.st_mode & 0o022):
raise ValueError("unsafe mounted repository")
return subprocess.run(
["git", f"--git-dir={bare_repo}", *args],
["git", "--no-replace-objects", "-c", f"safe.directory={bare_repo}",
f"--git-dir={bare_repo}", *args],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
@@ -168,12 +225,34 @@ with lock_handle as lock:
"gitea_repository_id",
"gitea_webhook_secret_file",
"validation",
"legacy_containers",
}
extra_keys = set(current) - set(project)
if not extra_keys.issubset(allowed_extra_keys):
raise SystemExit(23)
canonical_current = {key: current.get(key) for key in project}
if canonical_current != project:
immutable_keys = set(project) - {"source_dir", "exact_source", "verify_oci_revision", "health_timeout"}
if any(current.get(key) != project[key] for key in immutable_keys):
raise SystemExit(23)
# Preserve the registered source mode and fixed historical appdata path.
# Registration must never silently migrate an existing runtime's source.
source = current.get("source_dir")
known_sources = {project["source_dir"], f"/srv/example/appdata/{project['slug']}/source"}
exact_source = current.get("exact_source", False)
verification = current.get("verify_oci_revision", False)
health_timeout = current.get("health_timeout", 180)
if (not isinstance(source, str) or source not in known_sources or type(exact_source) is not bool
or type(verification) is not bool or type(project["verify_oci_revision"]) is not bool
or type(health_timeout) is not int or health_timeout != project["health_timeout"]
or verification and project["verify_oci_revision"] is not True):
raise SystemExit(23)
legacy_containers = current.get("legacy_containers")
if legacy_containers is not None and (
not isinstance(legacy_containers, list) or len(legacy_containers) > 32
or any(not isinstance(name, str) or not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,127}", name)
for name in legacy_containers)
or len(set(legacy_containers)) != len(legacy_containers)
or set(legacy_containers).intersection(project["containers"])
):
raise SystemExit(23)
env_source = current.get("env_source")
if env_source is not None:
@@ -222,6 +301,15 @@ with lock_handle as lock:
if not _validation_compatible(repository, validation):
raise SystemExit(23)
strengthened = not verification and project["verify_oci_revision"] is True
if strengthened and not _source_verified_strengthening():
raise SystemExit(39)
reconciled = dict(current)
if strengthened:
reconciled["verify_oci_revision"] = True
changed = reconciled != current
project = reconciled
if changed:
try:
backup_root = Path("/mnt/cache/appdata/gitea-deploy-runners/state/registry-backups")
@@ -266,11 +354,17 @@ with lock_handle as lock:
raise SystemExit(33)
try:
if current is not None and strengthened and not _source_verified_strengthening():
temporary.unlink(missing_ok=True)
raise SystemExit(39)
latest = mutation_path.lstat()
latest_identity = (latest.st_dev, latest.st_ino, latest.st_mode, latest.st_uid,
latest.st_gid, latest.st_mtime_ns, latest.st_ctime_ns, latest.st_size)
if latest_identity != registry_identity or mutation_path.read_bytes() != original or not os.path.samefile(path, mutation_path):
raise SystemExit(34)
if current is not None and strengthened and time.monotonic() >= strengthening_deadline:
temporary.unlink(missing_ok=True)
raise SystemExit(39)
os.replace(temporary, mutation_path)
except Exception:
try:
@@ -429,6 +523,8 @@ class DeploymentTargetRegistry:
verify_oci_revision: bool = False,
) -> dict[str, Any]:
try:
if type(verify_oci_revision) is not bool:
raise ValueError("OCI revision verification must be a boolean")
(
repository,
revision,
@@ -561,6 +657,7 @@ class DeploymentTargetRegistry:
36: "deployment projects registry host alias is unavailable or does not match the controller registry",
37: "controller project branch does not match the requested default branch",
38: "controller project Compose contract is invalid",
39: "existing target verification strengthening requires its exact protected-main source descriptor",
}
if exit_code in preflight_reasons:
return {