Fix all golangci-lint warnings
- errorlint: use errors.Is for db.ErrNotFound comparisons in accountservice.go, credentialservice.go, tokenservice.go - gofmt/goimports: move mciasv1 alias into internal import group in auth.go, credentialservice.go, grpcserver.go, grpcserver_test.go - gosec G115: add nolint annotation on int32 port conversions in mciasgrpcctl/main.go and credentialservice.go (port validated as [1,65535] on input; overflow not reachable) - govet fieldalignment: reorder Server, grpcRateLimiter, grpcRateLimitEntry, testEnv structs to reduce GC bitmap size (96 -> 80 pointer bytes each) - ineffassign: remove intermediate grpcSrv = GRPCServer() call in cmd/mciassrv/main.go (immediately overwritten by TLS build) - staticcheck SA9003: replace empty if-body with _ = Serve(lis) in grpcserver_test.go 0 golangci-lint issues; 137 tests pass (go test -race ./...)
This commit is contained in:
@@ -506,7 +506,7 @@ func (c *controller) pgCredsSet(args []string) {
|
||||
Id: *id,
|
||||
Creds: &mciasv1.PGCreds{
|
||||
Host: *host,
|
||||
Port: int32(*port),
|
||||
Port: int32(*port), //nolint:gosec // G115: port validated as [1,65535] by flag parsing
|
||||
Database: *dbName,
|
||||
Username: *username,
|
||||
Password: *password,
|
||||
|
||||
@@ -132,11 +132,8 @@ func run(configPath string, logger *slog.Logger) error {
|
||||
}
|
||||
|
||||
grpcSrvImpl := grpcserver.New(database, cfg, privKey, pubKey, masterKey, logger)
|
||||
grpcSrv = grpcSrvImpl.GRPCServer()
|
||||
// Apply TLS to the gRPC server by wrapping options.
|
||||
// We reconstruct the server with TLS credentials since GRPCServer()
|
||||
// returns an already-built server; instead, build with creds directly.
|
||||
// Re-create with TLS option.
|
||||
// Build server directly with TLS credentials. GRPCServerWithCreds builds
|
||||
// the server with transport credentials at construction time per gRPC idiom.
|
||||
grpcSrv = rebuildGRPCServerWithTLS(grpcSrvImpl, grpcTLSCreds)
|
||||
|
||||
grpcListener, err = net.Listen("tcp", cfg.Server.GRPCAddr)
|
||||
|
||||
@@ -4,16 +4,17 @@ package grpcserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/auth"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/db"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/model"
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
)
|
||||
|
||||
type accountServiceServer struct {
|
||||
@@ -101,7 +102,7 @@ func (a *accountServiceServer) GetAccount(ctx context.Context, req *mciasv1.GetA
|
||||
}
|
||||
acct, err := a.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
@@ -119,7 +120,7 @@ func (a *accountServiceServer) UpdateAccount(ctx context.Context, req *mciasv1.U
|
||||
}
|
||||
acct, err := a.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
@@ -149,7 +150,7 @@ func (a *accountServiceServer) DeleteAccount(ctx context.Context, req *mciasv1.D
|
||||
}
|
||||
acct, err := a.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
@@ -174,7 +175,7 @@ func (a *accountServiceServer) GetRoles(ctx context.Context, req *mciasv1.GetRol
|
||||
}
|
||||
acct, err := a.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
@@ -199,7 +200,7 @@ func (a *accountServiceServer) SetRoles(ctx context.Context, req *mciasv1.SetRol
|
||||
}
|
||||
acct, err := a.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/auth"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/crypto"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/model"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/token"
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
)
|
||||
|
||||
type authServiceServer struct {
|
||||
@@ -97,8 +97,8 @@ func (a *authServiceServer) Login(ctx context.Context, req *mciasv1.LoginRequest
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
}
|
||||
|
||||
a.s.db.WriteAuditEvent(model.EventLoginOK, &acct.ID, nil, ip, "") //nolint:errcheck
|
||||
a.s.db.WriteAuditEvent(model.EventTokenIssued, &acct.ID, nil, ip, //nolint:errcheck
|
||||
a.s.db.WriteAuditEvent(model.EventLoginOK, &acct.ID, nil, ip, "") //nolint:errcheck
|
||||
a.s.db.WriteAuditEvent(model.EventTokenIssued, &acct.ID, nil, ip, //nolint:errcheck
|
||||
fmt.Sprintf(`{"jti":%q}`, claims.JTI))
|
||||
|
||||
return &mciasv1.LoginResponse{
|
||||
|
||||
@@ -4,14 +4,15 @@ package grpcserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/crypto"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/db"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/model"
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
)
|
||||
|
||||
type credentialServiceServer struct {
|
||||
@@ -31,7 +32,7 @@ func (c *credentialServiceServer) GetPGCreds(ctx context.Context, req *mciasv1.G
|
||||
}
|
||||
acct, err := c.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
@@ -39,7 +40,7 @@ func (c *credentialServiceServer) GetPGCreds(ctx context.Context, req *mciasv1.G
|
||||
|
||||
cred, err := c.s.db.ReadPGCredentials(acct.ID)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "no credentials stored")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
@@ -58,8 +59,8 @@ func (c *credentialServiceServer) GetPGCreds(ctx context.Context, req *mciasv1.G
|
||||
Host: cred.PGHost,
|
||||
Database: cred.PGDatabase,
|
||||
Username: cred.PGUsername,
|
||||
Password: string(password), // security: returned only on explicit admin request
|
||||
Port: int32(cred.PGPort),
|
||||
Password: string(password), // security: returned only on explicit admin request
|
||||
Port: int32(cred.PGPort), //nolint:gosec // G115: PGPort is validated as [1,65535] on write
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -87,7 +88,7 @@ func (c *credentialServiceServer) SetPGCreds(ctx context.Context, req *mciasv1.S
|
||||
|
||||
acct, err := c.s.db.GetAccountByUUID(req.Id)
|
||||
if err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "account not found")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
|
||||
@@ -31,10 +31,10 @@ import (
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/config"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/db"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/token"
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
)
|
||||
|
||||
// contextKey is the unexported context key type for this package.
|
||||
@@ -55,10 +55,10 @@ func claimsFromContext(ctx context.Context) *token.Claims {
|
||||
type Server struct {
|
||||
db *db.DB
|
||||
cfg *config.Config
|
||||
logger *slog.Logger
|
||||
privKey ed25519.PrivateKey
|
||||
pubKey ed25519.PublicKey
|
||||
masterKey []byte
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// New creates a Server with the given dependencies (same as the REST Server).
|
||||
@@ -76,10 +76,10 @@ func New(database *db.DB, cfg *config.Config, priv ed25519.PrivateKey, pub ed255
|
||||
// publicMethods is the set of fully-qualified method names that bypass auth.
|
||||
// These match the gRPC full method path: /<package>.<Service>/<Method>.
|
||||
var publicMethods = map[string]bool{
|
||||
"/mcias.v1.AdminService/Health": true,
|
||||
"/mcias.v1.AdminService/GetPublicKey": true,
|
||||
"/mcias.v1.TokenService/ValidateToken": true,
|
||||
"/mcias.v1.AuthService/Login": true,
|
||||
"/mcias.v1.AdminService/Health": true,
|
||||
"/mcias.v1.AdminService/GetPublicKey": true,
|
||||
"/mcias.v1.TokenService/ValidateToken": true,
|
||||
"/mcias.v1.AuthService/Login": true,
|
||||
}
|
||||
|
||||
// GRPCServer builds and returns a configured *grpc.Server with all services
|
||||
@@ -217,17 +217,17 @@ func (s *Server) requireAdmin(ctx context.Context) error {
|
||||
// grpcRateLimiter is a per-IP token bucket for gRPC, sharing the same
|
||||
// algorithm as the REST RateLimit middleware.
|
||||
type grpcRateLimiter struct {
|
||||
mu sync.Mutex
|
||||
ips map[string]*grpcRateLimitEntry
|
||||
rps float64
|
||||
burst float64
|
||||
ttl time.Duration
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type grpcRateLimitEntry struct {
|
||||
mu sync.Mutex
|
||||
lastSeen time.Time
|
||||
tokens float64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newGRPCRateLimiter(rps float64, burst int) *grpcRateLimiter {
|
||||
|
||||
@@ -22,12 +22,12 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/auth"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/config"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/db"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/model"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/token"
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -38,11 +38,11 @@ const (
|
||||
// testEnv holds all resources for a single test's gRPC server.
|
||||
type testEnv struct {
|
||||
db *db.DB
|
||||
cfg *config.Config
|
||||
conn *grpc.ClientConn
|
||||
priv ed25519.PrivateKey
|
||||
pub ed25519.PublicKey
|
||||
masterKey []byte
|
||||
cfg *config.Config
|
||||
conn *grpc.ClientConn
|
||||
}
|
||||
|
||||
// newTestEnv spins up an in-process gRPC server using bufconn and returns
|
||||
@@ -76,9 +76,7 @@ func newTestEnv(t *testing.T) *testEnv {
|
||||
|
||||
lis := bufconn.Listen(bufConnSize)
|
||||
go func() {
|
||||
if err := grpcSrv.Serve(lis); err != nil {
|
||||
// Serve returns when the listener is closed; ignore that error.
|
||||
}
|
||||
_ = grpcSrv.Serve(lis) // returns on listener close; error ignored
|
||||
}()
|
||||
|
||||
conn, err := grpc.NewClient(
|
||||
|
||||
@@ -3,16 +3,17 @@ package grpcserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/db"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/model"
|
||||
"git.wntrmute.dev/kyle/mcias/internal/token"
|
||||
mciasv1 "git.wntrmute.dev/kyle/mcias/gen/mcias/v1"
|
||||
)
|
||||
|
||||
type tokenServiceServer struct {
|
||||
@@ -110,7 +111,7 @@ func (ts *tokenServiceServer) RevokeToken(ctx context.Context, req *mciasv1.Revo
|
||||
}
|
||||
|
||||
if err := ts.s.db.RevokeToken(req.Jti, "admin revocation"); err != nil {
|
||||
if err == db.ErrNotFound {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "token not found or already revoked")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "internal error")
|
||||
|
||||
Reference in New Issue
Block a user