mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-06 07:09:09 +08:00
fix(agent): separate public API queries from bound user operations
This commit is contained in:
@@ -15,7 +15,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from app.agent.policy.api import API_OPERATION_ROUTES # noqa: E402
|
||||
from app.agent.policy.api import API_OPERATION_ROUTES, API_OPERATION_SPECS # noqa: E402
|
||||
from app.api.apiv1 import api_router # noqa: E402
|
||||
|
||||
JSON_OUTPUT = PROJECT_ROOT / "docs/refactor/agent-api-surface-audit.json"
|
||||
@@ -302,6 +302,19 @@ def generate_audit() -> dict[str, Any]:
|
||||
"dynamic_gateway_routes": dynamic_gateway_routes,
|
||||
"disposition_counts": dict(sorted(counts.items())),
|
||||
"operations": entries,
|
||||
"gateway_identity_contracts": [
|
||||
{
|
||||
"operation_id": spec.operation_id,
|
||||
"method": API_OPERATION_ROUTES[spec.operation_id].method,
|
||||
"path": API_OPERATION_ROUTES[spec.operation_id].path,
|
||||
"identity_scope": spec.identity_scope.value,
|
||||
"required_role": spec.required_role.value,
|
||||
"effect": spec.effect.value,
|
||||
"result_sensitivity": spec.result_sensitivity.value,
|
||||
"confirmation": spec.confirmation.value,
|
||||
}
|
||||
for spec in sorted(API_OPERATION_SPECS, key=lambda item: item.operation_id)
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -339,6 +352,26 @@ def render_markdown(audit: dict[str, Any]) -> str:
|
||||
}
|
||||
for disposition, count in audit["disposition_counts"].items():
|
||||
lines.append(f"| `{disposition}` | {count} | {meanings[disposition]} |")
|
||||
lines.extend([
|
||||
"",
|
||||
"## Gateway Identity Audit",
|
||||
"",
|
||||
"All gateway operations are audited below. New operations default to bound_user; safe_read alone never grants public access.",
|
||||
"public: audited external public metadata only; the host-authenticated executor cannot call other operations.",
|
||||
"bound_user: an active account bound to the stable channel sender ID, or the authenticated Web user ID; endpoint ownership and management permissions still apply.",
|
||||
"admin: administrator authority, preserving existing verified channel/API integration semantics; this never substitutes for ownership on bound_user operations.",
|
||||
"Title recognition retains bound_user because its Context exposes locally configured applied identification rules. File recognition, source availability, rules, search results, media libraries, storage and public UI settings remain instance data.",
|
||||
"Plugin ratings include this installation's own rating and require the same administrator role as their REST dependencies. Community share/popularity/statistics and global plugin installation statistics are public reads; follow lists and rating submissions are not.",
|
||||
"",
|
||||
"| operation | method | path | identity scope | role | effect | result sensitivity | confirmation |",
|
||||
"| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |",
|
||||
])
|
||||
for item in audit["gateway_identity_contracts"]:
|
||||
lines.append(
|
||||
f"| `{item['operation_id']}` | `{item['method']}` | `{item['path']}` | "
|
||||
f"`{item['identity_scope']}` | `{item['required_role']}` | `{item['effect']}` | "
|
||||
f"`{item['result_sensitivity']}` | `{item['confirmation']}` |"
|
||||
)
|
||||
if audit["dynamic_gateway_routes"]:
|
||||
lines.extend(
|
||||
[
|
||||
|
||||
@@ -332,6 +332,7 @@ def _render_api_docs() -> str:
|
||||
f"### `{operation_id}`",
|
||||
f"`{route.method} {route.path}`; policy effect: `{effect}`.",
|
||||
f"Purpose: {description.split(' Method:', 1)[0].strip()}",
|
||||
f"Identity scope: `{specs[operation_id].identity_scope.value}`; required role: `{specs[operation_id].required_role.value}`.",
|
||||
]
|
||||
)
|
||||
collection_contract = branch.get("x-moviepilot-collection")
|
||||
|
||||
Reference in New Issue
Block a user