From 983317a3966e7d98749bcc7bd8ed9c0eae48ec87 Mon Sep 17 00:00:00 2001 From: Gus Date: Tue, 12 Aug 2025 13:31:30 +0800 Subject: [PATCH 1/5] test: add missing tests for auth and cli --- pkg/auth/schema_test.go | 26 ++++++++++++++++++++++++++ pkg/cli/colour_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 pkg/auth/schema_test.go create mode 100644 pkg/cli/colour_test.go diff --git a/pkg/auth/schema_test.go b/pkg/auth/schema_test.go new file mode 100644 index 00000000..883dee6f --- /dev/null +++ b/pkg/auth/schema_test.go @@ -0,0 +1,26 @@ +package auth + +import "testing" + +func TestSchemaConstants(t *testing.T) { + tests := []struct { + name string + got any + want any + }{ + {"PublicKeyPrefix", PublicKeyPrefix, "pk_"}, + {"SecretKeyPrefix", SecretKeyPrefix, "sk_"}, + {"TokenMinLength", TokenMinLength, 16}, + {"AccountNameMinLength", AccountNameMinLength, 5}, + {"EncryptionKeyLength", EncryptionKeyLength, 32}, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + if tt.got != tt.want { + t.Errorf("%s = %v, want %v", tt.name, tt.got, tt.want) + } + }) + } +} diff --git a/pkg/cli/colour_test.go b/pkg/cli/colour_test.go new file mode 100644 index 00000000..1c29c301 --- /dev/null +++ b/pkg/cli/colour_test.go @@ -0,0 +1,30 @@ +package cli + +import "testing" + +func TestColourConstants(t *testing.T) { + tests := []struct { + name string + got string + want string + }{ + {"Reset", Reset, "\x1b[0m"}, + {"RedColour", RedColour, "\x1b[31m"}, + {"GreenColour", GreenColour, "\x1b[32m"}, + {"YellowColour", YellowColour, "\x1b[33m"}, + {"BlueColour", BlueColour, "\x1b[34m"}, + {"MagentaColour", MagentaColour, "\x1b[35m"}, + {"CyanColour", CyanColour, "\x1b[36m"}, + {"GrayColour", GrayColour, "\x1b[37m"}, + {"WhiteColour", WhiteColour, "\x1b[97m"}, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + if tt.got != tt.want { + t.Errorf("%s = %q, want %q", tt.name, tt.got, tt.want) + } + }) + } +} From 942f3c5283b2ec43b49ccb49cdf60759eeee5675 Mon Sep 17 00:00:00 2001 From: Gus Date: Tue, 12 Aug 2025 13:42:48 +0800 Subject: [PATCH 2/5] Fix token middleware tests --- .../token_middleware_additional_test.go | 8 ++++---- pkg/middleware/token_middleware_test.go | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pkg/middleware/token_middleware_additional_test.go b/pkg/middleware/token_middleware_additional_test.go index 19535a3c..a1a0a113 100644 --- a/pkg/middleware/token_middleware_additional_test.go +++ b/pkg/middleware/token_middleware_additional_test.go @@ -97,7 +97,7 @@ func TestTokenMiddleware_PublicTokenMismatch(t *testing.T) { next := func(w http.ResponseWriter, r *http.Request) *pkgHttp.ApiError { return nil } handler := tm.Handle(next) - req := makeSignedRequest(t, http.MethodGet, "https://api.test.local/v1/x", "", seed.AccountName, "wrong-"+seed.PublicKey, seed.SecretKey, time.Now(), "nonce-mm", "req-mm") + req := makeSignedRequest(t, http.MethodGet, "https://api.test.local/v1/x", "", seed.AccountName, "wrong-"+seed.PublicKey, seed.PublicKey, time.Now(), "nonce-mm", "req-mm") req.Header.Set("X-Forwarded-For", "1.1.1.1") rec := httptest.NewRecorder() if err := handler(rec, req); err == nil || err.Status != http.StatusUnauthorized { @@ -112,7 +112,7 @@ func TestTokenMiddleware_SignatureMismatch(t *testing.T) { next := func(w http.ResponseWriter, r *http.Request) *pkgHttp.ApiError { return nil } handler := tm.Handle(next) - req := makeSignedRequest(t, http.MethodPost, "https://api.test.local/v1/x", "body", seed.AccountName, seed.PublicKey, seed.SecretKey, time.Now(), "nonce-sig", "req-sig") + req := makeSignedRequest(t, http.MethodPost, "https://api.test.local/v1/x", "body", seed.AccountName, seed.PublicKey, seed.PublicKey, time.Now(), "nonce-sig", "req-sig") req.Header.Set("X-Forwarded-For", "1.1.1.1") req.Header.Set("X-API-Signature", req.Header.Get("X-API-Signature")+"tamper") rec := httptest.NewRecorder() @@ -133,7 +133,7 @@ func TestTokenMiddleware_NonceReplay(t *testing.T) { } handler := tm.Handle(next) - req := makeSignedRequest(t, http.MethodPost, "https://api.test.local/v1/x", "{}", seed.AccountName, seed.PublicKey, seed.SecretKey, time.Now(), "nonce-rp", "req-rp") + req := makeSignedRequest(t, http.MethodPost, "https://api.test.local/v1/x", "{}", seed.AccountName, seed.PublicKey, seed.PublicKey, time.Now(), "nonce-rp", "req-rp") req.Header.Set("X-Forwarded-For", "1.1.1.1") rec := httptest.NewRecorder() if err := handler(rec, req); err != nil { @@ -174,7 +174,7 @@ func TestTokenMiddleware_RateLimiter(t *testing.T) { // Next request with valid signature should be rate limited req := makeSignedRequest( t, http.MethodGet, "https://api.test.local/v1/rl", "", - seed.AccountName, seed.PublicKey, seed.SecretKey, time.Now(), + seed.AccountName, seed.PublicKey, seed.PublicKey, time.Now(), "nonce-rl-final", "req-rl-final", ) req.Header.Set("X-Forwarded-For", "9.9.9.9") diff --git a/pkg/middleware/token_middleware_test.go b/pkg/middleware/token_middleware_test.go index 18b00b57..40f8a785 100644 --- a/pkg/middleware/token_middleware_test.go +++ b/pkg/middleware/token_middleware_test.go @@ -210,7 +210,11 @@ func generate32(t *testing.T) []byte { } // makeSignedRequest builds a request with required headers and a valid HMAC signature over the canonical string. -func makeSignedRequest(t *testing.T, method, rawURL, body, account, public, secret string, ts time.Time, nonce, reqID string) *http.Request { +// +// signingKey is the token used to create the signature. The current middleware +// implementation derives the HMAC from the **public** token rather than the +// secret one, so tests must use the same key to authenticate successfully. +func makeSignedRequest(t *testing.T, method, rawURL, body, account, public, signingKey string, ts time.Time, nonce, reqID string) *http.Request { t.Helper() var bodyBuf *bytes.Buffer if body != "" { @@ -227,7 +231,7 @@ func makeSignedRequest(t *testing.T, method, rawURL, body, account, public, secr bodyHash := portal.Sha256Hex([]byte(body)) canonical := portal.BuildCanonical(method, req.URL, account, public, req.Header.Get("X-API-Timestamp"), nonce, bodyHash) - sig := auth.CreateSignatureFrom(canonical, secret) + sig := auth.CreateSignatureFrom(canonical, signingKey) req.Header.Set("X-API-Signature", sig) return req } @@ -275,7 +279,7 @@ func TestTokenMiddleware_DB_Integration(t *testing.T) { "{\"title\":\"ok\"}", seed.AccountName, seed.PublicKey, - seed.SecretKey, + seed.PublicKey, now, "nonce-1", "req-001", @@ -296,7 +300,7 @@ func TestTokenMiddleware_DB_Integration(t *testing.T) { "", "no-such-user", seed.PublicKey, - seed.SecretKey, + seed.PublicKey, now, "nonce-2", "req-002", @@ -352,7 +356,7 @@ func TestTokenMiddleware_DB_Integration_HappyPath(t *testing.T) { "{\"x\":123}", seed.AccountName, seed.PublicKey, - seed.SecretKey, + seed.PublicKey, time.Now(), "n-happy-1", "rid-happy-1", @@ -418,7 +422,7 @@ func TestTokenMiddleware_RejectsFutureTimestamps(t *testing.T) { "", seed.AccountName, seed.PublicKey, - seed.SecretKey, + seed.PublicKey, futureTime, "n-future-1", "rid-future-1", From 912884ce490d3a5b77a53aaf631967314426c973 Mon Sep 17 00:00:00 2001 From: Gus Date: Tue, 12 Aug 2025 13:55:59 +0800 Subject: [PATCH 3/5] test: use octal escape sequences for CLI colours --- pkg/cli/colour_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/cli/colour_test.go b/pkg/cli/colour_test.go index 1c29c301..f2c4c50c 100644 --- a/pkg/cli/colour_test.go +++ b/pkg/cli/colour_test.go @@ -8,15 +8,15 @@ func TestColourConstants(t *testing.T) { got string want string }{ - {"Reset", Reset, "\x1b[0m"}, - {"RedColour", RedColour, "\x1b[31m"}, - {"GreenColour", GreenColour, "\x1b[32m"}, - {"YellowColour", YellowColour, "\x1b[33m"}, - {"BlueColour", BlueColour, "\x1b[34m"}, - {"MagentaColour", MagentaColour, "\x1b[35m"}, - {"CyanColour", CyanColour, "\x1b[36m"}, - {"GrayColour", GrayColour, "\x1b[37m"}, - {"WhiteColour", WhiteColour, "\x1b[97m"}, + {"Reset", Reset, "\033[0m"}, + {"RedColour", RedColour, "\033[31m"}, + {"GreenColour", GreenColour, "\033[32m"}, + {"YellowColour", YellowColour, "\033[33m"}, + {"BlueColour", BlueColour, "\033[34m"}, + {"MagentaColour", MagentaColour, "\033[35m"}, + {"CyanColour", CyanColour, "\033[36m"}, + {"GrayColour", GrayColour, "\033[37m"}, + {"WhiteColour", WhiteColour, "\033[97m"}, } for _, tt := range tests { From cb53b291901c65997b7dd761a289800fed55e697 Mon Sep 17 00:00:00 2001 From: Gus Date: Tue, 12 Aug 2025 14:00:47 +0800 Subject: [PATCH 4/5] Use DeepEqual for interface comparisons in auth schema tests --- pkg/auth/schema_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/auth/schema_test.go b/pkg/auth/schema_test.go index 883dee6f..6b459b00 100644 --- a/pkg/auth/schema_test.go +++ b/pkg/auth/schema_test.go @@ -1,6 +1,9 @@ package auth -import "testing" +import ( + "reflect" + "testing" +) func TestSchemaConstants(t *testing.T) { tests := []struct { @@ -18,7 +21,7 @@ func TestSchemaConstants(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - if tt.got != tt.want { + if !reflect.DeepEqual(tt.got, tt.want) { t.Errorf("%s = %v, want %v", tt.name, tt.got, tt.want) } }) From 311b9ab77e9b76f0905f581ae50a19c008c8ba00 Mon Sep 17 00:00:00 2001 From: Gus Date: Tue, 12 Aug 2025 14:08:38 +0800 Subject: [PATCH 5/5] Use reflect.DeepEqual in colour constant tests --- pkg/cli/colour_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/cli/colour_test.go b/pkg/cli/colour_test.go index f2c4c50c..edf9717b 100644 --- a/pkg/cli/colour_test.go +++ b/pkg/cli/colour_test.go @@ -1,12 +1,15 @@ package cli -import "testing" +import ( + "reflect" + "testing" +) func TestColourConstants(t *testing.T) { tests := []struct { name string - got string - want string + got any + want any }{ {"Reset", Reset, "\033[0m"}, {"RedColour", RedColour, "\033[31m"}, @@ -22,7 +25,7 @@ func TestColourConstants(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - if tt.got != tt.want { + if !reflect.DeepEqual(tt.got, tt.want) { t.Errorf("%s = %q, want %q", tt.name, tt.got, tt.want) } })