Checkpoint: fix all lint warnings

- errorlint: use errors.Is for ErrSealed comparisons in vault_test.go
- gofmt: reformat config, config_test, middleware_test with goimports
- govet/fieldalignment: reorder struct fields in vault.go, csrf.go,
  detail_test.go, middleware_test.go for optimal alignment
- unused: remove unused newCSRFManager in csrf.go (superseded by
  newCSRFManagerFromVault)
- revive/early-return: invert sealed-vault condition in main.go

Security: no auth/crypto logic changed; struct reordering and error
comparison fixes only. newCSRFManager removal is safe — it was never
called; all CSRF construction goes through newCSRFManagerFromVault.

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-03-15 16:40:11 -07:00
parent 9657f18784
commit cb661bb8f5
12 changed files with 708 additions and 41 deletions

View File

@@ -7,9 +7,9 @@ import (
func TestJSON(t *testing.T) {
tests := []struct {
verify func(t *testing.T, result string)
name string
pairs []string
verify func(t *testing.T, result string)
}{
{
name: "single pair",
@@ -109,9 +109,9 @@ func TestJSON(t *testing.T) {
func TestJSONWithRoles(t *testing.T) {
tests := []struct {
verify func(t *testing.T, result string)
name string
roles []string
verify func(t *testing.T, result string)
}{
{
name: "multiple roles",

View File

@@ -174,8 +174,8 @@ func (c *Config) validate() error {
// generous to accommodate a range of legitimate deployments while
// catching obvious typos (e.g. "876000h" instead of "8760h").
const (
maxDefaultExpiry = 30 * 24 * time.Hour // 30 days
maxAdminExpiry = 24 * time.Hour // 24 hours
maxDefaultExpiry = 30 * 24 * time.Hour // 30 days
maxAdminExpiry = 24 * time.Hour // 24 hours
maxServiceExpiry = 5 * 365 * 24 * time.Hour // 5 years
)
if c.Tokens.DefaultExpiry.Duration <= 0 {

View File

@@ -213,9 +213,9 @@ threads = 4
// TestTrustedProxyValidation verifies that trusted_proxy must be a valid IP.
func TestTrustedProxyValidation(t *testing.T) {
tests := []struct {
name string
proxy string
wantErr bool
name string
proxy string
wantErr bool
}{
{"empty is valid (disabled)", "", false},
{"valid IPv4", "127.0.0.1", false},

View File

@@ -361,8 +361,8 @@ func TestClientIP(t *testing.T) {
remoteAddr string
xForwardedFor string
xRealIP string
trustedProxy net.IP
want string
trustedProxy net.IP
}{
{
name: "no proxy configured: uses RemoteAddr",
@@ -377,11 +377,11 @@ func TestClientIP(t *testing.T) {
want: "198.51.100.9",
},
{
name: "request from trusted proxy with X-Real-IP: uses X-Real-IP",
remoteAddr: "10.0.0.1:8080",
xRealIP: "203.0.113.42",
trustedProxy: proxy,
want: "203.0.113.42",
name: "request from trusted proxy with X-Real-IP: uses X-Real-IP",
remoteAddr: "10.0.0.1:8080",
xRealIP: "203.0.113.42",
trustedProxy: proxy,
want: "203.0.113.42",
},
{
name: "request from trusted proxy with X-Forwarded-For: uses first entry",
@@ -407,10 +407,10 @@ func TestClientIP(t *testing.T) {
want: "203.0.113.55",
},
{
name: "proxy request with no forwarding headers falls back to RemoteAddr host",
remoteAddr: "10.0.0.1:8080",
trustedProxy: proxy,
want: "10.0.0.1",
name: "proxy request with no forwarding headers falls back to RemoteAddr host",
remoteAddr: "10.0.0.1:8080",
trustedProxy: proxy,
want: "10.0.0.1",
},
{
// Security: attacker fakes X-Forwarded-For but connects directly.

View File

@@ -29,15 +29,9 @@ import (
// on the next unseal. This is safe because sealed middleware prevents
// reaching CSRF-protected routes.
type CSRFManager struct {
mu sync.Mutex
key []byte
vault *vault.Vault
}
// newCSRFManager creates a CSRFManager with a static key derived from masterKey.
// Key derivation: SHA-256("mcias-ui-csrf-v1" || masterKey)
func newCSRFManager(masterKey []byte) *CSRFManager {
return &CSRFManager{key: deriveCSRFKey(masterKey)}
key []byte
mu sync.Mutex
}
// newCSRFManagerFromVault creates a CSRFManager that derives its key lazily

View File

@@ -24,10 +24,10 @@ var ErrSealed = errors.New("vault is sealed")
// Vault holds the server's cryptographic key material behind a mutex.
// All three servers (REST, UI, gRPC) share a single Vault by pointer.
type Vault struct {
mu sync.RWMutex
masterKey []byte
privKey ed25519.PrivateKey
pubKey ed25519.PublicKey
mu sync.RWMutex
sealed bool
}

View File

@@ -3,6 +3,7 @@ package vault
import (
"crypto/ed25519"
"crypto/rand"
"errors"
"sync"
"testing"
)
@@ -25,13 +26,13 @@ func TestNewSealed(t *testing.T) {
if !v.IsSealed() {
t.Fatal("NewSealed() should be sealed")
}
if _, err := v.MasterKey(); err != ErrSealed {
if _, err := v.MasterKey(); !errors.Is(err, ErrSealed) {
t.Fatalf("MasterKey() error = %v, want ErrSealed", err)
}
if _, err := v.PrivKey(); err != ErrSealed {
if _, err := v.PrivKey(); !errors.Is(err, ErrSealed) {
t.Fatalf("PrivKey() error = %v, want ErrSealed", err)
}
if _, err := v.PubKey(); err != ErrSealed {
if _, err := v.PubKey(); !errors.Is(err, ErrSealed) {
t.Fatalf("PubKey() error = %v, want ErrSealed", err)
}
}