Publish curated Unraid-AppOps-Gateway source from ad0a390e431166c3198a2ac3bec010c2b44f2dea

This commit is contained in:
Public Source Publisher committed 2026-10-02 09:56:13 +00:00
1 parent 29c1e3d5a1
commit 98d31477f9
35 files changed
+7264 -185

No files matched your search

+10 -6
View File
@@ -7,14 +7,15 @@ from fastapi import APIRouter, Depends, Header, HTTPException
from pydantic import BaseModel, ConfigDict, Field
from sqlmodel import Session, select
from ..db.session import get_session
from ..db.models import App, AppSetting, utc_now
from ..services.audit_logger import log_event
from ..services.container_restart_service import execute_container_restart
from ..services.policy_engine import evaluate_policy
from ..db.session import get_session
from ..services.action_execution import (
action_execution_profile,
execute_governed_action,
)
from ..services.action_registry import (
ACTIONS,
ACTION_RISK,
ACTIONS,
action_blast_radius,
action_capability,
action_category,
@@ -24,7 +25,9 @@ from ..services.action_registry import (
action_safeguards,
)
from ..services.approval_service import create_approval
from ..services.action_execution import action_execution_profile, execute_governed_action
from ..services.audit_logger import log_event
from ..services.container_restart_service import execute_container_restart
from ..services.policy_engine import evaluate_policy
from ..services.preflight_service import build_preflight
router = APIRouter(prefix='/api/actions')
@@ -446,6 +449,7 @@ def execute(payload: ActionRequest, session: Session = Depends(get_session), ide
})
if action in {
'controller.managed-storage.initialize',
'deployment.targets.sync',
'deployment.target.deploy_workmesh',
'deployment.target.register_portfolio',
+166 -3
View File
@@ -2,20 +2,37 @@
from __future__ import annotations
from copy import deepcopy
from typing import Annotated, Literal
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Request
from pydantic import BaseModel, ConfigDict
from sqlalchemy import insert as sql_insert
from sqlalchemy import update as sql_update
from sqlalchemy.exc import SQLAlchemyError
from sqlmodel import Session
from ..core.security import require_operator_request
from ..core.time import utc_now
from ..db.models import AppSetting
from ..db.session import get_session
from ..schemas.enrollment import EnrollmentPlanV1, EnrollmentTrustConfigV1
from ..services.enrollment_plane import EnrollmentError, EnrollmentPlane
from ..schemas.enrollment import (
LEGACY_APPDATA_ROOT,
EnrollmentPlanV1,
EnrollmentStorageRootSelectionV1,
EnrollmentTrustConfigV1,
)
from ..services.audit_logger import log_event
from ..services.enrollment_plane import (
TRUST_SETTING_KEY,
EnrollmentError,
EnrollmentPlane,
)
from ..services.repopulse_adoption_journal import (
RepoPulseAdoptionJournalError,
get_repopulse_adoption_status,
)
from ..services.user_access import current_user
def _require_operator(request: Request) -> str:
@@ -58,10 +75,156 @@ def enrollment_trust_status(session: EnrollmentSession):
@router.put("/trust")
def update_enrollment_trust(payload: EnrollmentTrustConfigV1, session: EnrollmentSession):
def update_enrollment_trust(
payload: EnrollmentTrustConfigV1,
session: EnrollmentSession,
request: Request,
):
actor = current_user(request)
if actor.role != "admin":
row = session.get(AppSetting, TRUST_SETTING_KEY)
original_value = deepcopy(row.value_json) if row is not None else None
original_updated_at = row.updated_at if row is not None else None
if row is None or row.is_secret:
existing = None
else:
try:
existing = EnrollmentTrustConfigV1.model_validate(original_value)
except ValueError:
existing = None
if row is None:
# Preserve initial legacy setup for settings.manage users, but the
# fixed managed-root opt-in must be made by an administrator.
selector_changed = (
payload.trusted_appdata_root != LEGACY_APPDATA_ROOT
or payload.managed_appdata_backup_acknowledged is not False
)
elif existing is None:
# A corrupt stored trust document has no safe selector baseline.
selector_changed = True
else:
selector_changed = (
payload.trusted_appdata_root != existing.trusted_appdata_root
or payload.managed_appdata_backup_acknowledged
!= existing.managed_appdata_backup_acknowledged
)
if selector_changed:
raise HTTPException(
status_code=403,
detail="Administrator role is required to change the appdata root.",
)
try:
if row is None:
# A concurrent administrator may create the trust row after the
# absence check. The unique key makes this insert a safe CAS:
# losing the race is a conflict, never an overwrite.
session.execute(
sql_insert(AppSetting).values(
key=TRUST_SETTING_KEY,
value_json=payload.model_dump(mode="json"),
is_secret=False,
updated_at=utc_now(),
)
)
else:
result = session.execute(
sql_update(AppSetting)
.where(AppSetting.key == TRUST_SETTING_KEY)
.where(AppSetting.updated_at == original_updated_at)
.where(AppSetting.value_json == original_value)
.values(
value_json=payload.model_dump(mode="json"),
is_secret=False,
updated_at=utc_now(),
)
.execution_options(synchronize_session=False)
)
if result.rowcount != 1:
session.rollback()
raise HTTPException(status_code=409, detail="enrollment_trust_changed")
session.commit()
except HTTPException:
raise
except SQLAlchemyError:
session.rollback()
raise HTTPException(status_code=409, detail="enrollment_trust_changed") from None
session.expire_all()
return EnrollmentPlane.trust_status(session)
return EnrollmentPlane.set_trust_config(session, payload)
@router.patch("/trust/storage-root")
def update_enrollment_storage_root(
payload: EnrollmentStorageRootSelectionV1,
session: EnrollmentSession,
request: Request,
):
"""Change only the fixed storage selector and persist its backup acknowledgement."""
if current_user(request).role != "admin":
raise HTTPException(status_code=403, detail="Administrator role is required.")
trust = EnrollmentPlane.get_trust_config(session)
row = session.get(AppSetting, TRUST_SETTING_KEY)
if trust is None or row is None:
raise HTTPException(status_code=409, detail="enrollment_trust_not_configured")
original_value = deepcopy(row.value_json)
original_updated_at = row.updated_at
try:
stored_trust = EnrollmentTrustConfigV1.model_validate(original_value)
except ValueError:
raise HTTPException(status_code=409, detail="enrollment_trust_changed") from None
if stored_trust.model_dump(mode="json") != trust.model_dump(mode="json"):
raise HTTPException(status_code=409, detail="enrollment_trust_changed")
updated = EnrollmentTrustConfigV1.model_validate({
**original_value,
**payload.model_dump(mode="json"),
})
before = {
"trustedAppdataRoot": trust.trusted_appdata_root,
"managedAppdataBackupAcknowledged": trust.managed_appdata_backup_acknowledged,
}
after = {
"trustedAppdataRoot": updated.trusted_appdata_root,
"managedAppdataBackupAcknowledged": updated.managed_appdata_backup_acknowledged,
}
try:
result = session.execute(
sql_update(AppSetting)
.where(AppSetting.key == TRUST_SETTING_KEY)
.where(AppSetting.updated_at == original_updated_at)
.where(AppSetting.value_json == original_value)
.values(
value_json=updated.model_dump(mode="json"),
is_secret=False,
updated_at=utc_now(),
)
.execution_options(synchronize_session=False)
)
except SQLAlchemyError:
session.rollback()
raise HTTPException(status_code=409, detail="enrollment_trust_changed") from None
if result.rowcount != 1:
session.rollback()
raise HTTPException(status_code=409, detail="enrollment_trust_changed")
session.expire(row)
log_event(
session,
source="settings",
identity="manual",
action_id="enrollment.trust.storage_root.update",
target="tower/deployment-controller",
risk="high",
policy_decision="allowed",
reason="Authenticated settings.manage operator selected a fixed appdata root and recorded its backup acknowledgement.",
result="updated",
target_type="controller",
before_state=before,
after_state=after,
redacted_metadata={"backupLocation": "dockerRootDir" if updated.managed_appdata_backup_acknowledged else None},
)
return EnrollmentPlane.trust_status(session)
@router.post("")
def request_enrollment(
payload: EnrollmentRequestV1,