Skip to content

feat(gateway): wire RFC-011 AsyncEmitter into PEP middleware#90

Merged
beonde merged 6 commits into
mainfrom
feat/gateway-event-integration
May 27, 2026
Merged

feat(gateway): wire RFC-011 AsyncEmitter into PEP middleware#90
beonde merged 6 commits into
mainfrom
feat/gateway-event-integration

Conversation

@beonde
Copy link
Copy Markdown
Member

@beonde beonde commented May 27, 2026

Summary

Wires the RFC-011 AsyncEmitter into the gateway PEP middleware to emit runtime events at key points in the request lifecycle.

Changes

pkg/gateway/middleware.go

  • Add RuntimeEmitter *mediation.AsyncEmitter field to PEPConfig
  • Add emitter field to pep struct and wire in NewPolicyMiddleware
  • Emit identity.verified event after successful badge verification
  • Emit identity.invalid event on badge verification failure (missing badge, verification error)
  • Emit authority.granted/authority.denied events on chain verification
  • Emit execution.started and execution.completed events for request lifecycle
  • Add helper functions:
    • emitIdentityVerified() - Emit identity verification success
    • emitIdentityInvalid() - Emit identity verification failure
    • emitAuthorityGranted() - Emit authority grant after chain verification
    • emitAuthorityDenied() - Emit authority denial
    • emitExecutionStarted() - Emit execution start with request context
    • emitExecutionCompleted() - Emit execution completion with status
    • parseTrustLevel() - Convert string trust level to int
    • parseIAL() - Convert string IAL to int

pkg/gateway/event_emission_test.go (NEW)

  • TestEventEmission_IdentityVerified - Verify identity.verified emitted on valid badge
  • TestEventEmission_IdentityInvalid_MissingBadge - Verify identity.invalid emitted when badge missing
  • TestEventEmission_ExecutionLifecycle - Verify execution.started/completed events
  • TestEventEmission_NoEmitter - Verify middleware works silently with nil emitter

RFC Compliance

  • RFC-011 §5.1: identity.verified and identity.invalid events
  • RFC-011 §5.2: authority.granted and authority.denied events
  • RFC-011 §5.4: execution.started and execution.completed events

Testing

go test -v ./pkg/gateway/... -run "TestEventEmission"

All 4 new tests pass. Full gateway test suite passes.

Implements

P1 of the Verification Locality plan - Gateway Event Integration

Follows

- Add RuntimeEmitter field to PEPConfig for RFC-011 event emission
- Add emitter field to pep struct and wire in NewPolicyMiddleware
- Emit identity.verified event after successful badge verification
- Emit identity.invalid event on badge verification failure
- Emit authority.granted/denied events on chain verification
- Emit execution.started and execution.completed events for request lifecycle
- Add helper functions for emitting events with proper mediation context
- Add parseTrustLevel/parseIAL helpers to convert string levels to int

Tests:
- Add event_emission_test.go with tests for:
  - identity.verified emission on valid badge
  - identity.invalid emission on missing badge
  - execution lifecycle (started/completed) emission
  - graceful handling when emitter is nil

Implements P1 of the Verification Locality plan.
RFC: RFC-011 §5.1, §5.2, §5.4
Copilot AI review requested due to automatic review settings May 27, 2026 18:14
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

❌ Patch coverage is 66.82243% with 71 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/gateway/middleware.go 69.41% 59 Missing and 4 partials ⚠️
pkg/mediation/emitter.go 0.00% 8 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates the RFC-011 mediation.AsyncEmitter into the gateway PEP middleware so the gateway can emit runtime events during identity verification, authority-chain handling, and request execution.

Changes:

  • Adds RuntimeEmitter *mediation.AsyncEmitter to gateway.PEPConfig and wires it into the PEP middleware instance.
  • Emits RFC-011 identity and execution lifecycle events from key points in the request flow.
  • Adds a new gateway test suite validating event emission behavior (including nil-emitter “silent mode”).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
pkg/gateway/middleware.go Wires an optional RFC-011 async emitter into the PEP middleware and adds helper functions to emit identity/authority/execution events.
pkg/gateway/event_emission_test.go Adds tests that validate runtime event emission for identity verification and execution lifecycle, plus nil-emitter behavior.

Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go Outdated
Comment thread pkg/gateway/event_emission_test.go Outdated
Comment thread pkg/gateway/event_emission_test.go Outdated
Comment thread pkg/gateway/event_emission_test.go Outdated
Comment thread pkg/gateway/middleware.go
- Clarify RuntimeEmitter doc comment re: blocking behavior (DropOnFull=true)
- Remove duplicate txnID generation in buildPIPRequest (set by serveHTTP)
- Pass LeafCapability in emitAuthorityDenied for leaf subject mismatch
- Add subjectDID parameter to emitExecutionCompleted for correlation
- Add authority.denied emission in handleChainError for chain failures
- Replace time.Sleep with require.Eventually in tests for determinism

Addresses: copilot-pull-request-reviewer comments on PR #90
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

Comment thread pkg/gateway/middleware.go Outdated
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go Outdated
Comment thread pkg/gateway/middleware.go Outdated
Comment thread pkg/gateway/middleware.go Outdated
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
beonde added 2 commits May 27, 2026 14:45
- Remove duplicate authority.denied emission (emit only in handleChainError)
- Pass LeafCapability to handleChainError for meaningful denial events
- Simplify emitAuthorityDenied signature (remove unused errorCode/reason)
- Add trust level 4 to parseTrustLevel (RFC-002 defines 0-4)
- Add warning log when UUIDv7 generation fails and falls back to v4

Addresses: copilot-pull-request-reviewer comments on PR #90
- Add statusCapturingResponseWriter to capture HTTP status codes
- Add executionState struct for tracking execution lifecycle
- Implement defer-based pattern ensuring execution events on ALL exit paths
- Add EmitExecutionAborted to AsyncEmitter for early terminations
- Add emitExecutionAborted helper and outcomeFromStatus for middleware
- Create WithState variants of key handlers for state tracking
- Add tests for execution.aborted and outcome-based execution.completed
- outcome field now reflects actual HTTP status (success/client_error/server_error)

RFC-011 §7.1 PEP Emission Requirements:
- MUST emit execution.completed OR execution.aborted on every exit path
- execution.completed: outcome derived from HTTP status code
- execution.aborted: emitted for auth failures, chain errors, PDP deny

Addresses PR review comments:
- Incomplete execution lifecycle (PRRT_kwDOQYQ-986FMftQ)
- execution.completed always 'success' (PRRT_kwDOQYQ-986FMfti)
- Missing test coverage (PRRT_kwDOQYQ-986FMfuU)
Copilot AI review requested due to automatic review settings May 27, 2026 19:00
@beonde
Copy link
Copy Markdown
Member Author

beonde commented May 27, 2026

RFC-011 §7.1 Execution Lifecycle Implementation Complete

Addressed all remaining review feedback in commit b2b2d7c:

Changes Made

1. Execution Lifecycle Defer Pattern

  • Added statusCapturingResponseWriter to capture HTTP status codes from upstream handlers
  • Added executionState struct to track execution lifecycle across request handling
  • Implemented defer-based pattern in serveHTTP() ensuring execution.completed OR execution.aborted is emitted on every exit path

2. Outcome Derived from HTTP Status

  • Added outcomeFromStatus() helper that maps HTTP status codes:
    • 2xx → "success"
    • 4xx → "client_error"
    • 5xx → "server_error"
  • execution.completed now reports actual outcome instead of always "success"

3. Execution Aborted Events

  • Added EmitExecutionAborted() to AsyncEmitter (mediation package)
  • Added emitExecutionAborted() helper in middleware
  • Aborted events emitted for: chain verification failures, PDP deny, obligation failures, PDP unavailability (non-OBSERVE modes)

4. WithState Handler Variants

  • Created handleBreakGlassWithState, evaluatePolicyWithState, handleCachedDecisionWithState, handlePDPUnavailableWithState, handlePDPDenyWithState, enforceObligationsWithState
  • These track abort state and let the defer handle execution event emission

5. New Test Coverage

  • TestEventEmission_ExecutionAborted_BadgeVerificationFailed - verifies identity.invalid on bad signature
  • TestEventEmission_OutcomeReflectsHTTPStatus - table-driven test verifying outcome field for 200, 201, 400, 404, 500, 503 status codes

All gateway tests passing (including new tests).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

pkg/gateway/middleware.go:516

  • Event emission for authority.granted / authority.denied (and execution.aborted paths) is introduced/expanded here, but the new test suite only covers identity events and execution.completed for successful requests. Please add tests that assert: (1) authority.granted is emitted on successful chain verification, (2) authority.denied is emitted on chain verification failures (including EM-OBSERVE pass-through), and (3) execution.aborted is emitted on fail-closed paths (e.g., EM-STRICT chain failure or PDP deny). This will prevent regressions in these newly added emission branches.
func (p *pep) handleChainError(w http.ResponseWriter, r *http.Request, err error, traceID, txnID, subjectDID, capability string) {
	var envErr *envelope.Error
	if errors.As(err, &envErr) {
		status := ChainErrorHTTPStatus(envErr.Code)
		p.logger.WarnContext(r.Context(), "authority chain verification failed",
			slog.String("error_code", envErr.Code),
			slog.String("error", envErr.Message),
			slog.Int("status", status),
			slog.String("enforcement_mode", p.config.EnforcementMode.String()),
		)

		// RFC-011 §5.2: Emit authority.denied on chain verification failure
		p.emitAuthorityDenied(traceID, txnID, subjectDID, capability)

		// In EM-OBSERVE, log but allow the request through (RFC-005 §6.3)
		if p.config.EnforcementMode == pip.EMObserve {
			p.logger.InfoContext(r.Context(), "chain error in EM-OBSERVE (allowing)",
				slog.String("error_code", envErr.Code))
			p.next.ServeHTTP(w, r)
			return

Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go Outdated
Comment thread pkg/gateway/event_emission_test.go Outdated
- Remove old non-WithState handler functions (handleBreakGlass,
  evaluatePolicy, handleCachedDecision, handlePDPUnavailable,
  handlePDPDeny, enforceObligations) now that serveHTTP uses
  the WithState variants exclusively
- Extract verifyBadge helper to reduce serveHTTP complexity
  from 16 to under 15 (gocyclo limit)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
Comment thread pkg/gateway/middleware.go
Comment thread pkg/mediation/emitter.go
Comment thread pkg/gateway/event_emission_test.go Outdated
- Fix: Only set execState.aborted when enforcement mode actually blocks.
  In EM-OBSERVE mode, chain errors allow the request through, so we
  should NOT emit execution.aborted (it's not an abort).
- Rename misleading test: TestEventEmission_ExecutionAborted_BadgeVerificationFailed
  → TestEventEmission_IdentityInvalid_BadgeVerificationFailed
  (reflects what the test actually verifies)
@beonde beonde merged commit db1eeae into main May 27, 2026
6 checks passed
@beonde beonde deleted the feat/gateway-event-integration branch May 27, 2026 21:05
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