2265 lines
76 KiB
Python
2265 lines
76 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
|
|
from sqlmodel import Session, select
|
|
|
|
from ..connectors.deluge import DelugeConnector
|
|
from ..connectors.plex import PlexConnector
|
|
from ..db.models import Approval, JobRun
|
|
from .audit_logger import log_event
|
|
from .job_runner import (
|
|
complete_job,
|
|
create_job,
|
|
prepare_job,
|
|
set_job_progress,
|
|
start_job,
|
|
)
|
|
from .setup_service import apply_stored_connector_settings
|
|
|
|
GENERIC_EXECUTOR_ACTIONS = {
|
|
"container.restart",
|
|
"controller.artifact.promote",
|
|
"deployment.targets.sync",
|
|
"deployment.runnerless.provision",
|
|
"deployment.target.deploy_workmesh",
|
|
"deployment.target.register_portfolio",
|
|
"deployment.target.register_privatemuse",
|
|
"deployment.target.reconcile_media_codec_dashboard",
|
|
"deployment.webhook.repair_privatemuse",
|
|
"privatemuse.comfyui.install_artifact",
|
|
}
|
|
|
|
DEDICATED_ENDPOINT_ACTIONS = {
|
|
"deluge.pause_torrent",
|
|
"deluge.resume_torrent",
|
|
"media_pipeline.check",
|
|
"media_pipeline.diagnose",
|
|
"notifications.evaluate_safety",
|
|
"plex.scan_library",
|
|
"prowlarr.search_test",
|
|
"radarr.add_movie",
|
|
"sonarr.add_series",
|
|
"unraid.vm.start",
|
|
"unraid.vm.resume",
|
|
"unraid.vm.pause",
|
|
"widefrog.retry_failed",
|
|
"widefrog.scan_library",
|
|
}
|
|
|
|
APPROVAL_EXECUTOR_ACTIONS = {
|
|
"container.restart",
|
|
"controller.artifact.promote",
|
|
"runner.fleet.upgrade_v2",
|
|
"deployment.targets.sync",
|
|
"deployment.runnerless.provision",
|
|
"deployment.target.deploy_workmesh",
|
|
"deployment.target.promote_workmesh",
|
|
"deployment.target.register_portfolio",
|
|
"deployment.target.register_privatemuse",
|
|
"deployment.target.reconcile_media_codec_dashboard",
|
|
"deployment.webhook.repair_privatemuse",
|
|
"privatemuse.comfyui.install_artifact",
|
|
"deluge.pause_all",
|
|
"deluge.resume_all",
|
|
"plex.scan_all_libraries",
|
|
"unraid.vm.start",
|
|
"unraid.vm.resume",
|
|
"unraid.vm.pause",
|
|
}
|
|
|
|
HUMAN_APPROVAL_ONLY_ACTIONS = {"deployment.target.promote_workmesh", "privatemuse.comfyui.install_artifact"}
|
|
|
|
_APPROVAL_STEPS = {
|
|
"deluge.pause_all": [
|
|
"Load approved request",
|
|
"Reload connector settings",
|
|
"Pause all torrents",
|
|
"Record result",
|
|
],
|
|
"deluge.resume_all": [
|
|
"Load approved request",
|
|
"Reload connector settings",
|
|
"Resume all torrents",
|
|
"Record result",
|
|
],
|
|
"plex.scan_all_libraries": [
|
|
"Load approved request",
|
|
"Reload connector settings",
|
|
"Scan all Plex libraries",
|
|
"Record result",
|
|
],
|
|
}
|
|
|
|
_DIRECT_STEPS = {
|
|
"deluge.pause_all": [
|
|
"Validate MCP policy",
|
|
"Reload connector settings",
|
|
"Pause all torrents",
|
|
"Record result",
|
|
],
|
|
"deluge.resume_all": [
|
|
"Validate MCP policy",
|
|
"Reload connector settings",
|
|
"Resume all torrents",
|
|
"Record result",
|
|
],
|
|
"plex.scan_all_libraries": [
|
|
"Validate MCP policy",
|
|
"Reload connector settings",
|
|
"Scan all Plex libraries",
|
|
"Record result",
|
|
],
|
|
}
|
|
|
|
|
|
def action_execution_profile(
|
|
action: str, policy_decision: str, capability: str
|
|
) -> dict[str, Any]:
|
|
if policy_decision == "blocked":
|
|
mode = "blocked"
|
|
surface = None
|
|
elif action in GENERIC_EXECUTOR_ACTIONS:
|
|
mode = "command_center"
|
|
surface = "/command-center"
|
|
elif action in APPROVAL_EXECUTOR_ACTIONS and policy_decision == "approval_required":
|
|
mode = "approval_then_execute"
|
|
surface = "/approvals"
|
|
elif action in DEDICATED_ENDPOINT_ACTIONS or capability == "read_only":
|
|
mode = "dedicated_surface"
|
|
surface = None
|
|
else:
|
|
mode = "governance_only"
|
|
surface = None
|
|
|
|
return {
|
|
"executionMode": mode,
|
|
"executionSupported": mode
|
|
in {"command_center", "approval_then_execute", "dedicated_surface"},
|
|
"commandExecutionSupported": mode == "command_center",
|
|
"executionSurface": surface,
|
|
}
|
|
|
|
|
|
def approval_execution_supported(action: str) -> bool:
|
|
return action in APPROVAL_EXECUTOR_ACTIONS
|
|
|
|
|
|
def mcp_execution_supported(action: str) -> bool:
|
|
"""MCP is a no-human-approval surface; never admit human-only executors."""
|
|
return approval_execution_supported(action) and action not in HUMAN_APPROVAL_ONLY_ACTIONS
|
|
|
|
|
|
def _execute_deployment_target_sync(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .gitea_project_auto_registration import GiteaProjectAutoRegistration
|
|
|
|
action = "deployment.targets.sync"
|
|
target = "jens/*"
|
|
steps = [
|
|
"Read owned Gitea repositories through the bounded catalog client",
|
|
"Validate repository deployment descriptors and Compose topology",
|
|
"Register exact-SHA controller targets where contracts are valid",
|
|
"Install exact-target deployment policies without deploying applications",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 20, "Reconciling bounded Gitea deployment targets.")
|
|
try:
|
|
result = GiteaProjectAutoRegistration().sync(session, force=True)
|
|
status = str(result.get("status") or "error")
|
|
summary = result.get("summary") if isinstance(result.get("summary"), dict) else {}
|
|
success = status == "ok"
|
|
message = (
|
|
"Deployment target catalog reconciled."
|
|
if success
|
|
else str(result.get("reason") or "Deployment target catalog reconciliation failed.")
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
summary = {}
|
|
message = f"{type(exc).__name__}: deployment target catalog reconciliation failed"
|
|
result = {"status": status}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-project-catalog",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"total": summary.get("total", 0),
|
|
"registered": summary.get("registered", 0),
|
|
"knownUnconfigured": summary.get("knownUnconfigured", 0),
|
|
"conflicts": summary.get("conflicts", 0),
|
|
"errors": summary.get("errors", 0),
|
|
"changed": summary.get("changedThisSync", 0),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"summary": {
|
|
"total": summary.get("total", 0),
|
|
"registered": summary.get("registered", 0),
|
|
"knownUnconfigured": summary.get("knownUnconfigured", 0),
|
|
"conflicts": summary.get("conflicts", 0),
|
|
"errors": summary.get("errors", 0),
|
|
"changed": summary.get("changedThisSync", 0),
|
|
},
|
|
}
|
|
|
|
|
|
def _execute_workmesh_first_deployment(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .workmesh_first_deployment import WorkMeshFirstDeployment
|
|
|
|
action = "deployment.target.deploy_workmesh"
|
|
target = "jens/workmesh"
|
|
steps = [
|
|
"Verify the fixed WorkMesh v0.1.0 protected-main release contract",
|
|
"Create or validate the external mode-0600 WorkMesh runtime environment",
|
|
"Reserve the fixed loopback port set and reconcile the exact-source controller target",
|
|
"Run the official deployment-controller preflight and transactional first deploy",
|
|
"Verify the controller-owned deployment receipt without exposing secret values",
|
|
]
|
|
service = WorkMeshFirstDeployment()
|
|
tracked_job_id = service.tracked_job_id(session)
|
|
job = session.get(JobRun, tracked_job_id) if tracked_job_id else None
|
|
orphan_running = False
|
|
if job is None:
|
|
job = session.exec(
|
|
select(JobRun)
|
|
.where(JobRun.action_id == action, JobRun.target == target, JobRun.status == "running")
|
|
.order_by(JobRun.started_at.desc())
|
|
).first()
|
|
if job is not None:
|
|
orphan_running = True
|
|
else:
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
|
|
try:
|
|
deployment = (
|
|
{
|
|
"status": "outcome_unknown",
|
|
"reason": "An earlier WorkMesh deployment job is running without matching durable execution state; reconcile it before another deploy",
|
|
}
|
|
if orphan_running
|
|
else service.run(session, job=job)
|
|
)
|
|
status = str(deployment.get("status") or "error")
|
|
execution_id = str(deployment.get("execution_id") or "")
|
|
if status == "deployed":
|
|
success = True
|
|
message = "WorkMesh v0.1.0 first deployment completed with controller receipt evidence."
|
|
elif status == "in_progress":
|
|
success = False
|
|
message = "WorkMesh v0.1.0 first deployment is still running."
|
|
elif status == "outcome_unknown":
|
|
success = False
|
|
message = str(deployment.get("reason") or "WorkMesh deployment outcome requires reconciliation.")
|
|
else:
|
|
success = False
|
|
message = str(deployment.get("reason") or "WorkMesh v0.1.0 first deployment failed closed.")
|
|
except Exception as exc:
|
|
status = "error"
|
|
execution_id = ""
|
|
success = False
|
|
deployment = {"status": status}
|
|
message = f"{type(exc).__name__}: WorkMesh first-deploy reconciliation failed"
|
|
|
|
if status in {"in_progress", "outcome_unknown"}:
|
|
if job.status not in {"succeeded", "failed", "cancelled"}:
|
|
completed = set_job_progress(
|
|
session,
|
|
job,
|
|
max(job.progress, 90 if status == "outcome_unknown" else 25),
|
|
message,
|
|
)
|
|
else:
|
|
completed = job
|
|
elif job.status in {"succeeded", "failed", "cancelled"}:
|
|
completed = job
|
|
else:
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
|
|
outward_status = (
|
|
status
|
|
if status in {"in_progress", "outcome_unknown"}
|
|
else "success"
|
|
if success
|
|
else "failed"
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result=outward_status,
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": deployment.get("repository", target),
|
|
"revision": deployment.get("revision"),
|
|
"composeProject": deployment.get("compose_project"),
|
|
"containers": deployment.get("containers"),
|
|
"ports": deployment.get("ports"),
|
|
"executionId": execution_id or None,
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"secretsReturned": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": outward_status,
|
|
"result": outward_status,
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
**({"executionId": execution_id} if execution_id else {}),
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_portfolio_target_enrollment(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .portfolio_deployment_recovery import PortfolioDeploymentRecovery
|
|
|
|
action = "deployment.target.register_portfolio"
|
|
target = "jens/portfolio"
|
|
steps = [
|
|
"Validate the fixed Portfolio deployment contract",
|
|
"Verify or re-attest the proven live Portfolio web/API pair",
|
|
"Atomically reconcile the paired controller target state",
|
|
"Preserve exact-source deployment provenance",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 20, "Validating fixed Portfolio deployment target.")
|
|
try:
|
|
enrollment = PortfolioDeploymentRecovery().run()
|
|
status = str(enrollment.get("status") or "error")
|
|
success = status in {"enrolled", "already-enrolled", "reconciled"}
|
|
message = str(
|
|
enrollment.get("reason")
|
|
or (
|
|
"Portfolio deployment target state verified."
|
|
if success
|
|
else "Portfolio deployment target enrollment failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
message = f"{type(exc).__name__}: Portfolio deployment target enrollment failed"
|
|
enrollment = {"status": status}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": enrollment.get("repository"),
|
|
"composeProject": enrollment.get("compose_project"),
|
|
"containers": enrollment.get("containers"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_privatemuse_target_enrollment(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .privatemuse_deployment_recovery import PrivateMuseDeploymentRecovery
|
|
|
|
action = "deployment.target.register_privatemuse"
|
|
target = "jens/privatemuse"
|
|
steps = [
|
|
"Validate the fixed PrivateMuse deployment contract",
|
|
"Verify or re-attest the proven live PrivateMuse production trio",
|
|
"Atomically reconcile only the bounded controller receipt state",
|
|
"Preserve immutable images, media, models and exact-source provenance",
|
|
]
|
|
recovery = PrivateMuseDeploymentRecovery()
|
|
candidate_job = prepare_job(
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
tracked, admitted = recovery.admit_job(session, candidate_job)
|
|
tracked_job_id = str(tracked.get("jobId") or "")
|
|
job = session.get(JobRun, tracked_job_id)
|
|
if job is None:
|
|
raise RuntimeError("PrivateMuse recovery owner job is unavailable")
|
|
if admitted:
|
|
start_job(session, job)
|
|
set_job_progress(
|
|
session, job, 20, "Validating fixed PrivateMuse deployment target."
|
|
)
|
|
try:
|
|
enrollment = recovery.run(
|
|
session=session,
|
|
job_id=job.id if admitted else candidate_job.id,
|
|
)
|
|
status = str(enrollment.get("status") or "error")
|
|
success = status in {"enrolled", "already-enrolled", "reconciled"}
|
|
message = str(
|
|
enrollment.get("reason")
|
|
or (
|
|
"PrivateMuse deployment target state verified."
|
|
if success
|
|
else "PrivateMuse deployment target enrollment failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
guarded = recovery.guarded_unknown_result(
|
|
session,
|
|
reason=(
|
|
"PrivateMuse recovery crossed its durable execution boundary but "
|
|
"local result handling failed; reconcile the recorded execution and "
|
|
"do not retry"
|
|
),
|
|
)
|
|
if guarded is not None:
|
|
success = False
|
|
status = "outcome_unknown"
|
|
message = str(guarded["reason"])
|
|
enrollment = guarded
|
|
else:
|
|
success = False
|
|
status = "error"
|
|
message = (
|
|
f"{type(exc).__name__}: PrivateMuse deployment target enrollment failed"
|
|
)
|
|
enrollment = {"status": status}
|
|
|
|
execution_id = str(enrollment.get("execution_id") or "")
|
|
original_job_id = str(enrollment.get("original_job_id") or job.id)
|
|
original_job = session.get(JobRun, original_job_id)
|
|
result_job = original_job or job
|
|
evidence_summary = (
|
|
f"{status}; executionId={execution_id}; {message}"
|
|
if execution_id
|
|
else f"{status}; {message}"
|
|
)
|
|
if status in {"in_progress", "outcome_unknown"}:
|
|
if result_job.status not in {"succeeded", "failed", "cancelled"}:
|
|
completed = set_job_progress(
|
|
session,
|
|
result_job,
|
|
max(result_job.progress, 90 if status == "outcome_unknown" else 5),
|
|
evidence_summary,
|
|
)
|
|
else:
|
|
completed = result_job
|
|
elif result_job.status in {"succeeded", "failed", "cancelled"}:
|
|
completed = result_job
|
|
else:
|
|
completed = complete_job(
|
|
session,
|
|
result_job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=evidence_summary,
|
|
)
|
|
outward_status = (
|
|
status
|
|
if status in {"in_progress", "outcome_unknown"}
|
|
else "success"
|
|
if success
|
|
else "failed"
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result=outward_status,
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": enrollment.get("repository"),
|
|
"composeProject": enrollment.get("compose_project"),
|
|
"containers": enrollment.get("containers"),
|
|
"executionId": execution_id or None,
|
|
"originalJobId": original_job_id,
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": outward_status,
|
|
"result": outward_status,
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
**({"executionId": execution_id} if execution_id else {}),
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
|
|
def _execute_media_codec_dashboard_reconciliation(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .media_codec_dashboard_deployment_reconciliation import (
|
|
MediaCodecDashboardDeploymentReconciliation,
|
|
)
|
|
|
|
action = "deployment.target.reconcile_media_codec_dashboard"
|
|
target = "jens/media-codec-dashboard"
|
|
steps = [
|
|
"Validate the fixed Media Codec Dashboard deployment contract",
|
|
"Verify the live immutable dashboard runtime",
|
|
"Reconcile only the bounded controller deployment state",
|
|
"Preserve containers, images, mounts and exact-source provenance",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(
|
|
session,
|
|
job,
|
|
20,
|
|
"Validating fixed Media Codec Dashboard deployment state.",
|
|
)
|
|
try:
|
|
reconciliation = MediaCodecDashboardDeploymentReconciliation().run()
|
|
status = str(reconciliation.get("status") or "error")
|
|
success = status == "reconciled"
|
|
message = str(
|
|
reconciliation.get("reason")
|
|
or (
|
|
"Media Codec Dashboard deployment state reconciled."
|
|
if success
|
|
else "Media Codec Dashboard deployment-state reconciliation failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
reconciliation = {"status": status}
|
|
message = (
|
|
f"{type(exc).__name__}: "
|
|
"Media Codec Dashboard deployment-state reconciliation failed"
|
|
)
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": reconciliation.get("repository"),
|
|
"container": reconciliation.get("container"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_privatemuse_webhook_repair(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .privatemuse_webhook_repair import PrivateMuseWebhookRepair
|
|
|
|
action = "deployment.webhook.repair_privatemuse"
|
|
target = "jens/privatemuse"
|
|
steps = [
|
|
"Validate the fixed PrivateMuse runnerless webhook contract",
|
|
"Verify controller-owned webhook secret and Gitea repository identity",
|
|
"Create or repair only the exact PrivateMuse push hook",
|
|
"Re-read the hook and verify active main-only push delivery metadata",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 20, "Validating fixed PrivateMuse webhook state.")
|
|
try:
|
|
repair = PrivateMuseWebhookRepair().run()
|
|
status = str(repair.get("status") or "error")
|
|
success = status == "repaired"
|
|
message = str(
|
|
repair.get("reason")
|
|
or (
|
|
"PrivateMuse runnerless webhook verified or repaired."
|
|
if success
|
|
else "PrivateMuse runnerless webhook repair failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
message = f"{type(exc).__name__}: PrivateMuse runnerless webhook repair failed"
|
|
repair = {"status": status}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-webhook",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": repair.get("repository"),
|
|
"endpoint": repair.get("endpoint"),
|
|
"branch": repair.get("branch"),
|
|
"event": repair.get("event"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"secretMaterialReturned": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else status,
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_runnerless_target_provisioning(
|
|
session: Session,
|
|
*,
|
|
target: str,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .gitea_project_auto_registration import GiteaProjectAutoRegistration
|
|
from .runnerless_target_provisioning import RunnerlessTargetProvisioning
|
|
|
|
action = "deployment.runnerless.provision"
|
|
application_id = target.strip().lower()
|
|
catalog = GiteaProjectAutoRegistration.catalog(session)
|
|
projects = catalog.get("projects") if isinstance(catalog, dict) else None
|
|
matches = [
|
|
item
|
|
for item in projects or []
|
|
if isinstance(item, dict)
|
|
and str(item.get("applicationId") or "").strip().lower() == application_id
|
|
and bool(item.get("deploymentRegistered"))
|
|
and str(item.get("state") or "") in {"registered", "registered_existing"}
|
|
]
|
|
if len(matches) != 1:
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": (
|
|
"Runnerless provisioning requires exactly one auto-registered "
|
|
"deployment target."
|
|
),
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
project = matches[0]
|
|
repository = str(project.get("repository") or "").strip().lower()
|
|
branch = str(project.get("defaultBranch") or "").strip()
|
|
revision = str(project.get("revision") or "").strip().lower()
|
|
if (
|
|
not repository.startswith("jens/")
|
|
or not branch
|
|
or len(revision) != 40
|
|
or any(character not in "0123456789abcdef" for character in revision)
|
|
):
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Auto-registered deployment target metadata is incomplete.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
steps = [
|
|
"Resolve the exact auto-registered application target",
|
|
"Verify controller target, repository identity and private Gitea reachability",
|
|
"Create or verify one repository-specific runnerless webhook secret",
|
|
"Install the exact main-push validation triplet and signed Gitea hook",
|
|
"Verify the hook without returning credentials",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=application_id,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(
|
|
session,
|
|
job,
|
|
20,
|
|
"Provisioning exact-target runnerless delivery metadata.",
|
|
)
|
|
try:
|
|
provisioned = RunnerlessTargetProvisioning().run(
|
|
repository=repository,
|
|
branch=branch,
|
|
)
|
|
status = str(provisioned.get("status") or "error")
|
|
success = status == "ready"
|
|
message = str(
|
|
provisioned.get("reason")
|
|
or (
|
|
"Runnerless delivery is ready for the registered target."
|
|
if success
|
|
else "Runnerless delivery provisioning failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
provisioned = {"status": "error"}
|
|
status = "error"
|
|
success = False
|
|
message = (
|
|
f"{type(exc).__name__}: runnerless target provisioning failed"
|
|
)
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=application_id,
|
|
target_type="deployment-webhook",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"applicationId": application_id,
|
|
"repository": repository,
|
|
"revision": revision,
|
|
"branch": provisioned.get("branch"),
|
|
"endpoint": provisioned.get("endpoint"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"secretMaterialReturned": False,
|
|
"repositoryCallerSelectable": False,
|
|
"branchCallerSelectable": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else status,
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"applicationId": application_id,
|
|
"repository": repository,
|
|
"revision": revision,
|
|
}
|
|
|
|
|
|
def _execute_workmesh_first_deployment(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .workmesh_first_deployment import WorkMeshFirstDeployment
|
|
|
|
action = "deployment.target.deploy_workmesh"
|
|
target = "jens/workmesh"
|
|
steps = [
|
|
"Verify the fixed WorkMesh v0.1.0 protected-main release contract",
|
|
"Create or validate the external mode-0600 WorkMesh runtime environment",
|
|
"Reserve the fixed loopback port set and reconcile the exact-source controller target",
|
|
"Run the official deployment-controller preflight and transactional first deploy",
|
|
"Verify the controller-owned deployment receipt without exposing secret values",
|
|
]
|
|
service = WorkMeshFirstDeployment()
|
|
tracked_job_id = service.tracked_job_id(session)
|
|
job = session.get(JobRun, tracked_job_id) if tracked_job_id else None
|
|
orphan_running = False
|
|
if job is None:
|
|
job = session.exec(
|
|
select(JobRun)
|
|
.where(JobRun.action_id == action, JobRun.target == target, JobRun.status == "running")
|
|
.order_by(JobRun.started_at.desc())
|
|
).first()
|
|
if job is not None:
|
|
orphan_running = True
|
|
else:
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
|
|
try:
|
|
deployment = (
|
|
{
|
|
"status": "outcome_unknown",
|
|
"reason": "An earlier WorkMesh deployment job is running without matching durable execution state; reconcile it before another deploy",
|
|
}
|
|
if orphan_running
|
|
else service.run(session, job=job)
|
|
)
|
|
status = str(deployment.get("status") or "error")
|
|
execution_id = str(deployment.get("execution_id") or "")
|
|
if status == "deployed":
|
|
success = True
|
|
message = "WorkMesh v0.1.0 first deployment completed with controller receipt evidence."
|
|
elif status == "in_progress":
|
|
success = False
|
|
message = "WorkMesh v0.1.0 first deployment is still running."
|
|
elif status == "outcome_unknown":
|
|
success = False
|
|
message = str(deployment.get("reason") or "WorkMesh deployment outcome requires reconciliation.")
|
|
else:
|
|
success = False
|
|
message = str(deployment.get("reason") or "WorkMesh v0.1.0 first deployment failed closed.")
|
|
except Exception as exc:
|
|
status = "error"
|
|
execution_id = ""
|
|
success = False
|
|
deployment = {"status": status}
|
|
message = f"{type(exc).__name__}: WorkMesh first-deploy reconciliation failed"
|
|
|
|
if status in {"in_progress", "outcome_unknown"}:
|
|
if job.status not in {"succeeded", "failed", "cancelled"}:
|
|
completed = set_job_progress(
|
|
session,
|
|
job,
|
|
max(job.progress, 90 if status == "outcome_unknown" else 25),
|
|
message,
|
|
)
|
|
else:
|
|
completed = job
|
|
elif job.status in {"succeeded", "failed", "cancelled"}:
|
|
completed = job
|
|
else:
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
|
|
outward_status = (
|
|
status
|
|
if status in {"in_progress", "outcome_unknown"}
|
|
else "success"
|
|
if success
|
|
else "failed"
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result=outward_status,
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": deployment.get("repository", target),
|
|
"revision": deployment.get("revision"),
|
|
"composeProject": deployment.get("compose_project"),
|
|
"containers": deployment.get("containers"),
|
|
"ports": deployment.get("ports"),
|
|
"executionId": execution_id or None,
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"secretsReturned": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": outward_status,
|
|
"result": outward_status,
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
**({"executionId": execution_id} if execution_id else {}),
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_portfolio_target_enrollment(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .portfolio_deployment_recovery import PortfolioDeploymentRecovery
|
|
|
|
action = "deployment.target.register_portfolio"
|
|
target = "jens/portfolio"
|
|
steps = [
|
|
"Validate the fixed Portfolio deployment contract",
|
|
"Verify or re-attest the proven live Portfolio web/API pair",
|
|
"Atomically reconcile the paired controller target state",
|
|
"Preserve exact-source deployment provenance",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 20, "Validating fixed Portfolio deployment target.")
|
|
try:
|
|
enrollment = PortfolioDeploymentRecovery().run()
|
|
status = str(enrollment.get("status") or "error")
|
|
success = status in {"enrolled", "already-enrolled", "reconciled"}
|
|
message = str(
|
|
enrollment.get("reason")
|
|
or (
|
|
"Portfolio deployment target state verified."
|
|
if success
|
|
else "Portfolio deployment target enrollment failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
message = f"{type(exc).__name__}: Portfolio deployment target enrollment failed"
|
|
enrollment = {"status": status}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": enrollment.get("repository"),
|
|
"composeProject": enrollment.get("compose_project"),
|
|
"containers": enrollment.get("containers"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_privatemuse_target_enrollment(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .privatemuse_deployment_recovery import PrivateMuseDeploymentRecovery
|
|
|
|
action = "deployment.target.register_privatemuse"
|
|
target = "jens/privatemuse"
|
|
steps = [
|
|
"Validate the fixed PrivateMuse deployment contract",
|
|
"Verify or re-attest the proven live PrivateMuse production trio",
|
|
"Atomically reconcile only the bounded controller receipt state",
|
|
"Preserve immutable images, media, models and exact-source provenance",
|
|
]
|
|
recovery = PrivateMuseDeploymentRecovery()
|
|
candidate_job = prepare_job(
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
tracked, admitted = recovery.admit_job(session, candidate_job)
|
|
tracked_job_id = str(tracked.get("jobId") or "")
|
|
job = session.get(JobRun, tracked_job_id)
|
|
if job is None:
|
|
raise RuntimeError("PrivateMuse recovery owner job is unavailable")
|
|
if admitted:
|
|
start_job(session, job)
|
|
set_job_progress(
|
|
session, job, 20, "Validating fixed PrivateMuse deployment target."
|
|
)
|
|
try:
|
|
enrollment = recovery.run(
|
|
session=session,
|
|
job_id=job.id if admitted else candidate_job.id,
|
|
)
|
|
status = str(enrollment.get("status") or "error")
|
|
success = status in {"enrolled", "already-enrolled", "reconciled"}
|
|
message = str(
|
|
enrollment.get("reason")
|
|
or (
|
|
"PrivateMuse deployment target state verified."
|
|
if success
|
|
else "PrivateMuse deployment target enrollment failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
guarded = recovery.guarded_unknown_result(
|
|
session,
|
|
reason=(
|
|
"PrivateMuse recovery crossed its durable execution boundary but "
|
|
"local result handling failed; reconcile the recorded execution and "
|
|
"do not retry"
|
|
),
|
|
)
|
|
if guarded is not None:
|
|
success = False
|
|
status = "outcome_unknown"
|
|
message = str(guarded["reason"])
|
|
enrollment = guarded
|
|
else:
|
|
success = False
|
|
status = "error"
|
|
message = (
|
|
f"{type(exc).__name__}: PrivateMuse deployment target enrollment failed"
|
|
)
|
|
enrollment = {"status": status}
|
|
|
|
execution_id = str(enrollment.get("execution_id") or "")
|
|
original_job_id = str(enrollment.get("original_job_id") or job.id)
|
|
original_job = session.get(JobRun, original_job_id)
|
|
result_job = original_job or job
|
|
evidence_summary = (
|
|
f"{status}; executionId={execution_id}; {message}"
|
|
if execution_id
|
|
else f"{status}; {message}"
|
|
)
|
|
if status in {"in_progress", "outcome_unknown"}:
|
|
if result_job.status not in {"succeeded", "failed", "cancelled"}:
|
|
completed = set_job_progress(
|
|
session,
|
|
result_job,
|
|
max(result_job.progress, 90 if status == "outcome_unknown" else 5),
|
|
evidence_summary,
|
|
)
|
|
else:
|
|
completed = result_job
|
|
elif result_job.status in {"succeeded", "failed", "cancelled"}:
|
|
completed = result_job
|
|
else:
|
|
completed = complete_job(
|
|
session,
|
|
result_job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=evidence_summary,
|
|
)
|
|
outward_status = (
|
|
status
|
|
if status in {"in_progress", "outcome_unknown"}
|
|
else "success"
|
|
if success
|
|
else "failed"
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result=outward_status,
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": enrollment.get("repository"),
|
|
"composeProject": enrollment.get("compose_project"),
|
|
"containers": enrollment.get("containers"),
|
|
"executionId": execution_id or None,
|
|
"originalJobId": original_job_id,
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": outward_status,
|
|
"result": outward_status,
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
**({"executionId": execution_id} if execution_id else {}),
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
|
|
def _execute_media_codec_dashboard_reconciliation(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .media_codec_dashboard_deployment_reconciliation import (
|
|
MediaCodecDashboardDeploymentReconciliation,
|
|
)
|
|
|
|
action = "deployment.target.reconcile_media_codec_dashboard"
|
|
target = "jens/media-codec-dashboard"
|
|
steps = [
|
|
"Validate the fixed Media Codec Dashboard deployment contract",
|
|
"Verify the live immutable dashboard runtime",
|
|
"Reconcile only the bounded controller deployment state",
|
|
"Preserve containers, images, mounts and exact-source provenance",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(
|
|
session,
|
|
job,
|
|
20,
|
|
"Validating fixed Media Codec Dashboard deployment state.",
|
|
)
|
|
try:
|
|
reconciliation = MediaCodecDashboardDeploymentReconciliation().run()
|
|
status = str(reconciliation.get("status") or "error")
|
|
success = status == "reconciled"
|
|
message = str(
|
|
reconciliation.get("reason")
|
|
or (
|
|
"Media Codec Dashboard deployment state reconciled."
|
|
if success
|
|
else "Media Codec Dashboard deployment-state reconciliation failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
reconciliation = {"status": status}
|
|
message = (
|
|
f"{type(exc).__name__}: "
|
|
"Media Codec Dashboard deployment-state reconciliation failed"
|
|
)
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-target",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": reconciliation.get("repository"),
|
|
"container": reconciliation.get("container"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def _execute_privatemuse_webhook_repair(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .privatemuse_webhook_repair import PrivateMuseWebhookRepair
|
|
|
|
action = "deployment.webhook.repair_privatemuse"
|
|
target = "jens/privatemuse"
|
|
steps = [
|
|
"Validate the fixed PrivateMuse runnerless webhook contract",
|
|
"Verify controller-owned webhook secret and Gitea repository identity",
|
|
"Create or repair only the exact PrivateMuse push hook",
|
|
"Re-read the hook and verify active main-only push delivery metadata",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 20, "Validating fixed PrivateMuse webhook state.")
|
|
try:
|
|
repair = PrivateMuseWebhookRepair().run()
|
|
status = str(repair.get("status") or "error")
|
|
success = status == "repaired"
|
|
message = str(
|
|
repair.get("reason")
|
|
or (
|
|
"PrivateMuse runnerless webhook verified or repaired."
|
|
if success
|
|
else "PrivateMuse runnerless webhook repair failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
success = False
|
|
status = "error"
|
|
message = f"{type(exc).__name__}: PrivateMuse runnerless webhook repair failed"
|
|
repair = {"status": status}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-webhook",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"repository": repair.get("repository"),
|
|
"endpoint": repair.get("endpoint"),
|
|
"branch": repair.get("branch"),
|
|
"event": repair.get("event"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"secretMaterialReturned": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else status,
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
|
|
def _execute_controller_artifact_promote(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .controller_artifact_promoter import ControllerArtifactPromoter
|
|
|
|
action = "controller.artifact.promote"
|
|
target = "tower/deployment-controller"
|
|
steps = [
|
|
"Resolve protected current main and successful push validation",
|
|
"Reuse the immutable image of the live deployment controller",
|
|
"Run one fixed ephemeral controller-promoter helper",
|
|
"Execute the existing rollbackable root controller upgrade procedure",
|
|
"Verify the installed controller release identity",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 20, "Promoting fixed root deployment-controller artifact.")
|
|
try:
|
|
result = ControllerArtifactPromoter().run()
|
|
status = str(result.get("status") or "error")
|
|
success = status in {"promoted", "already_applied"}
|
|
message = str(
|
|
result.get("reason")
|
|
or (
|
|
"Root deployment-controller artifact verified."
|
|
if success
|
|
else "Root deployment-controller promotion failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
result = {"status": "error"}
|
|
status = "error"
|
|
success = False
|
|
message = f"{type(exc).__name__}: controller artifact promotion failed"
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="deployment-controller",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"revision": result.get("revision"),
|
|
"controllerVersion": result.get("controllerVersion"),
|
|
"artifactSha256": result.get("artifactSha256"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"callerRevisionSelectable": False,
|
|
"callerCommandSelectable": False,
|
|
"callerMountSelectable": False,
|
|
"helperTargetSelectable": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else status,
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"revision": result.get("revision"),
|
|
"controllerVersion": result.get("controllerVersion"),
|
|
"artifactSha256": result.get("artifactSha256"),
|
|
}
|
|
|
|
|
|
def _execute_runner_fleet_upgrade_v2(
|
|
session: Session,
|
|
*,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
from .deployment_broker import DeploymentBrokerClient
|
|
|
|
action = "runner.fleet.upgrade_v2"
|
|
target = "tower/runner-fleet-v2"
|
|
steps = [
|
|
"Validate exact fixed runner-fleet target",
|
|
"Call HMAC-signed root controller endpoint",
|
|
"Prove protected main and successful push validation",
|
|
"Execute exact-revision fleet-v2 migration script",
|
|
"Verify specialized runner topology",
|
|
]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 25, "Requesting fixed Tower runner-fleet v2 migration.")
|
|
try:
|
|
result = DeploymentBrokerClient().runner_fleet_upgrade_v2(reason=reason)
|
|
status = str(result.get("status") or "error")
|
|
success = status in {"upgraded", "already_applied"}
|
|
message = str(
|
|
result.get("reason")
|
|
or (
|
|
"Tower runner-fleet v2 migration verified."
|
|
if success
|
|
else "Tower runner-fleet v2 migration was rejected or failed."
|
|
)
|
|
)
|
|
except Exception as exc:
|
|
result = {"status": "error"}
|
|
status = "error"
|
|
success = False
|
|
message = f"{type(exc).__name__}: runner fleet v2 migration failed"
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="runner-fleet",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={
|
|
"status": status,
|
|
"revision": result.get("revision"),
|
|
"verifiedRunners": result.get("verifiedRunners"),
|
|
},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp" if source == "chatgpt-mcp" else "operator",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"scriptPathCallerSelectable": False,
|
|
"runnerTargetCallerSelectable": False,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else status,
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
"controllerStatus": status,
|
|
"revision": result.get("revision"),
|
|
"verifiedRunners": result.get("verifiedRunners"),
|
|
}
|
|
|
|
|
|
def _approved_connector_call(action: str) -> tuple[Callable[[], dict[str, Any]], str]:
|
|
if action == "deluge.pause_all":
|
|
return lambda: DelugeConnector().pause_all(), "all_torrents_paused"
|
|
if action == "deluge.resume_all":
|
|
return lambda: DelugeConnector().resume_all(), "all_torrents_resumed"
|
|
if action == "plex.scan_all_libraries":
|
|
return lambda: PlexConnector().scan_all_libraries(), "scan_all_started"
|
|
raise ValueError("No approved executor is registered for this action.")
|
|
|
|
|
|
def execute_governed_action(
|
|
session: Session,
|
|
*,
|
|
action: str,
|
|
target: str,
|
|
source: str,
|
|
risk: str,
|
|
reason: str,
|
|
original_policy_decision: str,
|
|
) -> dict[str, Any]:
|
|
"""Execute a typed action after the trusted MCP boundary has evaluated policy.
|
|
|
|
This path deliberately does not create or consume an Approval row. It is used by
|
|
authenticated MCP automation in no-human-approval mode. The central policy still
|
|
fails closed for ``blocked`` actions before this function is called, and only the
|
|
small allowlist of typed rollback/post-check capable executors below is reachable.
|
|
"""
|
|
|
|
if not approval_execution_supported(action):
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "unsupported",
|
|
"message": "No typed MCP executor is registered for this action.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
if action == "controller.artifact.promote":
|
|
if target.strip().lower() != "tower/deployment-controller":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Controller artifact promotion accepts only tower/deployment-controller.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_controller_artifact_promote(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
|
|
if action == "runner.fleet.upgrade_v2":
|
|
if target.strip().lower() != "tower/runner-fleet-v2":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Runner fleet v2 upgrade accepts only tower/runner-fleet-v2.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_runner_fleet_upgrade_v2(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
|
|
if action == "deployment.runnerless.provision":
|
|
return _execute_runnerless_target_provisioning(
|
|
session,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
|
|
if action == "deployment.target.deploy_workmesh":
|
|
if target.strip().lower() != "jens/workmesh":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "WorkMesh first deploy accepts only the fixed jens/workmesh target.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_workmesh_first_deployment(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
|
|
if action == "deployment.target.promote_workmesh":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "approval_required",
|
|
"message": (
|
|
"WorkMesh promotion requires the exact-revision preflight and human approval flow."
|
|
),
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
if action == "deployment.targets.sync":
|
|
if target.strip().lower() != "jens/*":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Deployment target sync accepts only the fixed jens/* catalog target.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_deployment_target_sync(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
|
|
if action in {"unraid.vm.start", "unraid.vm.resume", "unraid.vm.pause"}:
|
|
from .unraid_vm_service import VM_ACTIONS, execute_vm_action
|
|
|
|
vm_action = next(
|
|
(
|
|
name
|
|
for name, definition in VM_ACTIONS.items()
|
|
if definition["action_id"] == action
|
|
),
|
|
None,
|
|
)
|
|
if vm_action not in {"start", "resume", "pause"}:
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "unsupported",
|
|
"message": "No safe VM executor is registered for this action.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
result = execute_vm_action(
|
|
session,
|
|
vm_id=target,
|
|
action=vm_action,
|
|
source=source,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
)
|
|
return {
|
|
**result,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
if action == "deployment.target.register_portfolio":
|
|
if target.strip().lower() != "jens/portfolio":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Portfolio target registration accepts only jens/portfolio.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_portfolio_target_enrollment(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
if action == "deployment.target.register_privatemuse":
|
|
if target.strip().lower() != "jens/privatemuse":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "PrivateMuse target registration accepts only jens/privatemuse.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_privatemuse_target_enrollment(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
if action == "deployment.target.reconcile_media_codec_dashboard":
|
|
if target.strip().lower() != "jens/media-codec-dashboard":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": (
|
|
"Media Codec Dashboard reconciliation accepts only "
|
|
"jens/media-codec-dashboard."
|
|
),
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_media_codec_dashboard_reconciliation(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
if action == "deployment.webhook.repair_privatemuse":
|
|
if target.strip().lower() != "jens/privatemuse":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "PrivateMuse webhook repair accepts only jens/privatemuse.",
|
|
"policyDecision": "blocked",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
return _execute_privatemuse_webhook_repair(
|
|
session,
|
|
source=source,
|
|
risk=risk,
|
|
reason=reason,
|
|
original_policy_decision=original_policy_decision,
|
|
)
|
|
if action == "container.restart":
|
|
from .container_restart_service import execute_container_restart
|
|
|
|
result = execute_container_restart(
|
|
session=session,
|
|
action=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
steps=[
|
|
"Validate MCP policy",
|
|
"Resolve container",
|
|
"Restart container",
|
|
"Post-check health",
|
|
],
|
|
policy_override={
|
|
"decision": "allowed",
|
|
"reason": reason,
|
|
"risk": risk,
|
|
},
|
|
)
|
|
return {
|
|
**result,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
apply_stored_connector_settings(session)
|
|
connector_call, default_message = _approved_connector_call(action)
|
|
steps = _DIRECT_STEPS[action]
|
|
job = create_job(
|
|
session,
|
|
action_id=action,
|
|
target=target,
|
|
source=source,
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(session, job, 35, "MCP policy authorized; calling typed connector.")
|
|
|
|
try:
|
|
connector_result = connector_call()
|
|
success = bool(connector_result.get("success"))
|
|
message = str(
|
|
connector_result.get("message")
|
|
or (default_message if success else "connector_action_failed")
|
|
)
|
|
except Exception as exc: # Connector errors must become an audited failed job.
|
|
success = False
|
|
message = f"{type(exc).__name__}: connector action failed"
|
|
connector_result = {"status": "error"}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="action",
|
|
identity=source,
|
|
action_id=action,
|
|
target=target,
|
|
target_type="approval",
|
|
risk=risk,
|
|
policy_decision="allowed",
|
|
reason=reason,
|
|
result="success" if success else "failed",
|
|
execution_plan={"steps": steps, "jobId": completed.id},
|
|
after_state={"status": connector_result.get("status"), "message": message},
|
|
redacted_metadata={
|
|
"executor": action,
|
|
"integration": "mcp",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
"policyDecision": "allowed",
|
|
"originalPolicyDecision": original_policy_decision,
|
|
}
|
|
|
|
|
|
def execute_approved_action(session: Session, approval: Approval) -> dict[str, Any]:
|
|
if not approval_execution_supported(approval.action):
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "unsupported",
|
|
"message": "Deze goedgekeurde actie heeft nog geen rollback-veilige executor.",
|
|
}
|
|
|
|
if approval.action == "controller.artifact.promote":
|
|
if approval.target.strip().lower() != "tower/deployment-controller":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Controller artifact promotion accepts only tower/deployment-controller.",
|
|
}
|
|
return _execute_controller_artifact_promote(
|
|
session,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
|
|
if approval.action == "deployment.runnerless.provision":
|
|
return _execute_runnerless_target_provisioning(
|
|
session,
|
|
target=approval.target,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
|
|
if approval.action == "runner.fleet.upgrade_v2":
|
|
if approval.target.strip().lower() != "tower/runner-fleet-v2":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Runner fleet v2 upgrade accepts only tower/runner-fleet-v2.",
|
|
}
|
|
return _execute_runner_fleet_upgrade_v2(
|
|
session,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
|
|
if approval.action in {"unraid.vm.start", "unraid.vm.resume", "unraid.vm.pause"}:
|
|
from .unraid_vm_service import execute_approved_vm_action
|
|
|
|
return execute_approved_vm_action(session, approval)
|
|
|
|
if approval.action == "deployment.target.promote_workmesh":
|
|
from .workmesh_promotion import WorkMeshPromotionService
|
|
|
|
return WorkMeshPromotionService().execute_approved(session, approval)
|
|
|
|
if approval.action == "deployment.target.register_portfolio":
|
|
if approval.target.strip().lower() != "jens/portfolio":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "Portfolio target registration accepts only jens/portfolio.",
|
|
}
|
|
return _execute_portfolio_target_enrollment(
|
|
session,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
if approval.action == "deployment.target.register_privatemuse":
|
|
if approval.target.strip().lower() != "jens/privatemuse":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "PrivateMuse target registration accepts only jens/privatemuse.",
|
|
}
|
|
return _execute_privatemuse_target_enrollment(
|
|
session,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
if approval.action == "deployment.target.reconcile_media_codec_dashboard":
|
|
if approval.target.strip().lower() != "jens/media-codec-dashboard":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": (
|
|
"Media Codec Dashboard reconciliation accepts only "
|
|
"jens/media-codec-dashboard."
|
|
),
|
|
}
|
|
return _execute_media_codec_dashboard_reconciliation(
|
|
session,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
if approval.action == "deployment.webhook.repair_privatemuse":
|
|
if approval.target.strip().lower() != "jens/privatemuse":
|
|
return {
|
|
"success": False,
|
|
"status": "failed",
|
|
"result": "blocked",
|
|
"message": "PrivateMuse webhook repair accepts only jens/privatemuse.",
|
|
}
|
|
return _execute_privatemuse_webhook_repair(
|
|
session,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
original_policy_decision="approval_required",
|
|
)
|
|
if approval.action == "container.restart":
|
|
from .container_restart_service import execute_container_restart
|
|
|
|
return execute_container_restart(
|
|
session=session,
|
|
action=approval.action,
|
|
target=approval.target,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
steps=[
|
|
"Load approved request",
|
|
"Resolve container",
|
|
"Restart container",
|
|
"Post-check health",
|
|
],
|
|
approved=True,
|
|
)
|
|
|
|
apply_stored_connector_settings(session)
|
|
connector_call, default_message = _approved_connector_call(approval.action)
|
|
steps = _APPROVAL_STEPS[approval.action]
|
|
job = create_job(
|
|
session,
|
|
action_id=approval.action,
|
|
target=approval.target,
|
|
source="approved_operator",
|
|
risk=approval.risk,
|
|
policy_decision="approval_required",
|
|
steps=steps,
|
|
)
|
|
start_job(session, job)
|
|
set_job_progress(
|
|
session, job, 35, f"Approval {approval.id} validated; calling connector."
|
|
)
|
|
|
|
try:
|
|
connector_result = connector_call()
|
|
success = bool(connector_result.get("success"))
|
|
message = str(
|
|
connector_result.get("message")
|
|
or (default_message if success else "connector_action_failed")
|
|
)
|
|
except Exception as exc: # Connector errors must become an audited failed job.
|
|
success = False
|
|
message = f"{type(exc).__name__}: connector action failed"
|
|
connector_result = {"status": "error"}
|
|
|
|
completed = complete_job(
|
|
session,
|
|
job,
|
|
status="succeeded" if success else "failed",
|
|
result_summary=message,
|
|
)
|
|
audit = log_event(
|
|
session,
|
|
source="approval",
|
|
identity="operator",
|
|
action_id=approval.action,
|
|
target=approval.target,
|
|
target_type="approval",
|
|
risk=approval.risk,
|
|
policy_decision="approval_required",
|
|
reason=approval.reason or f"Approved through {approval.id}.",
|
|
result="success" if success else "failed",
|
|
execution_plan={
|
|
"steps": steps,
|
|
"approvalId": approval.id,
|
|
"jobId": completed.id,
|
|
},
|
|
after_state={"status": connector_result.get("status"), "message": message},
|
|
redacted_metadata={"approvalId": approval.id, "executor": approval.action},
|
|
)
|
|
return {
|
|
"success": success,
|
|
"status": "success" if success else "failed",
|
|
"result": "success" if success else "failed",
|
|
"message": message,
|
|
"jobId": completed.id,
|
|
"auditId": audit.id,
|
|
}
|