diff --git a/.github/workflows/backend-linter.yml b/.github/workflows/backend-linter.yml new file mode 100644 index 00000000..4a458cbe --- /dev/null +++ b/.github/workflows/backend-linter.yml @@ -0,0 +1,36 @@ +name: Run Backend Linter + +on: + push: + branches: + - main + pull_request: + branches: + - main +permissions: + # Required: allow read access to the content for analysis. + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read + # Optional: allow write access to checks to allow the action to annotate code in the PR. + checks: write + +jobs: + golangci-lint: + name: Run Golangci-lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version-file: backend/go.mod + + - name: Run Golangci-lint + uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2 + with: + version: v1.64 + working-directory: backend + only-new-issues: ${{ github.event_name == 'pull_request' }} diff --git a/backend/.golangci.yml b/backend/.golangci.yml new file mode 100644 index 00000000..56603315 --- /dev/null +++ b/backend/.golangci.yml @@ -0,0 +1,21 @@ + +linters: + # Disable all linters. + # Default: false + disable-all: true + enable: + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - unused + - gosec + - gocognit + + presets: + - bugs + - sql +run: + timeout: "5m" + tests: true diff --git a/backend/internal/bootstrap/db_bootstrap.go b/backend/internal/bootstrap/db_bootstrap.go index 265c04ee..5fb588cf 100644 --- a/backend/internal/bootstrap/db_bootstrap.go +++ b/backend/internal/bootstrap/db_bootstrap.go @@ -56,17 +56,17 @@ func migrateDatabase(driver database.Driver) error { // Use the embedded migrations source, err := iofs.New(resources.FS, "migrations/"+string(common.EnvConfig.DbProvider)) if err != nil { - return fmt.Errorf("failed to create embedded migration source: %v", err) + return fmt.Errorf("failed to create embedded migration source: %w", err) } m, err := migrate.NewWithInstance("iofs", source, "pocket-id", driver) if err != nil { - return fmt.Errorf("failed to create migration instance: %v", err) + return fmt.Errorf("failed to create migration instance: %w", err) } err = m.Up() if err != nil && !errors.Is(err, migrate.ErrNoChange) { - return fmt.Errorf("failed to apply migrations: %v", err) + return fmt.Errorf("failed to apply migrations: %w", err) } return nil diff --git a/backend/internal/service/geolite_service.go b/backend/internal/service/geolite_service.go index 6c280d29..18987ea9 100644 --- a/backend/internal/service/geolite_service.go +++ b/backend/internal/service/geolite_service.go @@ -124,7 +124,7 @@ func (s *GeoLiteService) updateDatabase() error { log.Println("Updating GeoLite2 City database...") downloadUrl := fmt.Sprintf(common.EnvConfig.GeoLiteDBUrl, common.EnvConfig.MaxMindLicenseKey) - // Download the database tar.gz file + // Download the database tar.gz file nolint:gosec resp, err := http.Get(downloadUrl) if err != nil { return fmt.Errorf("failed to download database: %w", err) diff --git a/backend/internal/service/ldap_service.go b/backend/internal/service/ldap_service.go index 20cd8a70..3c31b307 100644 --- a/backend/internal/service/ldap_service.go +++ b/backend/internal/service/ldap_service.go @@ -163,7 +163,7 @@ func (s *LdapService) SyncGroups() error { // Get all LDAP groups from the database var ldapGroupsInDb []model.UserGroup if err := s.db.Find(&ldapGroupsInDb, "ldap_id IS NOT NULL").Select("ldap_id").Error; err != nil { - fmt.Println(fmt.Errorf("failed to fetch groups from database: %v", err)) + fmt.Println(fmt.Errorf("failed to fetch groups from database: %w", err)) } // Delete groups that no longer exist in LDAP @@ -276,7 +276,7 @@ func (s *LdapService) SyncUsers() error { // Get all LDAP users from the database var ldapUsersInDb []model.User if err := s.db.Find(&ldapUsersInDb, "ldap_id IS NOT NULL").Select("ldap_id").Error; err != nil { - fmt.Println(fmt.Errorf("failed to fetch users from database: %v", err)) + fmt.Println(fmt.Errorf("failed to fetch users from database: %w", err)) } // Delete users that no longer exist in LDAP diff --git a/backend/internal/service/oidc_service.go b/backend/internal/service/oidc_service.go index 1e4a7adb..112f0e57 100644 --- a/backend/internal/service/oidc_service.go +++ b/backend/internal/service/oidc_service.go @@ -492,6 +492,7 @@ func (s *OidcService) GetUserClaimsForClient(userID string, clientID string) (ma for _, customClaim := range customClaims { // The value of the custom claim can be a JSON object or a string var jsonValue interface{} + //nolint:errcheck // Ignore error for JSON unmarshalling json.Unmarshal([]byte(customClaim.Value), &jsonValue) if jsonValue != nil { // It's JSON so we store it as an object diff --git a/backend/internal/service/user_service.go b/backend/internal/service/user_service.go index bdea1675..fd318891 100644 --- a/backend/internal/service/user_service.go +++ b/backend/internal/service/user_service.go @@ -244,7 +244,7 @@ func (s *UserService) CreateOneTimeAccessToken(userID string, expiresAt time.Tim tokenLength := 16 // If expires at is less than 15 minutes, use an 6 character token instead of 16 - if expiresAt.Sub(time.Now()) <= 15*time.Minute { + if time.Until(expiresAt) <= 15*time.Minute { tokenLength = 6 } diff --git a/backend/internal/utils/email/composer.go b/backend/internal/utils/email/composer.go index 9017ffa7..b85abbd4 100644 --- a/backend/internal/utils/email/composer.go +++ b/backend/internal/utils/email/composer.go @@ -170,7 +170,7 @@ func (c *Composer) String() string { func convertRunes(str string) []string { var enc = make([]string, 0, len(str)) - for _, r := range []rune(str) { + for _, r := range str { if r == ' ' { enc = append(enc, "_") } else if isPrintableASCIIRune(r) && @@ -204,7 +204,7 @@ func hex(n byte) byte { } func isPrintableASCII(str string) bool { - for _, r := range []rune(str) { + for _, r := range str { if !unicode.IsPrint(r) || r >= unicode.MaxASCII { return false }