docs: plan auth admin read surface

This commit is contained in:
lda
2026-06-06 11:21:50 +07:00 Verified
parent 645d9f3c5d
commit 58771e4423
3 changed files with 927 additions and 0 deletions
@@ -0,0 +1,903 @@
# Auth Admin Read Slice 3 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a read-only auth admin surface that lists and inspects auth records without exposing secret payload values.
**Architecture:** Extend the existing neutral `WorkflowAdminApi` surface instead of creating a new top-level server field. Providers return safe auth summaries only: id, scheme, metadata, payload keys. MCP implements the provider from its existing store; JSON-RPC and CLI expose read-only methods. No save/delete/auth mutation and no provider-specific display promises in this slice.
**Tech Stack:** Python 3.14, dataclasses, protocols, Typer, JSON-RPC HTTP, pytest, ruff, basedpyright.
---
## Scope
Implement only:
- read-only auth summaries
- inspect one auth summary by auth ref
- JSON-RPC methods
- RPC client methods
- CLI commands under `wf admin auth`
Do not implement:
- secret payload output
- auth save/delete/update commands
- provider-specific display structs
- OAuth/secret-manager behavior
- changes to source registry mutation behavior
## Files
- Modify: `src/wf_api/admin.py`
- add `WorkflowAdminAuthProvider`
- add optional auth provider to `WorkflowAdminApi`
- add `list_auth_records` / `inspect_auth_record`
- Modify: `src/wf_api/surface.py`
- add auth methods to `WorkflowAdminSurface`
- Modify: `src/wf_api/__init__.py`
- export `WorkflowAdminAuthProvider`
- Modify: `src/wf_mcp/storage/store.py`
- add `list_auth_refs`
- Create: `src/wf_mcp/broker/service/auth_admin.py`
- `McpAuthAdminProvider`
- Modify: `src/wf_mcp/broker/service/upstream_transport.py`
- expose auth admin provider or list refs through store if needed
- Modify: `src/wf_mcp/broker/server.py`
- wire `WorkflowAdminApi(..., auth=...)`
- Modify: `src/wf_server/context.py`
- local/static admin uses no auth provider and reports unavailable
- Modify: `src/wf_transport_rpc_http/methods_admin.py`
- register `workflow.admin.auth.list` / `.inspect`
- Modify: `src/wf_transport_rpc_http/models.py`
- add `InspectAuthParams`
- Modify: `src/wf_transport_rpc_http/client_admin.py`
- add client methods
- Modify: `src/wf_cli/commands/admin.py`
- add auth sub-Typer
- Create: `src/wf_cli/commands/auth_admin.py`
- `wf admin auth list` / `inspect`
- Tests:
- `tests/wf_api/test_admin_api.py` or create if absent
- `tests/wf_mcp/service/test_auth_admin.py`
- `tests/wf_transport_rpc_http/test_admin_auth_rpc.py`
- `tests/wf_cli/test_auth_admin.py`
- Docs:
- `docs/current_roadmap.md`
- `docs/superpowers/specs/2026-06-06-auth-source-secrets-boundary.md`
## Task 1: Neutral admin auth surface
**Files:**
- Modify: `src/wf_api/admin.py`
- Modify: `src/wf_api/surface.py`
- Modify: `src/wf_api/__init__.py`
- Test: `tests/wf_api/test_admin_api.py`
- [ ] **Step 1: Add/extend wf_api admin tests**
If `tests/wf_api/test_admin_api.py` does not exist, create it with the imports
below. If it exists, append these tests.
```python
from __future__ import annotations
import pytest
from wf_api.admin import WorkflowAdminApi
class EmptyConnectionProvider:
def list_connections(self):
return []
def get_connection_statuses(self):
return []
class EmptyEventProvider:
def list_events(self):
return []
class AuthProvider:
def list_auth_records(self):
return [
{
"id": "github.work",
"scheme": "bearer",
"metadata": {"owner": "platform"},
"payload_keys": ["token"],
},
{
"id": "api.work",
"scheme": "headers",
"metadata": {},
"payload_keys": ["headers"],
},
]
def inspect_auth_record(self, auth_ref: str):
for record in self.list_auth_records():
if record["id"] == auth_ref:
return record
raise KeyError(auth_ref)
def _api(auth=None) -> WorkflowAdminApi:
return WorkflowAdminApi(
connections=EmptyConnectionProvider(),
events=EmptyEventProvider(),
auth=auth,
)
async def test_admin_lists_auth_records_sorted_without_payload_values() -> None:
payload = await _api(AuthProvider()).list_auth_records()
assert payload["total"] == 2
assert [record["id"] for record in payload["auth_records"]] == [
"api.work",
"github.work",
]
assert payload["auth_records"][0]["payload_keys"] == ["headers"]
assert "payload" not in payload["auth_records"][0]
async def test_admin_inspects_auth_record_without_payload_values() -> None:
payload = await _api(AuthProvider()).inspect_auth_record("github.work")
assert payload == {
"id": "github.work",
"scheme": "bearer",
"metadata": {"owner": "platform"},
"payload_keys": ["token"],
}
async def test_admin_auth_methods_report_unavailable_without_provider() -> None:
with pytest.raises(RuntimeError, match="auth admin is not available"):
await _api().list_auth_records()
with pytest.raises(RuntimeError, match="auth admin is not available"):
await _api().inspect_auth_record("github.work")
```
- [ ] **Step 2: Run tests to verify failure**
Run:
```bash
uv run pytest tests/wf_api/test_admin_api.py -q
```
Expected: fails because `WorkflowAdminApi` does not accept `auth` and auth methods do not exist.
- [ ] **Step 3: Add provider protocol and API methods**
Modify `src/wf_api/admin.py`.
Add protocol:
```python
class WorkflowAdminAuthProvider(Protocol):
"""Provides read-only auth inventory without secret payload values."""
def list_auth_records(self) -> Sequence[Mapping[str, Any] | object]: ...
def inspect_auth_record(self, auth_ref: str) -> Mapping[str, Any] | object: ...
```
Change `WorkflowAdminApi.__init__` signature:
```python
def __init__(
self,
*,
connections: WorkflowAdminConnectionProvider,
events: WorkflowAdminEventProvider,
auth: WorkflowAdminAuthProvider | None = None,
) -> None:
self.connections = connections
self.events = events
self.auth = auth
```
Add methods:
```python
async def list_auth_records(self) -> dict[str, Any]:
if self.auth is None:
raise RuntimeError("auth admin is not available for this target")
records = sorted(
(_payload(item) for item in self.auth.list_auth_records()),
key=lambda item: str(item.get("id", "")),
)
return {"auth_records": records, "total": len(records)}
async def inspect_auth_record(self, auth_ref: str) -> dict[str, Any]:
if self.auth is None:
raise RuntimeError("auth admin is not available for this target")
return _payload(self.auth.inspect_auth_record(auth_ref))
```
- [ ] **Step 4: Update surface protocol**
Modify `src/wf_api/surface.py`.
In `WorkflowAdminSurface`, add:
```python
async def list_auth_records(self) -> dict[str, Any]: ...
async def inspect_auth_record(self, auth_ref: str) -> dict[str, Any]: ...
```
If `Any` is not imported in that file, add:
```python
from typing import Any
```
- [ ] **Step 5: Export provider**
Modify `src/wf_api/__init__.py`.
Add to admin import:
```python
WorkflowAdminAuthProvider,
```
Add to `__all__`:
```python
"WorkflowAdminAuthProvider",
```
- [ ] **Step 6: Run focused tests**
Run:
```bash
uv run pytest tests/wf_api/test_admin_api.py tests/wf_api/test_import_direction.py -q
uv run ruff check src/wf_api/admin.py src/wf_api/surface.py src/wf_api/__init__.py tests/wf_api/test_admin_api.py
uv run basedpyright --level error src/wf_api tests/wf_api/test_admin_api.py
```
Expected: all pass.
## Task 2: MCP auth admin provider
**Files:**
- Modify: `src/wf_mcp/storage/store.py`
- Create: `src/wf_mcp/broker/service/auth_admin.py`
- Test: `tests/wf_mcp/service/test_auth_admin.py`
- [ ] **Step 1: Add provider tests**
Create `tests/wf_mcp/service/test_auth_admin.py`:
```python
from __future__ import annotations
from pathlib import Path
import pytest
from wf_mcp.broker.service.auth_admin import McpAuthAdminProvider
from wf_mcp.models import AuthRecord
from wf_mcp.storage import FileStore
def _store(tmp_path: Path) -> FileStore:
return FileStore(tmp_path)
def test_auth_admin_lists_safe_summaries_sorted(tmp_path: Path) -> None:
store = _store(tmp_path)
store.save_auth(
AuthRecord(
connection_id="github.work",
scheme="bearer",
payload={"token": "secret", "headers": {"Authorization": "Bearer secret"}},
)
)
store.save_auth(
AuthRecord(
connection_id="api.work",
scheme="headers",
payload={"headers": {"X-API-Key": "secret"}},
)
)
provider = McpAuthAdminProvider(store=store)
records = provider.list_auth_records()
assert records == [
{
"id": "api.work",
"scheme": "headers",
"metadata": {},
"payload_keys": ["headers"],
},
{
"id": "github.work",
"scheme": "bearer",
"metadata": {},
"payload_keys": ["headers", "token"],
},
]
def test_auth_admin_inspects_safe_summary(tmp_path: Path) -> None:
store = _store(tmp_path)
store.save_auth(
AuthRecord(
connection_id="github.work",
scheme="bearer",
payload={"token": "secret"},
)
)
provider = McpAuthAdminProvider(store=store)
assert provider.inspect_auth_record("github.work") == {
"id": "github.work",
"scheme": "bearer",
"metadata": {},
"payload_keys": ["token"],
}
def test_auth_admin_inspect_unknown_raises_key_error(tmp_path: Path) -> None:
provider = McpAuthAdminProvider(store=_store(tmp_path))
with pytest.raises(KeyError, match="unknown auth record"):
provider.inspect_auth_record("missing.auth")
```
- [ ] **Step 2: Run tests to verify failure**
Run:
```bash
uv run pytest tests/wf_mcp/service/test_auth_admin.py -q
```
Expected: fails because `McpAuthAdminProvider` does not exist and `FileStore` cannot list auth refs.
- [ ] **Step 3: Add `list_auth_refs` to store**
Modify `src/wf_mcp/storage/store.py`.
Add to `class Store`:
```python
def list_auth_refs(self) -> list[str]:
raise NotImplementedError
```
Add to `class FileStore`:
```python
def list_auth_refs(self) -> list[str]:
"""Return auth refs present in the local file auth store."""
return sorted(path.stem for path in self.auth_dir.glob("*.json"))
```
- [ ] **Step 4: Create MCP auth admin provider**
Create `src/wf_mcp/broker/service/auth_admin.py`:
```python
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from wf_api import WorkflowAdminAuthProvider
from ...storage import Store
@dataclass(frozen=True, slots=True)
class McpAuthAdminProvider(WorkflowAdminAuthProvider):
"""Read-only auth inventory for MCP-backed workflow servers.
Summaries intentionally expose payload keys, not payload values. Concrete
auth variants can provide richer safe display later.
"""
store: Store
def list_auth_records(self) -> list[dict[str, Any]]:
return [
self.inspect_auth_record(auth_ref)
for auth_ref in sorted(self.store.list_auth_refs())
]
def inspect_auth_record(self, auth_ref: str) -> dict[str, Any]:
record = self.store.load_auth(auth_ref)
if record is None:
raise KeyError(f"unknown auth record {auth_ref!r}")
return {
"id": record.connection_id,
"scheme": record.scheme,
"metadata": {},
"payload_keys": sorted(str(key) for key in record.payload),
}
__all__ = ["McpAuthAdminProvider"]
```
- [ ] **Step 5: Run focused tests**
Run:
```bash
uv run pytest tests/wf_mcp/service/test_auth_admin.py tests/wf_mcp/test_store.py -q
uv run ruff check src/wf_mcp/storage/store.py src/wf_mcp/broker/service/auth_admin.py tests/wf_mcp/service/test_auth_admin.py
uv run basedpyright --level error src/wf_mcp/storage/store.py src/wf_mcp/broker/service/auth_admin.py tests/wf_mcp/service/test_auth_admin.py
```
Expected: all pass.
## Task 3: Wire MCP-backed server admin auth provider
**Files:**
- Modify: `src/wf_mcp/broker/server.py`
- Test: `tests/wf_mcp/test_mcp_workflow_server.py`
- [ ] **Step 1: Add server wiring test**
Append to `tests/wf_mcp/test_mcp_workflow_server.py`:
```python
async def test_workflow_server_from_service_exposes_auth_admin(tmp_path: Path) -> None:
from wf_mcp.models import AuthRecord
service = WfMcpService(store=FileStore(tmp_path))
service.save_auth(
AuthRecord(
connection_id="github.work",
scheme="bearer",
payload={"token": "secret"},
)
)
server = workflow_server_from_service(service)
payload = await server.admin.list_auth_records()
assert payload["auth_records"] == [
{
"id": "github.work",
"scheme": "bearer",
"metadata": {},
"payload_keys": ["token"],
}
]
```
If the file uses a helper for `WfMcpService`, follow its existing style but keep
`tmp_path`.
- [ ] **Step 2: Run test to verify failure**
Run:
```bash
uv run pytest tests/wf_mcp/test_mcp_workflow_server.py::test_workflow_server_from_service_exposes_auth_admin -q
```
Expected: fails because MCP-backed server does not wire an auth provider.
- [ ] **Step 3: Wire provider**
Modify `src/wf_mcp/broker/server.py`.
Add import:
```python
from .service.auth_admin import McpAuthAdminProvider
```
Find `WorkflowAdminApi(...)` construction in `workflow_server_from_service`.
Change it to pass:
```python
auth=McpAuthAdminProvider(store=service.store),
```
Do not add an auth provider to local/static server construction.
- [ ] **Step 4: Run focused tests**
Run:
```bash
uv run pytest tests/wf_mcp/test_mcp_workflow_server.py tests/wf_server/test_local_static_server.py -q
uv run ruff check src/wf_mcp/broker/server.py tests/wf_mcp/test_mcp_workflow_server.py
uv run basedpyright --level error src/wf_mcp/broker/server.py tests/wf_mcp/test_mcp_workflow_server.py
```
Expected: all pass. Local/static server should still report auth admin unavailable through `WorkflowAdminApi`.
## Task 4: JSON-RPC methods and client
**Files:**
- Modify: `src/wf_transport_rpc_http/models.py`
- Modify: `src/wf_transport_rpc_http/methods_admin.py`
- Modify: `src/wf_transport_rpc_http/client_admin.py`
- Test: `tests/wf_transport_rpc_http/test_admin_auth_rpc.py`
- [ ] **Step 1: Add RPC tests**
Create `tests/wf_transport_rpc_http/test_admin_auth_rpc.py`:
```python
from __future__ import annotations
import pytest
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.server import workflow_server_from_service
from wf_mcp.models import AuthRecord
from wf_mcp.storage import FileStore
from wf_transport_rpc_http.app import create_rpc_app
from wf_transport_rpc_http.client import RpcWorkflowApiClient
@pytest.mark.anyio
async def test_rpc_lists_auth_records(tmp_path):
service = WfMcpService(store=FileStore(tmp_path))
service.save_auth(AuthRecord(connection_id="github.work", scheme="bearer", payload={"token": "secret"}))
app = create_rpc_app(workflow_server_from_service(service))
client = RpcWorkflowApiClient.from_asgi_app(app, url="http://test/rpc")
payload = await client.list_auth_records()
assert payload["auth_records"] == [
{
"id": "github.work",
"scheme": "bearer",
"metadata": {},
"payload_keys": ["token"],
}
]
@pytest.mark.anyio
async def test_rpc_inspects_auth_record(tmp_path):
service = WfMcpService(store=FileStore(tmp_path))
service.save_auth(AuthRecord(connection_id="github.work", scheme="bearer", payload={"token": "secret"}))
app = create_rpc_app(workflow_server_from_service(service))
client = RpcWorkflowApiClient.from_asgi_app(app, url="http://test/rpc")
payload = await client.inspect_auth_record("github.work")
assert payload["id"] == "github.work"
assert payload["payload_keys"] == ["token"]
assert "payload" not in payload
```
If existing RPC tests use `async def` without `pytest.mark.anyio`, follow the
existing local style instead.
- [ ] **Step 2: Run tests to verify failure**
Run:
```bash
uv run pytest tests/wf_transport_rpc_http/test_admin_auth_rpc.py -q
```
Expected: fails because RPC methods/client methods do not exist.
- [ ] **Step 3: Add params model**
Modify `src/wf_transport_rpc_http/models.py`.
Add:
```python
class InspectAuthParams(RpcBaseModel):
auth_ref: str = Field(min_length=1)
```
Use the same base model and `Field` import already used in this file.
- [ ] **Step 4: Register RPC methods**
Modify `src/wf_transport_rpc_http/methods_admin.py`.
Add import:
```python
from .models import AdminEmptyParams, InspectAuthParams
```
Add methods inside `register_methods`:
```python
@entrypoint.method(name="workflow.admin.auth.list", errors=[WorkflowRpcError])
async def workflow_admin_auth_list(
params: AdminEmptyParams = Body(default_factory=AdminEmptyParams),
) -> dict[str, Any]:
try:
return await server.admin.list_auth_records()
except (ValueError, KeyError, LookupError, FileNotFoundError, RuntimeError) as exc:
raise_workflow_rpc_error(exc)
@entrypoint.method(name="workflow.admin.auth.inspect", errors=[WorkflowRpcError])
async def workflow_admin_auth_inspect(
params: InspectAuthParams,
) -> dict[str, Any]:
try:
return await server.admin.inspect_auth_record(params.auth_ref)
except (ValueError, KeyError, LookupError, FileNotFoundError, RuntimeError) as exc:
raise_workflow_rpc_error(exc)
```
If ruff flags line length on the exception tuple, wrap it like existing methods.
- [ ] **Step 5: Add client methods**
Modify `src/wf_transport_rpc_http/client_admin.py`.
Add:
```python
async def list_auth_records(self) -> dict[str, Any]:
return await self._call("workflow.admin.auth.list", {})
async def inspect_auth_record(self, auth_ref: str) -> dict[str, Any]:
return await self._call(
"workflow.admin.auth.inspect",
{"auth_ref": auth_ref},
)
```
- [ ] **Step 6: Run focused tests**
Run:
```bash
uv run pytest tests/wf_transport_rpc_http/test_admin_auth_rpc.py -q
uv run ruff check src/wf_transport_rpc_http/models.py src/wf_transport_rpc_http/methods_admin.py src/wf_transport_rpc_http/client_admin.py tests/wf_transport_rpc_http/test_admin_auth_rpc.py
uv run basedpyright --level error src/wf_transport_rpc_http/models.py src/wf_transport_rpc_http/methods_admin.py src/wf_transport_rpc_http/client_admin.py tests/wf_transport_rpc_http/test_admin_auth_rpc.py
```
Expected: all pass.
## Task 5: CLI commands
**Files:**
- Create: `src/wf_cli/commands/auth_admin.py`
- Modify: `src/wf_cli/commands/admin.py`
- Test: `tests/wf_cli/test_auth_admin.py`
- [ ] **Step 1: Add CLI tests**
Create `tests/wf_cli/test_auth_admin.py`:
```python
from __future__ import annotations
from typer.testing import CliRunner
from wf_cli.app import app
class FakeAdmin:
async def list_auth_records(self):
return {
"auth_records": [
{
"id": "github.work",
"scheme": "bearer",
"metadata": {},
"payload_keys": ["token"],
}
],
"total": 1,
}
async def inspect_auth_record(self, auth_ref: str):
return {
"id": auth_ref,
"scheme": "bearer",
"metadata": {},
"payload_keys": ["token"],
}
class FakeContext:
admin = FakeAdmin()
verbose = False
def test_wf_admin_auth_list(monkeypatch) -> None:
monkeypatch.setattr(
"wf_cli.commands.auth_admin.load_cli_context_from_typer",
lambda ctx: FakeContext(),
)
result = CliRunner().invoke(app, ["admin", "auth", "list"])
assert result.exit_code == 0
assert "github.work" in result.stdout
assert "secret" not in result.stdout
def test_wf_admin_auth_inspect(monkeypatch) -> None:
monkeypatch.setattr(
"wf_cli.commands.auth_admin.load_cli_context_from_typer",
lambda ctx: FakeContext(),
)
result = CliRunner().invoke(app, ["admin", "auth", "inspect", "github.work"])
assert result.exit_code == 0
assert "github.work" in result.stdout
assert "payload_keys" in result.stdout
assert "secret" not in result.stdout
```
- [ ] **Step 2: Run tests to verify failure**
Run:
```bash
uv run pytest tests/wf_cli/test_auth_admin.py -q
```
Expected: fails because `wf admin auth` commands do not exist.
- [ ] **Step 3: Create CLI command module**
Create `src/wf_cli/commands/auth_admin.py`:
```python
from __future__ import annotations
from typing import Annotated
import typer
from wf_cli.context import load_cli_context_from_typer
from wf_cli.formats import ListOutputFormat, emit_detail_payload, emit_list_payload
from wf_cli.remote_errors import run_cli_operation
app = typer.Typer(
name="auth",
help="Read auth record status without exposing secret payload values.",
no_args_is_help=True,
)
@app.command("list")
def list_auth_records(
ctx: typer.Context,
output_format: Annotated[
ListOutputFormat, typer.Option("--format", help="Output format.")
] = ListOutputFormat.JSON,
) -> None:
"""List auth records known to the target."""
context = load_cli_context_from_typer(ctx)
payload = run_cli_operation(context, context.admin.list_auth_records())
emit_list_payload(
payload,
collection_key="auth_records",
output_format=output_format,
id_field="id",
summary_fields=("scheme", "payload_keys"),
)
@app.command("inspect")
def inspect_auth_record(
ctx: typer.Context,
auth_ref: Annotated[str, typer.Argument(help="Auth record id/ref.")],
) -> None:
"""Inspect one auth record summary without secret payload values."""
context = load_cli_context_from_typer(ctx)
payload = run_cli_operation(
context,
context.admin.inspect_auth_record(auth_ref),
)
emit_detail_payload(payload)
```
If `emit_detail_payload` has a different name in `wf_cli.formats`, inspect the
file and use the existing detail emitter.
- [ ] **Step 4: Register subcommand**
Modify `src/wf_cli/commands/admin.py`.
Change:
```python
from . import source_registry
```
to:
```python
from . import auth_admin, source_registry
```
Add after registry registration:
```python
app.add_typer(auth_admin.app, name="auth")
```
- [ ] **Step 5: Run focused tests**
Run:
```bash
uv run pytest tests/wf_cli/test_auth_admin.py -q
uv run ruff check src/wf_cli/commands/auth_admin.py src/wf_cli/commands/admin.py tests/wf_cli/test_auth_admin.py
uv run basedpyright --level error src/wf_cli/commands/auth_admin.py src/wf_cli/commands/admin.py tests/wf_cli/test_auth_admin.py
```
Expected: all pass.
## Task 6: Docs and final verification
**Files:**
- Modify: `docs/current_roadmap.md`
- Modify: `docs/superpowers/specs/2026-06-06-auth-source-secrets-boundary.md`
- [ ] **Step 1: Update spec status**
In `docs/superpowers/specs/2026-06-06-auth-source-secrets-boundary.md`, update
the `## Status` section to:
```markdown
Slice 1 implements the neutral auth record/store protocol and MCP compatibility
bridge. Slice 2 surfaces missing explicit auth refs through live source
diagnostics and source registry apply summaries. Slice 3 exposes read-only auth
admin summaries without secret payload values. Auth mutation surfaces and
provider-specific auth unions are future slices.
```
- [ ] **Step 2: Update roadmap**
In `docs/current_roadmap.md`, under the auth/source secrets boundary bullet,
append:
```markdown
Third implementation slice complete: read-only auth admin summaries are
available through MCP-backed server admin, JSON-RPC, and CLI. Summaries show
ids, schemes, metadata, and payload keys only; secret payload values remain
hidden.
```
- [ ] **Step 3: Run final verification**
Run:
```bash
uv run pytest tests/wf_api/test_admin_api.py tests/wf_mcp/service/test_auth_admin.py tests/wf_mcp/test_mcp_workflow_server.py tests/wf_transport_rpc_http/test_admin_auth_rpc.py tests/wf_cli/test_auth_admin.py -q
uv run ruff check src/wf_api/admin.py src/wf_api/surface.py src/wf_api/__init__.py src/wf_mcp/storage/store.py src/wf_mcp/broker/service/auth_admin.py src/wf_mcp/broker/server.py src/wf_transport_rpc_http/models.py src/wf_transport_rpc_http/methods_admin.py src/wf_transport_rpc_http/client_admin.py src/wf_cli/commands/auth_admin.py src/wf_cli/commands/admin.py tests/wf_api/test_admin_api.py tests/wf_mcp/service/test_auth_admin.py tests/wf_transport_rpc_http/test_admin_auth_rpc.py tests/wf_cli/test_auth_admin.py
uv run basedpyright --level error src/wf_api src/wf_mcp/broker/service/auth_admin.py src/wf_mcp/storage/store.py src/wf_transport_rpc_http src/wf_cli/commands/auth_admin.py tests/wf_api/test_admin_api.py tests/wf_mcp/service/test_auth_admin.py tests/wf_transport_rpc_http/test_admin_auth_rpc.py tests/wf_cli/test_auth_admin.py
```
Expected: all pass.
- [ ] **Step 4: Final report**
Report:
- files changed
- verification output
- final auth summary shape
- confirmation that no secret payload values are returned
- deviations from this plan
@@ -164,6 +164,30 @@ Live source checks and source registry apply should prefer diagnostics over late
adapter failures. Runtime invocation can still fail if the upstream server adapter failures. Runtime invocation can still fail if the upstream server
requires auth but does not declare that requirement. requires auth but does not declare that requirement.
## Read-Only Display
Read-only admin surfaces may show that an auth record exists, but they must not
promise provider-specific display until auth records are concrete variants.
For the current `scheme + payload` bridge, safe display should stay intentionally
minimal:
- `id`
- `scheme`
- `metadata`
- `payload_keys`
Do not expose payload values. Do not promise token hints, OAuth subjects,
expiry, scopes, header names, or environment-variable names as the stable
neutral contract yet. Once auth records become a discriminated union, each
variant can own a richer safe display method:
- bearer auth can show token presence or a redacted hint
- headers auth can show safe header names
- env auth can show safe environment variable names
- OAuth auth can show subject, expiry, scopes, and refreshability
- opaque auth can stay limited to scheme and payload keys
## Store Shape ## Store Shape
The current filesystem store can remain: The current filesystem store can remain: