Files
lda-wf/docs/historical/superpowers/plans/2026-06-06-auth-admin-mutation-slice-4.md
T

29 KiB

Auth Admin Mutation Slice 4 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 local/dev auth record save and delete through neutral admin, JSON-RPC, and wf admin auth CLI without exposing secret payload values in responses.

Architecture: Extend the existing neutral WorkflowAdminApi auth surface with mutation methods, then implement those methods in the MCP-backed file-store provider. JSON-RPC and CLI call the neutral admin surface; do not add new wf-mcp tools or old broker-only product behavior. This is a local/dev file-store slice only: no OAuth, no production secret manager, no provider-specific auth variants, and no secret payload values in response bodies.

Tech Stack: Python 3.14, dataclasses, Pydantic v2, Typer, JSON-RPC HTTP transport, pytest, ruff, basedpyright.


Boundaries

  • Do not add new behavior to the legacy wf-mcp script.
  • Do not expose auth payload values in list, inspect, save, or delete responses.
  • Do not support inline auth records in wf_config or source registry documents.
  • Do not add OAuth/browser login, encryption, or secret-manager integration.
  • Do not change the on-disk auth JSON shape in this slice.
  • Do use wf_api.auth.AuthRecord as the neutral input shape for save/upsert.
  • Do keep the current compatibility wf_mcp.auth.AuthRecord(connection_id, scheme, payload) file adapter.

Files

  • Modify src/wf_api/admin.py
    • Add mutation methods to WorkflowAdminAuthProvider.
    • Add WorkflowAdminApi.save_auth_record(...).
    • Add WorkflowAdminApi.delete_auth_record(...).
  • Modify src/wf_api/surface.py
    • Add mutation methods to WorkflowAdminSurface.
  • Modify src/wf_mcp/storage/store.py
    • Add delete_auth(...) and delete_auth_record(...) to Store / FileStore.
  • Modify src/wf_mcp/broker/service/auth_admin.py
    • Implement save/delete using Store.save_auth_record and Store.delete_auth_record.
  • Modify src/wf_transport_rpc_http/models.py
    • Add SaveAuthParams and DeleteAuthParams.
  • Modify src/wf_transport_rpc_http/methods_admin.py
    • Register workflow.admin.auth.save and workflow.admin.auth.delete.
  • Modify src/wf_transport_rpc_http/client_admin.py
    • Add save_auth_record(...) and delete_auth_record(...).
  • Modify src/wf_cli/commands/auth_admin.py
    • Add wf admin auth save.
    • Add wf admin auth delete --confirm.
  • Modify docs:
    • docs/superpowers/specs/2026-06-06-auth-source-secrets-boundary.md
    • docs/current_roadmap.md
    • docs/wf_cli.md
  • Add/update tests:
    • tests/wf_api/test_admin_api.py
    • tests/wf_mcp/service/test_auth_admin.py
    • tests/wf_mcp/test_auth.py or tests/wf_mcp/test_store.py
    • tests/wf_transport_rpc_http/test_admin_auth_rpc.py
    • tests/wf_cli/test_auth_admin.py

Task 1: Neutral Admin Auth Mutation Surface

Files:

  • Modify: src/wf_api/admin.py

  • Modify: src/wf_api/surface.py

  • Test: tests/wf_api/test_admin_api.py

  • Step 1: Add failing neutral API tests

Append these tests to tests/wf_api/test_admin_api.py. If a local fake provider already exists in the file, extend it instead of duplicating the whole class.

from wf_api.auth import AuthRecord


class MutableAuthProvider(AuthProvider):
    def __init__(self) -> None:
        self.records: dict[str, dict[str, Any]] = {}

    def list_auth_records(self):
        return list(self.records.values())

    def inspect_auth_record(self, auth_ref: str):
        try:
            return self.records[auth_ref]
        except KeyError as exc:
            raise KeyError(auth_ref) from exc

    def save_auth_record(self, record: AuthRecord):
        self.records[record.id] = {
            "id": record.id,
            "scheme": record.scheme,
            "metadata": dict(record.metadata),
            "payload_keys": sorted(str(key) for key in record.payload),
        }
        return self.records[record.id]

    def delete_auth_record(self, auth_ref: str):
        if auth_ref not in self.records:
            raise KeyError(auth_ref)
        del self.records[auth_ref]
        return {"deleted": True, "id": auth_ref}


def test_admin_saves_auth_record_without_payload_values() -> None:
    provider = MutableAuthProvider()
    api = _api(provider)

    payload = asyncio.run(
        api.save_auth_record(
            auth_ref="drive.work",
            scheme="bearer",
            payload={"token": "secret"},
            metadata={"owner": "test"},
        )
    )

    assert payload == {
        "id": "drive.work",
        "scheme": "bearer",
        "metadata": {"owner": "test"},
        "payload_keys": ["token"],
    }
    assert "secret" not in str(payload)


def test_admin_deletes_auth_record() -> None:
    provider = MutableAuthProvider()
    api = _api(provider)
    asyncio.run(
        api.save_auth_record(
            auth_ref="drive.work",
            scheme="bearer",
            payload={"token": "secret"},
        )
    )

    payload = asyncio.run(api.delete_auth_record("drive.work"))

    assert payload == {"deleted": True, "id": "drive.work"}
    with pytest.raises(KeyError):
        provider.inspect_auth_record("drive.work")


def test_admin_auth_mutations_report_unavailable_without_provider() -> None:
    with pytest.raises(RuntimeError, match="auth admin is not available"):
        asyncio.run(
            _api().save_auth_record(
                auth_ref="drive.work",
                scheme="bearer",
                payload={"token": "secret"},
            )
        )

    with pytest.raises(RuntimeError, match="auth admin is not available"):
        asyncio.run(_api().delete_auth_record("drive.work"))
  • Step 2: Run the failing tests

Run:

uv run pytest tests\wf_api\test_admin_api.py -q

Expected: fail because WorkflowAdminApi.save_auth_record and delete_auth_record do not exist.

  • Step 3: Implement neutral API methods

In src/wf_api/admin.py, add:

from wf_api.auth import AuthRecord

Extend WorkflowAdminAuthProvider:

class WorkflowAdminAuthProvider(Protocol):
    """Provides auth inventory and local/dev auth mutation."""

    def list_auth_records(self) -> Sequence[Mapping[str, Any] | object]: ...

    def inspect_auth_record(self, auth_ref: str) -> Mapping[str, Any] | object: ...

    def save_auth_record(self, record: AuthRecord) -> Mapping[str, Any] | object: ...

    def delete_auth_record(self, auth_ref: str) -> Mapping[str, Any] | object: ...

Add methods to WorkflowAdminApi:

    async def save_auth_record(
        self,
        *,
        auth_ref: str,
        scheme: str,
        payload: Mapping[str, object],
        metadata: Mapping[str, object] | None = None,
    ) -> dict[str, Any]:
        if self.auth is None:
            raise RuntimeError("auth admin is not available for this target")
        record = AuthRecord(
            id=auth_ref,
            scheme=scheme,
            payload=dict(payload),
            metadata=dict(metadata or {}),
        )
        return _payload(self.auth.save_auth_record(record))

    async def delete_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.delete_auth_record(auth_ref))

In src/wf_api/surface.py, add these methods to WorkflowAdminSurface:

    async def save_auth_record(
        self,
        *,
        auth_ref: str,
        scheme: str,
        payload: Mapping[str, object],
        metadata: Mapping[str, object] | None = None,
    ) -> dict[str, Any]: ...

    async def delete_auth_record(self, auth_ref: str) -> dict[str, Any]: ...

If Mapping is not imported in surface.py, import it from collections.abc.

  • Step 4: Run tests

Run:

uv run pytest tests\wf_api\test_admin_api.py -q
uv run ruff check src\wf_api\admin.py src\wf_api\surface.py tests\wf_api\test_admin_api.py
uv run basedpyright --level error src\wf_api\admin.py src\wf_api\surface.py tests\wf_api\test_admin_api.py

Expected: pass.


Task 2: MCP File Store Save/Delete Provider

Files:

  • Modify: src/wf_mcp/storage/store.py

  • Modify: src/wf_mcp/broker/service/auth_admin.py

  • Test: tests/wf_mcp/test_store.py

  • Test: tests/wf_mcp/service/test_auth_admin.py

  • Step 1: Add failing store tests

Append to tests/wf_mcp/test_store.py:

def test_file_store_deletes_auth_record(tmp_path) -> None:
    store = FileStore(tmp_path / "store")
    record = AuthRecord(
        connection_id="drive.work",
        scheme="bearer",
        payload={"token": "secret"},
    )
    store.save_auth(record)

    assert store.load_auth("drive.work") == record
    assert store.delete_auth("drive.work") is True
    assert store.load_auth("drive.work") is None
    assert store.delete_auth("drive.work") is False


def test_file_store_deletes_neutral_auth_record(tmp_path) -> None:
    store = FileStore(tmp_path / "store")
    store.save_auth_record(
        NeutralAuthRecord(
            id="drive.work",
            scheme="bearer",
            payload={"token": "secret"},
        )
    )

    assert store.delete_auth_record("drive.work") is True
    assert store.load_auth_record("drive.work") is None

Add imports if needed:

from wf_api.auth import AuthRecord as NeutralAuthRecord
  • Step 2: Add failing provider tests

Append to tests/wf_mcp/service/test_auth_admin.py:

from wf_api.auth import AuthRecord as NeutralAuthRecord


def test_auth_admin_provider_saves_auth_without_returning_payload(tmp_path) -> None:
    store = FileStore(tmp_path / "store")
    provider = McpAuthAdminProvider(store)

    payload = provider.save_auth_record(
        NeutralAuthRecord(
            id="drive.work",
            scheme="bearer",
            payload={"token": "secret"},
            metadata={"owner": "test"},
        )
    )

    assert payload == {
        "id": "drive.work",
        "scheme": "bearer",
        "metadata": {},
        "payload_keys": ["token"],
    }
    assert "secret" not in str(payload)
    assert store.load_auth("drive.work") == AuthRecord(
        connection_id="drive.work",
        scheme="bearer",
        payload={"token": "secret"},
    )


def test_auth_admin_provider_deletes_auth(tmp_path) -> None:
    store = FileStore(tmp_path / "store")
    provider = McpAuthAdminProvider(store)
    store.save_auth(AuthRecord(connection_id="drive.work", scheme="bearer"))

    payload = provider.delete_auth_record("drive.work")

    assert payload == {"deleted": True, "id": "drive.work"}
    assert store.load_auth("drive.work") is None


def test_auth_admin_provider_delete_unknown_auth_raises_key_error(tmp_path) -> None:
    provider = McpAuthAdminProvider(FileStore(tmp_path / "store"))

    with pytest.raises(KeyError, match="unknown auth record 'missing'"):
        provider.delete_auth_record("missing")
  • Step 3: Run failing tests

Run:

uv run pytest tests\wf_mcp\test_store.py tests\wf_mcp\service\test_auth_admin.py -q

Expected: fail because delete/save provider mutation methods are missing.

  • Step 4: Implement store delete methods

In src/wf_mcp/storage/store.py, extend Store:

    def delete_auth(self, connection_id: str) -> bool:
        raise NotImplementedError

    def delete_auth_record(self, auth_ref: str) -> bool:
        raise NotImplementedError

In FileStore, add:

    def delete_auth(self, connection_id: str) -> bool:
        path = self._auth_path(connection_id)
        if not path.exists():
            return False
        path.unlink()
        return True

    def delete_auth_record(self, auth_ref: str) -> bool:
        """Delete neutral auth through the legacy MCP file shape."""
        return self.delete_auth(auth_ref)
  • Step 5: Implement provider methods

In src/wf_mcp/broker/service/auth_admin.py, import neutral auth:

from wf_api.auth import AuthRecord as NeutralAuthRecord

Add methods to McpAuthAdminProvider:

    def save_auth_record(self, record: NeutralAuthRecord) -> dict[str, Any]:
        self.store.save_auth_record(record)
        return self.inspect_auth_record(record.id)

    def delete_auth_record(self, auth_ref: str) -> dict[str, Any]:
        deleted = self.store.delete_auth_record(auth_ref)
        if not deleted:
            raise KeyError(f"unknown auth record {auth_ref!r}")
        return {"deleted": True, "id": auth_ref}
  • Step 6: Run tests

Run:

uv run pytest tests\wf_mcp\test_store.py tests\wf_mcp\service\test_auth_admin.py -q
uv run ruff check src\wf_mcp\storage\store.py src\wf_mcp\broker\service\auth_admin.py tests\wf_mcp\test_store.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\test_store.py tests\wf_mcp\service\test_auth_admin.py

Expected: pass.


Task 3: JSON-RPC Auth Mutation Methods

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 failing RPC tests

Append to tests/wf_transport_rpc_http/test_admin_auth_rpc.py:

async def test_rpc_saves_auth_record_without_returning_payload(tmp_path) -> None:
    store = FileStore(tmp_path / "store")
    server = build_workflow_server_from_config(BrokerConfig(store_root=store.root))

    async with _client(server) as client:
        payload = await client.save_auth_record(
            auth_ref="drive.work",
            scheme="bearer",
            payload={"token": "secret"},
            metadata={"owner": "test"},
        )

    assert payload["id"] == "drive.work"
    assert payload["scheme"] == "bearer"
    assert payload["payload_keys"] == ["token"]
    assert "secret" not in str(payload)
    assert FileStore(store.root).load_auth("drive.work") == AuthRecord(
        connection_id="drive.work",
        scheme="bearer",
        payload={"token": "secret"},
    )


async def test_rpc_deletes_auth_record(tmp_path) -> None:
    store = FileStore(tmp_path / "store")
    store.save_auth(AuthRecord(connection_id="drive.work", scheme="bearer"))
    server = build_workflow_server_from_config(BrokerConfig(store_root=store.root))

    async with _client(server) as client:
        payload = await client.delete_auth_record("drive.work")

    assert payload == {"deleted": True, "id": "drive.work"}
    assert FileStore(store.root).load_auth("drive.work") is None

Use the existing _client(...) helper in this test file. If it has a different name, adapt only the helper call.

  • Step 2: Run failing tests

Run:

uv run pytest tests\wf_transport_rpc_http\test_admin_auth_rpc.py -q

Expected: fail because RPC client/server mutation methods do not exist.

  • Step 3: Add RPC parameter models

In src/wf_transport_rpc_http/models.py, add:

class SaveAuthParams(RpcParamsModel):
    auth_ref: str = Field(min_length=1)
    scheme: str = Field(min_length=1)
    payload: dict[str, Any] = Field(default_factory=dict)
    metadata: dict[str, Any] = Field(default_factory=dict)


class DeleteAuthParams(RpcParamsModel):
    auth_ref: str = Field(min_length=1)

If Any is not imported in that file, import it from typing.

  • Step 4: Register RPC methods

In src/wf_transport_rpc_http/methods_admin.py, import the new params:

from .models import AdminEmptyParams, DeleteAuthParams, InspectAuthParams, SaveAuthParams

Add methods after workflow.admin.auth.inspect:

    @entrypoint.method(
        name="workflow.admin.auth.save",
        errors=[WorkflowRpcError],
    )
    async def workflow_admin_auth_save(
        params: SaveAuthParams = RpcParams(),
    ) -> dict[str, Any]:
        try:
            return await server.admin.save_auth_record(
                auth_ref=params.auth_ref,
                scheme=params.scheme,
                payload=params.payload,
                metadata=params.metadata,
            )
        except (
            ValueError,
            KeyError,
            LookupError,
            FileNotFoundError,
            RuntimeError,
        ) as exc:
            raise_workflow_rpc_error(exc)

    @entrypoint.method(
        name="workflow.admin.auth.delete",
        errors=[WorkflowRpcError],
    )
    async def workflow_admin_auth_delete(
        params: DeleteAuthParams = RpcParams(),
    ) -> dict[str, Any]:
        try:
            return await server.admin.delete_auth_record(params.auth_ref)
        except (
            ValueError,
            KeyError,
            LookupError,
            FileNotFoundError,
            RuntimeError,
        ) as exc:
            raise_workflow_rpc_error(exc)
  • Step 5: Add RPC client methods

In src/wf_transport_rpc_http/client_admin.py, add:

    async def save_auth_record(
        self,
        *,
        auth_ref: str,
        scheme: str,
        payload: dict[str, Any],
        metadata: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        return await self._call(
            "workflow.admin.auth.save",
            {
                "auth_ref": auth_ref,
                "scheme": scheme,
                "payload": payload,
                "metadata": metadata or {},
            },
        )

    async def delete_auth_record(self, auth_ref: str) -> dict[str, Any]:
        return await self._call(
            "workflow.admin.auth.delete",
            {"auth_ref": auth_ref},
        )
  • Step 6: Run tests

Run:

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: pass.


Task 4: CLI Auth Save/Delete

Files:

  • Modify: src/wf_cli/commands/auth_admin.py

  • Test: tests/wf_cli/test_auth_admin.py

  • Step 1: Add failing CLI tests

Append to tests/wf_cli/test_auth_admin.py:

def test_wf_admin_auth_save(monkeypatch) -> None:
    mock_admin = MockAuthAdmin()
    monkeypatch.setattr(
        "wf_cli.commands.auth_admin.load_cli_context_from_typer",
        lambda _ctx: SimpleNamespace(admin=mock_admin),
    )

    result = CliRunner().invoke(
        app,
        [
            "admin",
            "auth",
            "save",
            "drive.work",
            "--scheme",
            "bearer",
            "--payload",
            '{"token":"secret"}',
        ],
    )

    assert result.exit_code == 0
    payload = json.loads(result.output)
    assert payload["id"] == "drive.work"
    assert payload["payload_keys"] == ["token"]
    assert "secret" not in result.output
    mock_admin.save_auth_record.assert_called_once_with(
        auth_ref="drive.work",
        scheme="bearer",
        payload={"token": "secret"},
        metadata=None,
    )


def test_wf_admin_auth_save_reads_payload_file(tmp_path, monkeypatch) -> None:
    mock_admin = MockAuthAdmin()
    payload_file = tmp_path / "auth.json"
    payload_file.write_text('{"token":"secret"}', encoding="utf-8")
    monkeypatch.setattr(
        "wf_cli.commands.auth_admin.load_cli_context_from_typer",
        lambda _ctx: SimpleNamespace(admin=mock_admin),
    )

    result = CliRunner().invoke(
        app,
        [
            "admin",
            "auth",
            "save",
            "drive.work",
            "--scheme",
            "bearer",
            "--payload-file",
            str(payload_file),
        ],
    )

    assert result.exit_code == 0
    mock_admin.save_auth_record.assert_called_once_with(
        auth_ref="drive.work",
        scheme="bearer",
        payload={"token": "secret"},
        metadata=None,
    )


def test_wf_admin_auth_delete_requires_confirm(monkeypatch) -> None:
    mock_admin = MockAuthAdmin()
    monkeypatch.setattr(
        "wf_cli.commands.auth_admin.load_cli_context_from_typer",
        lambda _ctx: SimpleNamespace(admin=mock_admin),
    )

    result = CliRunner().invoke(app, ["admin", "auth", "delete", "drive.work"])

    assert result.exit_code != 0
    assert "--confirm" in result.output
    mock_admin.delete_auth_record.assert_not_called()


def test_wf_admin_auth_delete(monkeypatch) -> None:
    mock_admin = MockAuthAdmin()
    monkeypatch.setattr(
        "wf_cli.commands.auth_admin.load_cli_context_from_typer",
        lambda _ctx: SimpleNamespace(admin=mock_admin),
    )

    result = CliRunner().invoke(
        app,
        ["admin", "auth", "delete", "drive.work", "--confirm"],
    )

    assert result.exit_code == 0
    assert json.loads(result.output) == {"deleted": True, "id": "drive.work"}
    mock_admin.delete_auth_record.assert_called_once_with("drive.work")

If the test file uses a different fake than MockAuthAdmin, extend the existing fake with save_auth_record = MagicMock(...) and delete_auth_record = MagicMock(...).

  • Step 2: Run failing CLI tests

Run:

uv run pytest tests\wf_cli\test_auth_admin.py -q

Expected: fail because commands are missing.

  • Step 3: Implement JSON input helper locally

In src/wf_cli/commands/auth_admin.py, add imports:

import json
from pathlib import Path

Add helpers:

def _read_json_object(
    inline: str | None,
    file_path: str | None,
    flag_names: str,
) -> dict[str, object]:
    if inline and file_path:
        raise typer.BadParameter(f"provide exactly one of {flag_names}")
    if inline:
        try:
            value = json.loads(inline)
        except json.JSONDecodeError as exc:
            raise typer.BadParameter(f"invalid JSON: {exc}") from exc
        if not isinstance(value, dict):
            raise typer.BadParameter(f"{flag_names} must be a JSON object")
        return dict(value)
    if file_path:
        try:
            value = json.loads(Path(file_path).read_text(encoding="utf-8"))
        except FileNotFoundError as exc:
            raise typer.BadParameter(f"file not found: {file_path}") from exc
        except json.JSONDecodeError as exc:
            raise typer.BadParameter(f"invalid JSON in file: {exc}") from exc
        if not isinstance(value, dict):
            raise typer.BadParameter(f"{flag_names} must be a JSON object")
        return dict(value)
    raise typer.BadParameter(f"{flag_names} is required")
  • Step 4: Add CLI commands

In src/wf_cli/commands/auth_admin.py, add:

@app.command("save")
def save_auth_record(
    ctx: typer.Context,
    auth_ref: Annotated[str, typer.Argument(help="Auth record id/ref.")],
    scheme: Annotated[str, typer.Option("--scheme", help="Auth scheme/kind.")],
    payload_json: Annotated[
        str | None,
        typer.Option("--payload", help="Secret payload JSON object."),
    ] = None,
    payload_file: Annotated[
        str | None,
        typer.Option("--payload-file", help="File containing secret payload JSON object."),
    ] = None,
    metadata_json: Annotated[
        str | None,
        typer.Option("--metadata", help="Non-secret metadata JSON object."),
    ] = None,
    metadata_file: Annotated[
        str | None,
        typer.Option("--metadata-file", help="File containing non-secret metadata JSON object."),
    ] = None,
) -> None:
    """Save or replace a local/dev auth record; response never includes payload values."""
    payload = _read_json_object(payload_json, payload_file, "--payload/--payload-file")
    metadata = (
        _read_json_object(metadata_json, metadata_file, "--metadata/--metadata-file")
        if metadata_json or metadata_file
        else None
    )
    context = load_cli_context_from_typer(ctx)
    result = run_cli_operation(
        context,
        context.admin.save_auth_record(
            auth_ref=auth_ref,
            scheme=scheme,
            payload=payload,
            metadata=metadata,
        ),
    )
    emit_json(result)


@app.command("delete")
def delete_auth_record(
    ctx: typer.Context,
    auth_ref: Annotated[str, typer.Argument(help="Auth record id/ref.")],
    confirm: Annotated[
        bool,
        typer.Option("--confirm", help="Required to delete an auth record."),
    ] = False,
) -> None:
    """Delete a local/dev auth record."""
    if not confirm:
        raise typer.BadParameter("--confirm is required to delete an auth record")
    context = load_cli_context_from_typer(ctx)
    result = run_cli_operation(context, context.admin.delete_auth_record(auth_ref))
    emit_json(result)
  • Step 5: Run CLI tests

Run:

uv run pytest tests\wf_cli\test_auth_admin.py -q
uv run ruff check src\wf_cli\commands\auth_admin.py tests\wf_cli\test_auth_admin.py
uv run basedpyright --level error src\wf_cli\commands\auth_admin.py tests\wf_cli\test_auth_admin.py

Expected: pass.


Task 5: Docs and Final Verification

Files:

  • Modify: docs/superpowers/specs/2026-06-06-auth-source-secrets-boundary.md

  • Modify: docs/current_roadmap.md

  • Modify: docs/wf_cli.md

  • Step 1: Update auth spec status

In docs/superpowers/specs/2026-06-06-auth-source-secrets-boundary.md, update the ## Status paragraph to include:

Slice 4 adds local/dev file-backed auth save/delete through neutral admin,
JSON-RPC, and CLI. Responses still expose only ids, schemes, metadata, and
payload keys; secret payload values remain write-only. OAuth, production secret
managers, and provider-specific auth variants remain future work.
  • Step 2: Update roadmap

In docs/current_roadmap.md, under the auth/source secrets boundary bullet, add:

Fourth implementation slice complete: local/dev auth records can be saved and
deleted through neutral admin, JSON-RPC, and `wf admin auth`. This is still not
a production secret manager or OAuth flow; payload values are accepted only as
write inputs and never returned.
  • Step 3: Update CLI docs

In docs/wf_cli.md, add an auth section near admin/source registry commands:

### Local/dev auth records

Auth payload values are write-only. `list`, `inspect`, `save`, and `delete`
responses show ids, schemes, metadata, and payload keys only.

```powershell
wf admin auth save drive.work --scheme bearer --payload-file drive-auth.json
wf admin auth list
wf admin auth inspect drive.work
wf admin auth delete drive.work --confirm

Use source auth_ref values to point sources at these records. Do not commit payload files containing real secrets.

  • Step 4: Run final focused suite

Run:

uv run pytest tests\wf_api\test_admin_api.py tests\wf_mcp\test_store.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 -q
uv run ruff check src\wf_api\admin.py src\wf_api\surface.py src\wf_mcp\storage\store.py src\wf_mcp\broker\service\auth_admin.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 tests\wf_api\test_admin_api.py tests\wf_mcp\test_store.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\storage\store.py src\wf_mcp\broker\service\auth_admin.py src\wf_transport_rpc_http src\wf_cli\commands\auth_admin.py tests\wf_api\test_admin_api.py tests\wf_mcp\test_store.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: pass.

  • Step 5: Run broader smoke

Run:

uv run pytest tests\wf_mcp tests\wf_transport_rpc_http tests\wf_cli\test_auth_admin.py -q

Expected: pass with the existing skipped/xfail counts only.

  • Step 6: Review security invariant

Run:

rg -n "\"payload\"|secret|token" src\wf_api\admin.py src\wf_mcp\broker\service\auth_admin.py src\wf_transport_rpc_http\methods_admin.py 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:

  • Payload appears only as input construction or persisted store calls.
  • Response assertions use payload_keys.
  • Tests assert secret values are not present in output.

Self-Review

  • Spec coverage: this plan implements local/dev auth save/delete, keeps read responses secret-free, and leaves OAuth/secret managers/provider unions future.
  • Placeholder scan: no TBD/TODO placeholders are present.
  • Type consistency: public API method names are save_auth_record and delete_auth_record across wf_api, JSON-RPC client, and CLI. RPC method names are workflow.admin.auth.save and workflow.admin.auth.delete.
  • Scope check: this plan does not touch legacy wf-mcp tools; it routes through neutral admin surfaces and JSON-RPC/CLI.