Publish curated ITWorx_MCP_Hub source from 6c7434368ce2a594005983c5a6601a31a639e7f1
This commit is contained in:
1 parent
77946d62c4
commit
6d40ab975c
86 files changed
+6784
-1478
No files matched your search
@@ -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}),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user