Merge branch 'fix/m2-pr-f-scheduler-contextcheck-audit-closeout'

This commit is contained in:
shankar0123
2026-04-18 01:43:56 +00:00
4 changed files with 26 additions and 4 deletions
+1
View File
@@ -6,6 +6,7 @@ run:
linters:
default: none
enable:
- contextcheck
- govet
- staticcheck
- unused
+10 -1
View File
@@ -132,6 +132,15 @@ func (a *AuditMiddleware) Middleware(next http.Handler) http.Handler {
path := r.URL.Path
status := wrapped.statusCode
// Derive a detached context that preserves request-scoped values
// (trace IDs, auth info carried via context keys) but is not cancelled
// when the HTTP server finalizes the request. Using r.Context()
// directly would cause the async audit write to observe ctx.Done()
// as soon as the response completes; using context.Background() would
// discard useful observability metadata. WithoutCancel gives us both
// (M-2 / D-3).
auditCtx := context.WithoutCancel(r.Context())
// Record audit event asynchronously (best-effort, don't block response).
// SECURITY: We intentionally use r.URL.Path (not r.URL.String() or r.RequestURI)
// to prevent query parameters from being recorded in the immutable audit trail.
@@ -147,7 +156,7 @@ func (a *AuditMiddleware) Middleware(next http.Handler) http.Handler {
go func() {
defer a.wg.Done()
if err := a.recorder.RecordAPICall(
context.Background(),
auditCtx,
method,
path,
actor,
+10 -2
View File
@@ -5,6 +5,7 @@ import (
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"fmt"
"log"
"log/slog"
"net/http"
@@ -78,10 +79,17 @@ func NewLogging(logger *slog.Logger) func(http.Handler) http.Handler {
// Recovery middleware recovers from panics and returns a 500 error.
func Recovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
defer func() {
if err := recover(); err != nil {
requestID := getRequestID(r.Context())
log.Printf("[%s] PANIC: %v", requestID, err)
requestID := getRequestID(ctx)
// Use slog.ErrorContext so the panic log carries the same
// request-scoped trace/auth metadata as normal request logs
// (M-2 / D-3 — preserve ctx propagation on the panic path).
slog.ErrorContext(ctx, "panic recovered in HTTP handler",
"request_id", requestID,
"panic", fmt.Sprintf("%v", err),
)
http.Error(w, `{"error":"Internal Server Error"}`, http.StatusInternalServerError)
}
}()
+5 -1
View File
@@ -547,7 +547,11 @@ func (c *Connector) solveAuthorizationsHTTP01(ctx context.Context, authzURLs []s
return fmt.Errorf("failed to start challenge server: %w", err)
}
defer func() {
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
// Derive the challenge-server shutdown context from the parent ctx so
// values (trace IDs, deadlines) propagate, but detach from its
// cancellation so Shutdown always gets its full budget even when the
// parent was cancelled (M-2 / D-3).
shutdownCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
defer cancel()
_ = srv.Shutdown(shutdownCtx)
c.logger.Debug("challenge server stopped")