ci/cd: migrate backend linter to v2. fixed unit test workflow (#400)

This commit is contained in:
Rich
2025-03-28 02:00:55 -07:00
committed by GitHub
parent cbd1bbdf74
commit b935a4824a
16 changed files with 95 additions and 53 deletions

View File

@@ -32,8 +32,8 @@ jobs:
go-version-file: backend/go.mod
- name: Run Golangci-lint
uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2
uses: golangci/golangci-lint-action@dec74fa03096ff515422f71d18d41307cacde373 # v7.0.0
with:
version: v1.64
version: v2.0.2
working-directory: backend
only-new-issues: ${{ github.event_name == 'pull_request' }}

View File

@@ -25,6 +25,7 @@ jobs:
- name: Run backend unit tests
working-directory: backend
run: |
set -e -o pipefail
go test -v ./... | tee /tmp/TestResults.log
- uses: actions/upload-artifact@v4
if: always()

View File

@@ -1,25 +1,64 @@
version: "2"
run:
tests: true
timeout: 5m
linters:
# Disable all linters.
# Default: false
disable-all: true
default: none
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- contextcheck
- copyloopvar
- durationcheck
- errcheck
- gosimple
- errchkjson
- errorlint
- exhaustive
- gocheckcompilerdirectives
- gochecksumtype
- gocognit
- gocritic
- gosec
- gosmopolitan
- govet
- ineffassign
- loggercheck
- makezero
- musttag
- nilerr
- nilnesserr
- noctx
- protogetter
- reassign
- recvcheck
- rowserrcheck
- spancheck
- sqlclosecheck
- staticcheck
- testifylint
- unused
- gosec
- gocognit
presets:
- bugs
- sql
- usestdlibvars
- zerologlint
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
- internal/service/test_service.go
run:
timeout: "5m"
tests: true
formatters:
enable:
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@@ -1,6 +1,6 @@
module github.com/pocket-id/pocket-id/backend
go 1.23.1
go 1.23.7
require (
github.com/caarlos0/env/v11 v11.3.1

View File

@@ -240,12 +240,13 @@ func (oc *OidcController) EndSessionHandler(c *gin.Context) {
var input dto.OidcLogoutDto
// Bind query parameters to the struct
if c.Request.Method == http.MethodGet {
switch c.Request.Method {
case http.MethodGet:
if err := c.ShouldBindQuery(&input); err != nil {
_ = c.Error(err)
return
}
} else if c.Request.Method == http.MethodPost {
case http.MethodPost:
// Bind form parameters to the struct
if err := c.ShouldBind(&input); err != nil {
_ = c.Error(err)

View File

@@ -63,13 +63,14 @@ func mapStructInternal(sourceVal reflect.Value, destVal reflect.Value) error {
}
func mapField(sourceField reflect.Value, destField reflect.Value) error {
if sourceField.Type() == destField.Type() {
switch {
case sourceField.Type() == destField.Type():
destField.Set(sourceField)
} else if sourceField.Kind() == reflect.Slice && destField.Kind() == reflect.Slice {
case sourceField.Kind() == reflect.Slice && destField.Kind() == reflect.Slice:
return mapSlice(sourceField, destField)
} else if sourceField.Kind() == reflect.Struct && destField.Kind() == reflect.Struct {
case sourceField.Kind() == reflect.Struct && destField.Kind() == reflect.Struct:
return mapStructInternal(sourceField, destField)
} else {
default:
return mapSpecialTypes(sourceField, destField)
}
return nil
@@ -98,8 +99,7 @@ func mapSlice(sourceField reflect.Value, destField reflect.Value) error {
}
func mapSpecialTypes(sourceField reflect.Value, destField reflect.Value) error {
switch sourceField.Interface().(type) {
case datatype.DateTime:
if _, ok := sourceField.Interface().(datatype.DateTime); ok {
if sourceField.Type() == reflect.TypeOf(datatype.DateTime{}) && destField.Type() == reflect.TypeOf(time.Time{}) {
dateValue := sourceField.Interface().(datatype.DateTime)
destField.Set(reflect.ValueOf(dateValue.ToTime()))

View File

@@ -1,10 +1,11 @@
package dto
import (
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
"log"
"regexp"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
var validateUsername validator.Func = func(fl validator.FieldLevel) bool {

View File

@@ -1,6 +1,8 @@
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/pocket-id/pocket-id/backend/internal/common"
)
@@ -23,7 +25,7 @@ func (m *CorsMiddleware) Add() gin.HandlerFunc {
c.Writer.Header().Set("Access-Control-Allow-Headers", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
if c.Request.Method == http.MethodOptions {
c.AbortWithStatus(204)
return
}

View File

@@ -1,8 +1,6 @@
package model
import (
"github.com/pocket-id/pocket-id/backend/internal/model/types"
)
import datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
type ApiKey struct {
Base

View File

@@ -4,7 +4,7 @@ import (
"time"
"github.com/google/uuid"
"github.com/pocket-id/pocket-id/backend/internal/model/types"
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
"gorm.io/gorm"
)

View File

@@ -2,10 +2,11 @@ package service
import (
"errors"
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
"log"
"time"
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
"github.com/pocket-id/pocket-id/backend/internal/common"
"github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/model"

View File

@@ -105,9 +105,10 @@ func (s *CustomClaimService) updateCustomClaims(idType idType, value string, cla
Value: claim.Value,
}
if idType == UserID {
switch idType {
case UserID:
customClaim.UserID = &value
} else if idType == UserGroupID {
case UserGroupID:
customClaim.UserGroupID = &value
}

View File

@@ -319,7 +319,7 @@ func TestGenerateVerifyAccessToken(t *testing.T) {
assert.False(t, isAdmin, "isAdmin should be false")
audience, ok := claims.Audience()
_ = assert.True(t, ok, "Audience not found in token") &&
assert.EqualValues(t, []string{"https://test.example.com"}, audience, "Audience should contain the app URL")
assert.Equal(t, []string{"https://test.example.com"}, audience, "Audience should contain the app URL")
// Check token expiration time is approximately 1 hour from now
expectedExp := time.Now().Add(1 * time.Hour)
@@ -606,7 +606,7 @@ func TestGenerateVerifyIdToken(t *testing.T) {
assert.Equal(t, "user123", subject, "Token subject should match user ID")
audience, ok := claims.Audience()
_ = assert.True(t, ok, "Audience not found in token") &&
assert.EqualValues(t, []string{clientID}, audience, "Audience should contain the client ID")
assert.Equal(t, []string{clientID}, audience, "Audience should contain the client ID")
issuer, ok := claims.Issuer()
_ = assert.True(t, ok, "Issuer not found in token") &&
assert.Equal(t, common.EnvConfig.AppURL, issuer, "Issuer should match app URL")
@@ -935,7 +935,7 @@ func TestGenerateVerifyOauthAccessToken(t *testing.T) {
assert.Equal(t, user.ID, subject, "Token subject should match user ID")
audience, ok := claims.Audience()
_ = assert.True(t, ok, "Audience not found in token") &&
assert.EqualValues(t, []string{clientID}, audience, "Audience should contain the client ID")
assert.Equal(t, []string{clientID}, audience, "Audience should contain the client ID")
issuer, ok := claims.Issuer()
_ = assert.True(t, ok, "Issuer not found in token") &&
assert.Equal(t, common.EnvConfig.AppURL, issuer, "Issuer should match app URL")
@@ -1050,7 +1050,7 @@ func TestGenerateVerifyOauthAccessToken(t *testing.T) {
assert.Equal(t, user.ID, subject, "Token subject should match user ID")
audience, ok := claims.Audience()
_ = assert.True(t, ok, "Audience not found in token") &&
assert.EqualValues(t, []string{clientID}, audience, "Audience should contain the client ID")
assert.Equal(t, []string{clientID}, audience, "Audience should contain the client ID")
// Verify the key type is OKP
publicKey, err := service.GetPublicJWK()
@@ -1104,7 +1104,7 @@ func TestGenerateVerifyOauthAccessToken(t *testing.T) {
assert.Equal(t, user.ID, subject, "Token subject should match user ID")
audience, ok := claims.Audience()
_ = assert.True(t, ok, "Audience not found in token") &&
assert.EqualValues(t, []string{clientID}, audience, "Audience should contain the client ID")
assert.Equal(t, []string{clientID}, audience, "Audience should contain the client ID")
// Verify the key type is EC
publicKey, err := service.GetPublicJWK()
@@ -1158,7 +1158,7 @@ func TestGenerateVerifyOauthAccessToken(t *testing.T) {
assert.Equal(t, user.ID, subject, "Token subject should match user ID")
audience, ok := claims.Audience()
_ = assert.True(t, ok, "Audience not found in token") &&
assert.EqualValues(t, []string{clientID}, audience, "Audience should contain the client ID")
assert.Equal(t, []string{clientID}, audience, "Audience should contain the client ID")
// Verify the key type is RSA
publicKey, err := service.GetPublicJWK()

View File

@@ -53,7 +53,7 @@ func TestGetAuthenticatorName(t *testing.T) {
// Inject a test AAGUID map
aaguidMap = map[string]string{
"adce0002-35bc-c60a-648b-m0b25f1f05503": "Test Authenticator",
"adce0002-35bc-c60a-648b-0b25f1f05503": "Test Authenticator",
"00000000-0000-0000-0000-000000000000": "Zero Authenticator",
}
aaguidMapOnce = sync.Once{}

View File

@@ -171,14 +171,12 @@ func (c *Composer) String() string {
func convertRunes(str string) []string {
var enc = make([]string, 0, len(str))
for _, r := range str {
if r == ' ' {
switch {
case r == ' ':
enc = append(enc, "_")
} else if isPrintableASCIIRune(r) &&
r != '=' &&
r != '?' &&
r != '_' {
case isPrintableASCIIRune(r) && r != '=' && r != '?' && r != '_':
enc = append(enc, string(r))
} else {
default:
enc = append(enc, string(toHex([]byte(string(r)))))
}
}