Skip to content

fix(control-plane): authorize execution note writes(#420)#575

Open
Luffy2208 wants to merge 1 commit into
Agent-Field:mainfrom
Luffy2208:fix/420-execution-notes-authorization
Open

fix(control-plane): authorize execution note writes(#420)#575
Luffy2208 wants to merge 1 commit into
Agent-Field:mainfrom
Luffy2208:fix/420-execution-notes-authorization

Conversation

@Luffy2208
Copy link
Copy Markdown
Contributor

Summary

Fixes an IDOR in the execution notes write endpoint by enforcing execution ownership before appending a note.

File-specific changes:

  • control-plane/internal/handlers/execution_notes.go

    • Resolves the caller agent identity before writing a note.
    • Compares the caller agent ID with the execution owner, execution.AgentNodeID.
    • Returns 403 execution_ownership_mismatch when the caller does not own the execution.
    • Supports DID-authenticated callers by resolving the verified caller DID to an agent ID.
  • control-plane/internal/server/middleware/auth.go

    • Stores API-key caller identity in Gin context using CallerAgentIDKey.
    • Uses X-Caller-Agent-ID first, with X-Agent-Node-ID as fallback.
  • control-plane/internal/handlers/execution_notes_test.go

    • Adds coverage for owner write success.
    • Adds coverage for non-owner API-key write returning 403.
    • Adds coverage for DID-authenticated owner and non-owner behavior.
  • control-plane/internal/server/middleware/auth_test.go

    • Adds coverage that API-key auth populates caller identity in Gin context.
  • control-plane/internal/handlers/coverage_handlers_90_test.go

    • Updates the existing successful note-write coverage test to include matching caller identity.

Testing

  • ./scripts/test-all.sh
  • Additional verification:
    • cd control-plane && go test ./internal/handlers ./internal/server/middleware
    • cd control-plane && go test ./internal/handlers ./internal/server/middleware -coverprofile=/tmp/issue-420.coverprofile
    • cd control-plane && golangci-lint run --new-from-rev=upstream/main ./internal/handlers ./internal/server/middleware
    • Manual E2E curl verification:
      • Agent A adding a note to Agent A’s execution returns 200 OK
      • Agent A adding a note to Agent B’s execution returns 403 Forbidden
      • Agent B’s fresh execution remains with notes: [] after the blocked write

Note: full repo lint currently reports pre-existing unrelated Go lint issues outside this PR’s changed files. Changed-line lint for the touched packages reports 0 issues.

Checklist

  • I updated documentation where applicable.
  • I added or updated tests (or none were needed).
  • I updated CHANGELOG.md (or this change does not warrant a changelog entry).

Screenshots (if UI-related)

Not UI-related.

Related issues

Fixes #420

@Luffy2208 Luffy2208 requested review from a team and AbirAbbas as code owners May 19, 2026 03:44
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 86%, aggregate ≥ 88%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 87.50% 87.30% ↑ +0.20 pp 🟡
sdk-go 91.90% 90.70% ↑ +1.20 pp 🟢
sdk-python 93.73% 93.63% ↑ +0.10 pp 🟢
sdk-typescript 92.68% 92.56% ↑ +0.12 pp 🟢
web-ui 89.91% 90.01% ↓ -0.10 pp 🟡
aggregate 89.02% 89.01% ↑ +0.01 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 76 100.00%
sdk-go 0 ➖ no changes
sdk-python 0 ➖ no changes
sdk-typescript 0 ➖ no changes
web-ui 0 ➖ no changes

✅ Patch gate passed

Every surface whose lines were touched by this PR has patch coverage at or above the threshold.

@Luffy2208 Luffy2208 force-pushed the fix/420-execution-notes-authorization branch from b9fb5f5 to 72f59ee Compare May 19, 2026 04:01
@Luffy2208
Copy link
Copy Markdown
Contributor Author

I fixed the patch coverage failure by adding targeted tests in control-plane/internal/handlers/execution_notes_test.go.

What was added:

  • Tests for missing execution owner returning 403
  • Tests for missing caller identity returning 403
  • Tests for DID resolver failure returning 500
  • Tests for unresolved DID fail-closed behavior returning 403
  • Tests for caller identity resolution from:
    • Gin context CallerAgentIDKey
    • X-Caller-Agent-ID
    • X-Agent-Node-ID
    • DID list fallback
    • DID lookup error fallback
  • Direct coverage for executionNoteAuthorizationError.Error()

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.

[Security] Execution notes write endpoint has no authorization (IDOR)

1 participant