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:
2026-03-11 15:24:07 -07:00
parent 941c71f2d1
commit f34e9a69a0
8 changed files with 35 additions and 37 deletions

View File

@@ -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,

View File

@@ -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)

View File

@@ -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")

View File

@@ -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{

View File

@@ -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")

View File

@@ -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 {

View File

@@ -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(

View File

@@ -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")