Publish curated ITWorx_MCP_Hub source from 6c7434368ce2a594005983c5a6601a31a639e7f1

This commit is contained in:
Public Source Publisher committed 2026-10-01 18:03:00 +00:00
1 parent 77946d62c4
commit 6d40ab975c
86 files changed
+6784 -1478

No files matched your search

+2
View File
@@ -23,6 +23,7 @@ against every route.
| tool.invoke | | | X | X |
| operations.check | | | X | X |
| client.bootstrap | | | X | X |
| client.verify | | | X | X |
| client.disable | | | X | X |
| client.revoke | | | X | X |
| client.create | | | | X |
@@ -62,6 +63,7 @@ ENDPOINT_PERMISSIONS: Mapping[str, frozenset[ManagementRole]] = {
"operations.check": frozenset({_R.OPERATOR, _R.ADMIN}),
"client.read": frozenset({_R.VIEWER, _R.AUDITOR, _R.OPERATOR, _R.ADMIN}),
"client.bootstrap": frozenset({_R.OPERATOR, _R.ADMIN}),
"client.verify": frozenset({_R.OPERATOR, _R.ADMIN}),
"client.disable": frozenset({_R.OPERATOR, _R.ADMIN}),
"client.revoke": frozenset({_R.OPERATOR, _R.ADMIN}),
"client.create": frozenset({_R.ADMIN}),
+4 -1
View File
@@ -150,6 +150,7 @@ class CatalogLoader:
documents: list[CatalogDocument] = []
source_files: list[str] = []
seen: set[tuple[str, str]] = set()
schema_store: dict[str, Any] | None = None
if not self.root.is_dir():
return ValidationReport(
valid=False,
@@ -191,7 +192,9 @@ class CatalogLoader:
continue
issues.extend(self._secret_issues(raw, path, []))
schema = self._schema(schema_name)
resolver = RefResolver.from_schema(schema, store=self._schema_store())
if schema_store is None:
schema_store = self._schema_store()
resolver = RefResolver.from_schema(schema, store=schema_store)
for error in sorted(
Draft202012Validator(schema, resolver=resolver).iter_errors(raw),
key=lambda item: list(item.path),
+44 -3
View File
@@ -9,7 +9,13 @@ from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Request, status
from pydantic import BaseModel, ConfigDict, Field
from packages.hub_clients import BootstrapHandle, ClientConfig, ClientKind, ClientRecord
from packages.hub_clients import (
BootstrapHandle,
ClientConfig,
ClientKind,
ClientRecord,
ClientStatus,
)
from .service import ClientService
@@ -50,6 +56,9 @@ def build_client_router(
*,
authenticate: Callable[[Request], Any] = _deny_by_default,
authorize: Callable[[Any, str], None] = _deny_all_actions,
onboarding_status: Callable[[UUID], dict[str, Any]] | None = None,
verify_onboarding: Callable[[UUID, Any], dict[str, Any]] | None = None,
transition_client: Callable[[UUID, ClientStatus, Any], ClientRecord] | None = None,
prefix: str = "/clients",
token_endpoint: str = "https://auth.example.invalid/application/o/token/", # noqa: S107
oauth_client_id: str = "itworx-mcp-hub",
@@ -112,6 +121,28 @@ def build_client_router(
except KeyError as exc:
raise HTTPException(status_code=404, detail="client not found") from exc
@router.get("/{client_id}/onboarding-status")
def onboarding(client_id: UUID, principal: Any = authenticated) -> dict[str, Any]:
authorize(principal, "client.read")
if onboarding_status is None:
raise HTTPException(status_code=404, detail="client onboarding status is unavailable")
try:
return onboarding_status(client_id)
except KeyError as exc:
raise HTTPException(status_code=404, detail="onboarding client not found") from exc
@router.post("/{client_id}/verify")
def verify(client_id: UUID, principal: Any = authenticated) -> dict[str, Any]:
authorize(principal, "client.verify")
if verify_onboarding is None:
raise HTTPException(
status_code=404, detail="client onboarding verification is unavailable"
)
try:
return verify_onboarding(client_id, principal)
except KeyError as exc:
raise HTTPException(status_code=404, detail="onboarding client not found") from exc
@router.post("/{client_id}/bootstrap", response_model=BootstrapHandle)
def bootstrap(client_id: UUID, principal: Any = authenticated) -> BootstrapHandle:
authorize(principal, "client.bootstrap")
@@ -126,15 +157,25 @@ def build_client_router(
def disable(client_id: UUID, principal: Any = authenticated) -> ClientRecord:
authorize(principal, "client.disable")
try:
return service.disable(client_id)
return (
transition_client(client_id, ClientStatus.DISABLED, principal)
if transition_client is not None
else service.disable(client_id)
)
except KeyError as exc:
raise HTTPException(status_code=404, detail="client not found") from exc
except ValueError as exc:
raise HTTPException(status_code=409, detail=str(exc)) from exc
@router.post("/{client_id}/revoke", response_model=ClientRecord)
def revoke(client_id: UUID, principal: Any = authenticated) -> ClientRecord:
authorize(principal, "client.revoke")
try:
return service.revoke(client_id)
return (
transition_client(client_id, ClientStatus.REVOKED, principal)
if transition_client is not None
else service.revoke(client_id)
)
except KeyError as exc:
raise HTTPException(status_code=404, detail="client not found") from exc
@@ -8,6 +8,8 @@ from uuid import NAMESPACE_URL, UUID, uuid5
from sqlalchemy import select
from sqlalchemy.orm import Session
from packages.hub_clients import ClientKind
from .models import (
ClientBindingRow,
ClientRow,
@@ -114,6 +116,12 @@ def provision_machine_client(
or by_id.status != "pending"
):
raise ValueError("existing Hub client is not an activatable pending identity")
try:
kind = ClientKind(existing_metadata.get("kind", ClientKind.STDIO_BRIDGE.value))
except (TypeError, ValueError) as exc:
raise ValueError("pending machine client has an invalid client kind") from exc
else:
kind = ClientKind.STDIO_BRIDGE
client = principal or by_id
metadata = {
"managedBy": "authentik-machine-provisioning",
@@ -121,7 +129,7 @@ def provision_machine_client(
"name": name,
"project": project_slug,
"environment": environment_name,
"kind": "stdio-bridge",
"kind": kind.value,
"oauthUsername": oauth_username,
"credentialReference": f"authentik://service-account/{oauth_username}",
"operatorDisabled": False,
+55 -6
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
import hashlib
import json
from datetime import UTC, datetime, timedelta
from typing import Any
from uuid import UUID, uuid4
@@ -14,7 +16,9 @@ from packages.hub_clients import (
ClientStatus,
generate_config,
)
from services.control_api.auth.models import AuthenticatedPrincipal
from services.control_api.persistence.models import (
AuditEventRow,
ClientBindingRow,
ClientRow,
EnvironmentRow,
@@ -158,13 +162,21 @@ class PersistentClientService:
selected = record if kind is None else record.model_copy(update={"kind": kind})
return generate_config(selected, public_host=self.public_host)
def _transition(self, client_id: UUID, status: ClientStatus) -> ClientRecord:
def transition(
self, client_id: UUID, status: ClientStatus, actor: AuthenticatedPrincipal | None = None
) -> ClientRecord:
now = datetime.now(UTC)
with self.sessions() as session, session.begin():
row = session.get(ClientRow, client_id)
row = session.scalar(
select(ClientRow)
.join(WorkspaceRow, WorkspaceRow.id == ClientRow.workspace_id)
.where(ClientRow.id == client_id, WorkspaceRow.slug == "itworx")
)
if row is None:
raise KeyError(client_id)
metadata = dict(row.record_metadata or {})
if row.status == "revoked" and status is ClientStatus.DISABLED:
raise ValueError("revoked clients cannot be changed to disabled")
metadata["operatorDisabled"] = True
if status is ClientStatus.DISABLED:
metadata["disabledAt"] = now.isoformat()
@@ -173,18 +185,55 @@ class PersistentClientService:
row.status = "revoked"
row.revoked_at = now
row.record_metadata = metadata
for binding in session.scalars(
bindings = session.scalars(
select(ClientBindingRow).where(ClientBindingRow.client_id == client_id)
).all():
).all()
for binding in bindings:
binding.enabled = False
scope_binding = bindings[0] if len(bindings) == 1 else None
scope_server = (
session.get(VirtualServerRow, scope_binding.virtual_server_id)
if scope_binding is not None
else None
)
session.flush()
action = "client.disable" if status is ClientStatus.DISABLED else "client.revoke"
arguments = {"clientId": str(client_id), "action": action}
session.add(
AuditEventRow(
id=uuid4(),
occurred_at=now,
trace_id=str(uuid4()),
workspace_id=row.workspace_id,
project_id=scope_binding.project_id if scope_binding else None,
environment_id=scope_server.environment_id if scope_server else None,
virtual_server_id=scope_server.id if scope_server else None,
client_id=row.id,
event_type=action,
tool_name=action,
principal_issuer=(actor.issuer if actor is not None else self.issuer)[:512],
principal_subject=(
actor.subject if actor is not None else "runtime-client-management"
)[:256],
policy_decision="allow",
matched_rule_ids=[action],
policy_trace=[{"action": action, "decision": "allow"}],
arguments_hash=hashlib.sha256(
json.dumps(arguments, sort_keys=True).encode("utf-8")
).hexdigest(),
sanitized_arguments=arguments,
duration_ms=0,
outcome="success",
retention_until=now + timedelta(days=30),
)
)
return self._record(row)
def disable(self, client_id: UUID) -> ClientRecord:
return self._transition(client_id, ClientStatus.DISABLED)
return self.transition(client_id, ClientStatus.DISABLED)
def revoke(self, client_id: UUID) -> ClientRecord:
return self._transition(client_id, ClientStatus.REVOKED)
return self.transition(client_id, ClientStatus.REVOKED)
def bootstrap(self, client_id: UUID) -> BootstrapHandle:
record = self._get(client_id)
+4 -4
View File
@@ -677,9 +677,7 @@ def build_server() -> MCPServer[Any]:
)
async def portfolio_governance_apply(
context: Context[Any, Any],
plans: Annotated[
list[PortfolioGovernanceApplyPlan], Field(min_length=1, max_length=5)
],
plans: Annotated[list[PortfolioGovernanceApplyPlan], Field(min_length=1, max_length=5)],
) -> dict[str, Any]:
"""Apply at most five exact governance plans; every item is independently verified."""
return connector.portfolio_governance_apply(
@@ -813,7 +811,9 @@ def build_server() -> MCPServer[Any]:
structured_output=True,
)
async def pull_request_validation_ensure(
repositoryRef: str, number: int, expectedHeadSha: str,
repositoryRef: str,
number: int,
expectedHeadSha: str,
context: Context[Any, Any],
) -> dict[str, Any]:
"""Ensure a real canonical full PR run for the exact current head."""
File diff suppressed because it is too large. Load diff