Publish curated Unraid-AppOps-Gateway source from ba66029223865607deddc234e283c11127324eb8
This commit is contained in:
1 parent
820244dbb3
commit
8dd4b40252
52 files changed
+11814
-288
No files matched your search
@@ -15,6 +15,7 @@ import secrets
|
||||
import uuid
|
||||
from typing import Any, Literal
|
||||
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from ..connectors.authentik import AuthentikConnector
|
||||
@@ -46,6 +47,20 @@ _CONTROLLER_EVIDENCE = {"status", "targetId", "repository", "applicationId", "ap
|
||||
_PROXY_EVIDENCE = {"success", "status", "hostId", "hostname"}
|
||||
_OIDC_EVIDENCE = {"success", "status", "applicationId", "providerId", "clientSecretCreated"}
|
||||
_APPDATA_ROOT_STATUSES = {"ready", "needs_initialization", "unavailable"}
|
||||
_CAPABILITY_REASON = re.compile(r"^[a-z][a-z0-9_]{0,79}$")
|
||||
_RUNTIME_SECURITY_FEATURES = ("exactTargetPolicy", "hmacV2", "replayProtection")
|
||||
|
||||
|
||||
def _safe_capability_reason(value: object) -> str:
|
||||
reason = str(value or "")
|
||||
return reason if _CAPABILITY_REASON.fullmatch(reason) else ""
|
||||
|
||||
|
||||
def _features_ready(features: object, names: tuple[str, ...]) -> bool:
|
||||
return bool(
|
||||
isinstance(features, dict)
|
||||
and all(features.get(name) is True for name in names)
|
||||
)
|
||||
|
||||
|
||||
def _trusted_appdata_roots_readiness(
|
||||
@@ -57,7 +72,7 @@ def _trusted_appdata_roots_readiness(
|
||||
if isinstance(reported, list):
|
||||
if len(reported) != len(roots):
|
||||
return [{"root": root, "status": unavailable[root]} for root in roots]
|
||||
statuses: dict[str, str] = {}
|
||||
statuses: dict[str, dict[str, str]] = {}
|
||||
for item in reported:
|
||||
if not isinstance(item, dict):
|
||||
return [{"root": root, "status": unavailable[root]} for root in roots]
|
||||
@@ -71,10 +86,14 @@ def _trusted_appdata_roots_readiness(
|
||||
or status not in _APPDATA_ROOT_STATUSES
|
||||
):
|
||||
return [{"root": expected, "status": unavailable[expected]} for expected in roots]
|
||||
statuses[root] = status
|
||||
value = {"root": root, "status": status}
|
||||
reason = _safe_capability_reason(item.get("reason"))
|
||||
if reason:
|
||||
value["reason"] = reason
|
||||
statuses[root] = value
|
||||
if set(statuses) != set(roots):
|
||||
return [{"root": root, "status": unavailable[root]} for root in roots]
|
||||
return [{"root": root, "status": statuses[root]} for root in roots]
|
||||
return [statuses[root] for root in roots]
|
||||
|
||||
# A legacy V1 controller reports only its configured root. It cannot attest
|
||||
# independent managed-volume readiness, so only its exact legacy root can
|
||||
@@ -224,11 +243,40 @@ class EnrollmentPlane:
|
||||
controller_root_matches = bool(selected_root and selected_root.get("status") == "ready")
|
||||
else:
|
||||
controller_root_matches = False
|
||||
broker_ready = bool(
|
||||
controller_core_ready = bool(
|
||||
bootstrap
|
||||
and self.broker.is_configured()
|
||||
and controller_capability.get("status") == "ready"
|
||||
)
|
||||
features = controller_capability.get("features")
|
||||
runtime_security_ready = _features_ready(features, _RUNTIME_SECURITY_FEATURES)
|
||||
apply_ready = bool(
|
||||
controller_core_ready
|
||||
and runtime_security_ready
|
||||
and isinstance(features, dict)
|
||||
and features.get("deploymentApply") is True
|
||||
)
|
||||
verify_ready = bool(
|
||||
controller_core_ready
|
||||
and runtime_security_ready
|
||||
and isinstance(features, dict)
|
||||
and features.get("deploymentVerify") is True
|
||||
)
|
||||
rollback_ready = bool(
|
||||
controller_core_ready
|
||||
and runtime_security_ready
|
||||
and isinstance(features, dict)
|
||||
and features.get("rollback") is True
|
||||
)
|
||||
runtime_deployment_ready = apply_ready and verify_ready
|
||||
enrollment_features_ready = _features_ready(
|
||||
features,
|
||||
("enrollment", "targetRegistration", "runtimeSecretSealing"),
|
||||
)
|
||||
target_enrollment_ready = bool(
|
||||
controller_core_ready
|
||||
and controller_root_matches
|
||||
and enrollment_features_ready
|
||||
)
|
||||
controller_managed_storage = controller_capability.get("managedStorage")
|
||||
if not isinstance(controller_managed_storage, dict):
|
||||
@@ -248,6 +296,41 @@ class EnrollmentPlane:
|
||||
else:
|
||||
managed_storage_status = "unavailable"
|
||||
managed_storage_blocker = "managed_appdata_volume_unavailable"
|
||||
controller_roots_by_path = {
|
||||
str(item.get("root") or ""): item
|
||||
for item in available_roots
|
||||
if isinstance(item, dict)
|
||||
}
|
||||
selected_root_readiness = (
|
||||
controller_roots_by_path.get(trust.trusted_appdata_root)
|
||||
if trust is not None
|
||||
else None
|
||||
)
|
||||
controller_enrollment = controller_capability.get("enrollmentReadiness")
|
||||
if not isinstance(controller_enrollment, dict):
|
||||
controller_enrollment = {}
|
||||
root_reason = _safe_capability_reason(
|
||||
selected_root_readiness.get("reason")
|
||||
if isinstance(selected_root_readiness, dict)
|
||||
else None
|
||||
)
|
||||
if not root_reason and trust is not None and trust.trusted_appdata_root == MANAGED_DOCKER_APPDATA_ROOT:
|
||||
root_reason = _safe_capability_reason(controller_managed_storage.get("reason"))
|
||||
enrollment_reason = (
|
||||
root_reason
|
||||
or _safe_capability_reason(controller_enrollment.get("reason"))
|
||||
or (
|
||||
"enrollment_trust_not_configured"
|
||||
if trust is None
|
||||
else "trusted_appdata_root_unavailable"
|
||||
if not controller_root_matches
|
||||
else "controller_enrollment_feature_unavailable"
|
||||
if not enrollment_features_ready
|
||||
else "deployment_executor_unavailable"
|
||||
)
|
||||
)
|
||||
if target_enrollment_ready:
|
||||
enrollment_reason = ""
|
||||
npm_ready = self.npm.is_configured()
|
||||
oidc_configured = bool(
|
||||
trust
|
||||
@@ -262,18 +345,44 @@ class EnrollmentPlane:
|
||||
def item(ready: bool, code: str) -> dict[str, str]:
|
||||
return {"status": "ready" if ready else "unavailable", "blockerCode": "" if ready else code}
|
||||
|
||||
if not controller_core_ready:
|
||||
enrollment_blocker = "deployment_executor_unavailable"
|
||||
elif not controller_root_matches:
|
||||
enrollment_blocker = "trusted_appdata_root_unavailable"
|
||||
else:
|
||||
enrollment_blocker = "controller_enrollment_feature_unavailable"
|
||||
registry_report = controller_capability.get("registry")
|
||||
registry_projection: dict[str, Any] = {"status": "unavailable"}
|
||||
if isinstance(registry_report, dict):
|
||||
registry_status = registry_report.get("status")
|
||||
if registry_status in {"ready", "unavailable"}:
|
||||
registry_projection["status"] = registry_status
|
||||
count = registry_report.get("registeredProjectCount")
|
||||
if (
|
||||
registry_status == "ready"
|
||||
and type(count) is int
|
||||
and 0 <= count <= 500
|
||||
):
|
||||
registry_projection["registeredProjectCount"] = count
|
||||
controller_reason = (
|
||||
""
|
||||
if controller_core_ready
|
||||
else _safe_capability_reason(controller_capability.get("reason"))
|
||||
or "deployment_executor_unavailable"
|
||||
)
|
||||
|
||||
return {
|
||||
"apiVersion": "itworx.enrollment-capabilities/v1",
|
||||
"trust": item(configured, "enrollment_trust_not_configured"),
|
||||
"targetEnrollment": item(broker_ready, "deployment_executor_unavailable"),
|
||||
"targetEnrollment": item(target_enrollment_ready, enrollment_blocker),
|
||||
"secretBootstrap": item(_enrollment_secret_store_ready(storage), "secret_store_not_production_ready"),
|
||||
"runtimeDeployment": item(broker_ready, "deployment_executor_unavailable"),
|
||||
"runtimeDeployment": item(runtime_deployment_ready, "deployment_executor_unavailable"),
|
||||
"reverseProxyProvisioning": item(npm_ready, "npm_credentials_missing"),
|
||||
"tlsProvisioning": item(certificate_ready, "certificate_provisioning_unavailable"),
|
||||
"oidcProvisioning": item(oidc_configured, "oidc_profile_unavailable"),
|
||||
"policyProvisioning": item(configured, "policy_template_unavailable"),
|
||||
"rollback": item(broker_ready, "deployment_executor_unavailable"),
|
||||
"verification": item(broker_ready, "deployment_executor_unavailable"),
|
||||
"rollback": item(rollback_ready, "deployment_executor_unavailable"),
|
||||
"verification": item(verify_ready, "deployment_executor_unavailable"),
|
||||
"availableTrustedAppdataRoots": available_roots,
|
||||
"managedStorage": {
|
||||
"status": managed_storage_status,
|
||||
@@ -283,19 +392,23 @@ class EnrollmentPlane:
|
||||
"backupAcknowledged": bool(
|
||||
trust and trust.managed_appdata_backup_acknowledged
|
||||
),
|
||||
},
|
||||
"controller": {
|
||||
"status": "ready" if broker_ready else "unavailable",
|
||||
"reason": (
|
||||
""
|
||||
if broker_ready
|
||||
else str(controller_capability.get("reason") or (
|
||||
"trusted_appdata_root_mismatch"
|
||||
if controller_capability.get("status") == "ready" and not controller_root_matches
|
||||
else "deployment_executor_unavailable"
|
||||
))
|
||||
**(
|
||||
{"reason": _safe_capability_reason(controller_managed_storage.get("reason"))}
|
||||
if trust is not None
|
||||
and trust.trusted_appdata_root == MANAGED_DOCKER_APPDATA_ROOT
|
||||
and _safe_capability_reason(controller_managed_storage.get("reason"))
|
||||
else {}
|
||||
),
|
||||
},
|
||||
"enrollmentReadiness": {
|
||||
"status": "ready" if target_enrollment_ready else "unavailable",
|
||||
"reason": enrollment_reason,
|
||||
},
|
||||
"registry": registry_projection,
|
||||
"controller": {
|
||||
"status": "ready" if controller_core_ready else "unavailable",
|
||||
"reason": controller_reason,
|
||||
},
|
||||
"profiles": [profile_summary(name) for name in ("internal-webapp", "internal-webapp-oidc", "internal-service", "repopulse-authenticated")],
|
||||
}
|
||||
|
||||
@@ -433,6 +546,18 @@ class EnrollmentPlane:
|
||||
if by_repository and (not by_application or by_repository.id != by_application.id):
|
||||
checks.append(_check("target_already_exists", "blocked", "Repository is already bound to a different managed application."))
|
||||
|
||||
policy_ids = (
|
||||
f"enrollment-{plan.application_id}-deployment-apply",
|
||||
f"enrollment-{plan.application_id}-deployment-rollback",
|
||||
)
|
||||
policy_collisions = [policy_id for policy_id in policy_ids if session.get(Policy, policy_id) is not None]
|
||||
checks.append(_check(
|
||||
"exact_policy_id_collision",
|
||||
"blocked" if policy_collisions else "passed",
|
||||
"An enrollment-generated exact policy identifier is already owned and cannot be adopted."
|
||||
if policy_collisions else "Both enrollment-generated exact policy identifiers are available.",
|
||||
))
|
||||
|
||||
containers = self.portainer.list_containers()
|
||||
if containers.get("status") != "ok":
|
||||
checks.append(_check("container_inventory_unavailable", "blocked", "Portainer inventory is unavailable for collision protection."))
|
||||
@@ -676,17 +801,25 @@ class EnrollmentPlane:
|
||||
"sourceRevision": plan.revision,
|
||||
"createdAt": utc_now().isoformat(),
|
||||
}
|
||||
identifiers: list[str] = []
|
||||
for action, suffix in (("deployment.apply", "deployment-apply"), ("deployment.rollback", "deployment-rollback")):
|
||||
policy_id = f"enrollment-{plan.application_id}-{suffix}"
|
||||
existing = session.get(Policy, policy_id)
|
||||
if existing is not None:
|
||||
# Enrollment never adopts or repurposes a pre-existing policy,
|
||||
# even where its visible action/target happen to match. A
|
||||
# replay is handled before this method; this branch is a
|
||||
# collision, not a safe recovery path.
|
||||
raise EnrollmentError("exact policy identifier is already owned and cannot be adopted")
|
||||
existing = Policy(
|
||||
policy_specs = (
|
||||
(
|
||||
"deployment.apply",
|
||||
f"enrollment-{plan.application_id}-deployment-apply",
|
||||
),
|
||||
(
|
||||
"deployment.rollback",
|
||||
f"enrollment-{plan.application_id}-deployment-rollback",
|
||||
),
|
||||
)
|
||||
identifiers = [policy_id for _action, policy_id in policy_specs]
|
||||
# Check the complete pair before adding either row. The database flush
|
||||
# below is one transaction so a concurrent uniqueness collision cannot
|
||||
# leave the first insert committed by _fail().
|
||||
if any(session.get(Policy, policy_id) is not None for policy_id in identifiers):
|
||||
raise EnrollmentError("exact policy identifier is already owned and cannot be adopted")
|
||||
|
||||
for action, policy_id in policy_specs:
|
||||
policy = Policy(
|
||||
id=policy_id,
|
||||
action=action,
|
||||
target=plan.application_id,
|
||||
@@ -695,10 +828,17 @@ class EnrollmentPlane:
|
||||
risk="high",
|
||||
reason="Enrollment-generated exact-target deployment policy.",
|
||||
)
|
||||
existing.provenance_json = provenance
|
||||
session.add(existing)
|
||||
identifiers.append(policy_id)
|
||||
session.commit()
|
||||
policy.provenance_json = provenance
|
||||
session.add(policy)
|
||||
try:
|
||||
# Force uniqueness errors inside this boundary; on failure discard
|
||||
# the uncommitted unit of work before _fail() persists its outcome.
|
||||
session.flush()
|
||||
except IntegrityError as exc:
|
||||
session.rollback()
|
||||
raise EnrollmentError("exact policy identifier is already owned and cannot be adopted") from exc
|
||||
# Deliberately do not commit here: the caller commits these rows together
|
||||
# with the enrollment/job ready state after policy installation succeeds.
|
||||
return identifiers
|
||||
|
||||
def _compensate(
|
||||
|
||||
Reference in new issue
Block a user