Skip to content

feat(activity): name the caller on config, quarantine and token-rotation rows - #1842

Open
Dumbris wants to merge 2 commits into
mainfrom
claude/1698-audit-actor-gaps
Open

Dumbris wants to merge 2 commits into
mainfrom
claude/1698-audit-actor-gaps

Conversation

@Dumbris

@Dumbris Dumbris commented Nov 8, 2026

Copy link
Copy Markdown
Member

Summary

Closes the three audit gaps that need no schema change, as agreed on #1698: who changed the rules now shows up on the existing activity rows.

  1. Caller identity on config_change and quarantine_change rows. The authenticated caller travels in the request context (runtime.ContextWithActor / runtime.RequestActor; the REST door stamps it in a middleware after authentication, the MCP management tools stamp the mcp surface) and the runtime copies it onto the activity event, so the stored row carries actor_kind, actor_name, surface and request_id under the same keys a profile_change row already uses. A change with no caller behind it (config file edited on disk, admission gate at load) carries none of them: an absent actor means "no request", never an unknown one.
  2. REST / CLI server changes now record a row. POST /servers, PATCH /servers/{id}, DELETE /servers/{id}, the quarantine toggles, security approve, enable/disable and the restart that re-enables a disabled server write server_added / server_updated (with changed_fields and the before/after values of those fields only, computed against the committed entry so an admission-gate quarantine in the same commit is part of the delta) / server_removed (with the purge summary) / server_enabled|disabled. Values go through the existing redactActivityConfigValues redaction. The MCP tool, which already recorded add/remove, now carries the agent's identity too.
  3. Token regenerate writes a record. POST /api/v1/tokens/{name}/regenerate (mcpproxy token regenerate) goes through CredentialsService.Regenerate, which writes one profile_change row with change: rotate, the actor and the old/new token_prefix (never a secret), the shape client rotation already has. The store's refusals keep their sentinels, so 404 / 409 mapping is unchanged.

No new dependencies. Docs: docs/features/activity-log.md (Config Change Events: doors, actions, "Who changed it"), docs/features/agent-tokens.md (regenerate), docs/features/mcp-credential-lifecycle.md.

Verification

  • TDD: every production change has a test that failed first (internal/runtime/activity_actor_test.go, credentials_regenerate_test.go, internal/server/activity_actor_rest_test.go, internal/httpapi/actor_middleware_test.go, tokens_regenerate_record_test.go, scanner and management tests).
  • go test -race on runtime, server, httpapi, management, security/scanner: green.
  • ./scripts/test-api-e2e.sh: 70 passed, 0 failed.
  • golangci-lint (CI config, bare and --build-tags server, --new-from-rev=origin/main): 0 issues.
  • Cross-model review: opencode github-copilot/gpt-6.1-sol, three rounds. Round 1: 5 attribution gaps (MCP enable/registry-add surface, security approve, restart-enables, add row vs committed state, patch delta vs admission gate). Round 2: 6 more (add row read the live config instead of the create commit's snapshot, restart retry loop, MCP restart surface, scan EnsureConnected, secret-change restarts, legacy REST fallbacks). All fixed with tests; round 3: VERDICT: CLEAN.

Out of scope (next step on #1698)

A fourth audit file event kind (admin_action) for log shippers. This PR puts the actor on the activity rows so that spec has one vocabulary to lift.

Refs #1698 (first phase; the issue stays open for the admin_action spec).

🤖 Generated with Claude Code

…ion rows (#1698)

Three audit gaps from #1698, none needing a schema change:

- Caller identity on config_change and quarantine_change rows. The
  authenticated caller rides in the request context (ContextWithActor /
  RequestActor; the REST door stamps it in a middleware after
  authentication, the MCP management tools stamp the mcp surface) and the
  runtime copies it onto the activity event: actor_kind, actor_name,
  surface and request_id, the profile_change vocabulary. A change with no
  caller (file reload, admission gate at load) carries none of them.
- REST / CLI server changes record a row. POST/PATCH/DELETE /servers,
  the quarantine toggles, security approve, enable/disable and a restart
  that re-enables a disabled server write server_added / server_updated
  (changed fields and their before/after values, computed against the
  committed entry) / server_removed (with the purge summary) /
  server_enabled|disabled, through the existing redaction. The MCP tool,
  which already recorded add/remove, now carries the agent's identity.
- Token regenerate records a rotate row. POST /tokens/{name}/regenerate
  goes through CredentialsService.Regenerate, which writes one
  profile_change row with change rotate, the actor and the old/new
  token_prefix (never a secret); the store's refusals keep their
  sentinels so the 404 / 409 mapping is unchanged.

Docs: activity-log.md (doors, actions, "Who changed it"),
agent-tokens.md, mcp-credential-lifecycle.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: d4ffdcf
Status: ✅  Deploy successful!
Preview URL: https://7eccaaf7.mcpproxy-docs.pages.dev
Branch Preview URL: https://claude-1698-audit-actor-gaps.mcpproxy-docs.pages.dev

View logs

The round-8 door scan (internal/oauth TestNoDoorPublishesARawServerLeaf)
flagged serverAddedValues: it copied sc.URL and sc.Command into a payload
map and relied on the caller to redact. The two leaves now pass through
redactActivityValue as they are read, so the function is a routed door on
its own and the caller no longer re-redacts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

📦 Build Artifacts

Workflow Run: View Run
Branch: claude/1698-audit-actor-gaps

Available Artifacts

  • archive-darwin-amd64 (32 MB)
  • archive-darwin-arm64 (29 MB)
  • archive-linux-amd64 (20 MB)
  • archive-linux-arm64 (18 MB)
  • archive-windows-amd64 (32 MB)
  • archive-windows-arm64 (28 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (28 MB)
  • installer-dmg-darwin-arm64 (25 MB)
  • smart-mcp-proxymcpproxy-goYFL17Y.dockerbuild (0 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 42487070854 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@codecov-commenter

codecov-commenter commented Nov 8, 2026 •

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants