Fix 8 high-severity audit findings across security, Go, API, and container domains

- Use typed context key for auth context to prevent collisions (auth.go)
- Eliminate nested locking in CheckRateLimit to prevent potential deadlock (auth.go)
- Add 1MB request body size limit middleware to prevent DoS (router.go)
- Return proper gRPC status codes instead of nil errors on failures (handler.go)
- Use key name instead of raw API key in admin URL paths to prevent secret leakage (keys.go, router.go, keystore_db.go, keystore_hybrid.go)
- Enforce RBAC authorization in service Send/SendBatch for both REST and gRPC (service.go)
- Pin runtime Docker image to alpine:3.21 for reproducible builds (Dockerfile)
- Enable readOnlyRootFilesystem with /tmp emptyDir in k8s deployment (deployment.yaml)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-26 20:17:51 -07:00
parent 71b02758d7
commit 298c960808
9 changed files with 212 additions and 43 deletions
+6 -9
View File
@@ -8,6 +8,8 @@ import (
pb "github.com/igodwin/notifier/api/grpc/pb"
"github.com/igodwin/notifier/internal/domain"
"github.com/igodwin/notifier/internal/logging"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)
@@ -82,12 +84,7 @@ func (h *NotifierHandler) SendNotification(ctx context.Context, req *pb.SendNoti
if err != nil {
h.logger.Errorf("gRPC: Failed to send notification - type=%s, account=%s, error=%v",
req.Type, req.Account, err)
return &pb.SendNotificationResponse{
Result: &pb.NotificationResult{
Success: false,
Error: err.Error(),
},
}, nil
return nil, status.Errorf(codes.Internal, "failed to send notification: %v", err)
}
// Log success
@@ -139,7 +136,7 @@ func (h *NotifierHandler) SendBatchNotifications(ctx context.Context, req *pb.Se
func (h *NotifierHandler) GetNotification(ctx context.Context, req *pb.GetNotificationRequest) (*pb.GetNotificationResponse, error) {
notification, err := h.service.GetNotification(ctx, req.Id)
if err != nil {
return nil, err
return nil, status.Errorf(codes.NotFound, "notification not found: %v", err)
}
return &pb.GetNotificationResponse{
@@ -154,7 +151,7 @@ func (h *NotifierHandler) ListNotifications(ctx context.Context, req *pb.ListNot
notifications, err := h.service.ListNotifications(ctx, filter)
if err != nil {
return nil, err
return nil, status.Errorf(codes.Internal, "failed to list notifications: %v", err)
}
protoNotifications := make([]*pb.Notification, len(notifications))
@@ -230,7 +227,7 @@ func (h *NotifierHandler) GetNotifiers(ctx context.Context, req *pb.GetNotifiers
notifiers, err := h.service.GetNotifiers(ctx)
if err != nil {
h.logger.Errorf("gRPC: Failed to get notifiers - error=%v", err)
return nil, err
return nil, status.Errorf(codes.Internal, "failed to get notifiers: %v", err)
}
// Convert domain notifiers to proto notifiers