chore(skills): docs + ruff format for skill-management-console
Tests / Test passed: 855

Documents Skill Management in CLOUD_DEPLOYMENT.md (cloud-skill store,
per-host entitlement, incremental sync, local authoring/override,
inventory report, skills:admin scope) and applies ruff check/format to
all touched modules. All tasks complete; full non-integration suite
green (593 passed) and openspec validate --strict passes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 08:10:20 +08:00
co-authored by Claude Opus 4.6
parent fd0ea3a066
commit f8054cb58c
9 changed files with 83 additions and 53 deletions
+37 -11
View File
@@ -8,6 +8,7 @@ Two routers:
heartbeat/planner-decision) endpoints an agent uses to pull incremental
skill deltas and report its local-skill inventory.
"""
from __future__ import annotations
import json
@@ -16,7 +17,12 @@ from uuid import uuid4
from fastapi import APIRouter, HTTPException, Query, Request, status
from cloud.auth import AuthProvider, HostAuthorizationError, Principal, SKILLS_ADMIN_SCOPE
from cloud.auth import (
AuthProvider,
HostAuthorizationError,
Principal,
SKILLS_ADMIN_SCOPE,
)
from cloud.observability import current_correlation_id
from cloud.skills import (
CloudSkillConflictError,
@@ -86,7 +92,9 @@ def create_skill_management_router(
authorize(request)
skill = service.get_skill(skill_id)
if skill is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Skill not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Skill not found"
)
return _skill_response(skill)
@router.post(
@@ -112,9 +120,13 @@ def create_skill_management_router(
now=utc_now(),
)
except CloudSkillValidationError as exc:
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc)) from exc
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc)
) from exc
except CloudSkillConflictError as exc:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail=str(exc)
) from exc
_audit(repository, principal, skill.id, "cloud_skill_create")
return _skill_response(skill)
@@ -139,9 +151,13 @@ def create_skill_management_router(
now=utc_now(),
)
except CloudSkillValidationError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Skill not found") from exc
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Skill not found"
) from exc
except CloudSkillConflictError as exc:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail=str(exc)
) from exc
_audit(repository, principal, skill.id, "cloud_skill_update")
return _skill_response(skill)
@@ -152,14 +168,18 @@ def create_skill_management_router(
try:
service.delete_skill(skill_id)
except KeyError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Skill not found") from exc
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Skill not found"
) from exc
_audit(repository, principal, skill_id, "cloud_skill_delete")
@router.get(
"/skills/{skill_id}/entitlements",
response_model=CloudSkillEntitlementListResponse,
)
def list_entitlements(skill_id: str, request: Request) -> CloudSkillEntitlementListResponse:
def list_entitlements(
skill_id: str, request: Request
) -> CloudSkillEntitlementListResponse:
authorize(request)
return CloudSkillEntitlementListResponse(
skill_id=skill_id,
@@ -176,7 +196,9 @@ def create_skill_management_router(
try:
service.grant_entitlement(skill_id, host_id, now=utc_now())
except CloudSkillValidationError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)
) from exc
_audit(repository, principal, skill_id, "cloud_skill_entitlement_grant")
@router.delete(
@@ -193,7 +215,9 @@ def create_skill_management_router(
"/hosts/{host_id}/skill-inventory",
response_model=HostSkillInventoryResponse,
)
def get_host_inventory(host_id: str, request: Request) -> HostSkillInventoryResponse:
def get_host_inventory(
host_id: str, request: Request
) -> HostSkillInventoryResponse:
authorize(request)
entry = service.get_host_inventory(host_id)
if entry is None:
@@ -231,7 +255,9 @@ def create_skill_host_router(
try:
principal.require_host(host_id)
except HostAuthorizationError as exc:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(exc)) from exc
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail=str(exc)
) from exc
@router.get("/hosts/{host_id}/skills/sync", response_model=CloudSkillSyncResponse)
def sync_skills(