diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..b2fdbb035 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + open-pull-requests-limit: 5 + groups: + Github Actions updates: + applies-to: version-updates + dependency-type: production + schedule: + # Check for updates to GitHub Actions every week + day: "monday" + time: "09:00" + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e41c4052..8f642c9d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,11 +37,11 @@ jobs: - name: Lint & test webapp run: cd focalboard; make webapp-ci - - name: set up golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.8 - - - name: Lint & test server - run: cd focalboard; make server-ci + - name: Run golangci-lint + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 + with: + version: v2.8.0 + working-directory: focalboard/server dist: uses: mattermost/actions-workflows/.github/workflows/plugin-dist-pr.yml@main diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b4b6b78c3..1431b8464 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,7 +30,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3.28.9 + uses: github/codeql-action/init@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 with: languages: ${{ matrix.language }} debug: false @@ -38,8 +38,8 @@ jobs: # Autobuild attempts to build any compiled languages - name: Autobuild - uses: github/codeql-action/autobuild@v3.28.9 + uses: github/codeql-action/autobuild@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 # Perform Analysis - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3.28.9 \ No newline at end of file + uses: github/codeql-action/analyze@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 \ No newline at end of file diff --git a/.github/workflows/lint-server.yml b/.github/workflows/lint-server.yml index e0019ea52..03f4a5b29 100644 --- a/.github/workflows/lint-server.yml +++ b/.github/workflows/lint-server.yml @@ -34,9 +34,9 @@ jobs: - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: go-version-file: focalboard/go.mod - - name: set up golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.8 - - name: lint - run: | - cd focalboard - make server-lint + + - name: Run golangci-lint + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 + with: + version: v2.8.0 + working-directory: focalboard/server diff --git a/server/.golangci.yml b/server/.golangci.yml index d8bc3347e..6f8b50b7d 100644 --- a/server/.golangci.yml +++ b/server/.golangci.yml @@ -1,80 +1,111 @@ +version: "2" run: - timeout: 5m modules-download-mode: readonly - -linters-settings: - gofmt: - simplify: true - goimports: - local-prefixes: github.com/mattermost/mattermost-starter-template - golint: - min-confidence: 0 - govet: - enable-all: true - disable: - - fieldalignment - misspell: - locale: US - lll: - line-length: 150 - revive: - enableAllRules: true - rules: - - name: exported - disabled: true - linters: - disable-all: true - settings: - govet: - enable: - - shadow + default: none enable: - - gofmt - - goimports - - ineffassign - - unparam - - govet + - asciicheck - bodyclose + - copyloopvar + - dogsled - durationcheck + - err113 - errorlint - exhaustive - - copyloopvar - - gosec - - makezero - - staticcheck - - prealloc - - asciicheck - - dogsled - gocritic + - gocyclo - godot - - err113 - goheader - - revive - - nakedret - gomodguard - goprintffuncname - - gosimple + - gosec + - govet + - ineffassign + - makezero - misspell + - nakedret - nolintlint - - typecheck + - prealloc + - revive + - staticcheck - unconvert + - unparam - unused - whitespace - - gocyclo - -issues: - exclude-files: - - product/boards_product.go - - services/store/sqlstore/migrations - exclude-rules: - - path: server/manifest.go - linters: - - unused - - path: server/configuration.go - linters: - - unused - - path: _test\.go - linters: - - bodyclose - - scopelint # https://github.com/kyoh86/scopelint/issues/4 + settings: + govet: + disable: + - fieldalignment + enable-all: true + lll: + line-length: 150 + misspell: + locale: US + revive: + rules: + - name: exported + disabled: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - unused + path: server/manifest.go + - linters: + - unused + path: server/configuration.go + - linters: + - bodyclose + path: _test\.go + # QF1008 - ignoring for now and must be revisited after bumping lint version. + - linters: + - staticcheck + text: QF1008 + path: app/category_boards.go + - linters: + - staticcheck + text: QF1008 + path: plugin.go + - linters: + - staticcheck + text: QF1008 + path: services/metrics/service.go + - linters: + - staticcheck + text: QF1008 + path: web/webserver.go + # QF1003: this file is using boardTypes undefined in the models - must be revisited after bumping lint version. + - linters: + - staticcheck + text: QF1003 + path: store/sqlstore/data_migrations.go + paths: + - product/boards_product.go + - services/store/sqlstore/migrations + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + settings: + gofmt: + simplify: true + goimports: + local-prefixes: + # todo: update to the correct module name after bumping lint version. + - github.com/mattermost/mattermost-starter-template + exclusions: + generated: lax + paths: + - product/boards_product.go + - services/store/sqlstore/migrations + - third_party$ + - builtin$ + - examples$ diff --git a/server/api/members.go b/server/api/members.go index da30034b2..ebd163573 100644 --- a/server/api/members.go +++ b/server/api/members.go @@ -131,7 +131,7 @@ func (a *API) handleAddMember(w http.ResponseWriter, r *http.Request) { } if !a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionManageBoardRoles) && - !(board.Type == model.BoardTypeOpen && a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionManageBoardProperties)) { + (board.Type != model.BoardTypeOpen || !a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionManageBoardProperties)) { a.errorResponse(w, r, model.NewErrPermission("access denied to modify board members")) return } diff --git a/server/app/boards.go b/server/app/boards.go index f8904a2cf..2c9704dec 100644 --- a/server/app/boards.go +++ b/server/app/boards.go @@ -431,9 +431,10 @@ func (a *App) broadcastTeamUsers(teamID, boardID string, boardType model.BoardTy } } if !isMember { - if boardType == model.BoardTypePrivate { + switch boardType { + case model.BoardTypePrivate: a.wsAdapter.BroadcastMemberDelete(teamID, boardID, user.ID) - } else if boardType == model.BoardTypeOpen { + case model.BoardTypeOpen: a.wsAdapter.BroadcastMemberChange(teamID, boardID, &model.BoardMember{UserID: user.ID, BoardID: boardID, SchemeViewer: true, Synthetic: true}) } } diff --git a/server/boards/boardsapp_util.go b/server/boards/boardsapp_util.go index ba22451c4..10a432306 100644 --- a/server/boards/boardsapp_util.go +++ b/server/boards/boardsapp_util.go @@ -58,14 +58,11 @@ func createBoardsConfig(mmconfig mm_model.Config, baseURL string, serverID strin enableTelemetry = *mmconfig.LogSettings.EnableDiagnostics } - enablePublicSharedBoards := false - if mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true { - enablePublicSharedBoards = true - } + enablePublicSharedBoards := mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true enableBoardsDeletion := false if mmconfig.DataRetentionSettings.EnableBoardsDeletion != nil { - enableBoardsDeletion = true + enableBoardsDeletion = *mmconfig.DataRetentionSettings.EnableBoardsDeletion } featureFlags := parseFeatureFlags(mmconfig.FeatureFlags.ToMap()) diff --git a/server/boards/configuration.go b/server/boards/configuration.go index 30134bdbe..5fd8cbe15 100644 --- a/server/boards/configuration.go +++ b/server/boards/configuration.go @@ -78,10 +78,7 @@ func (b *BoardsApp) OnConfigurationChange() error { } mmconfig := b.servicesAPI.GetConfig() - enableShareBoards := false - if mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true { - enableShareBoards = true - } + enableShareBoards := mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true configuration := &configuration{ EnablePublicSharedBoards: enableShareBoards, @@ -90,10 +87,8 @@ func (b *BoardsApp) OnConfigurationChange() error { b.server.Config().EnablePublicSharedBoards = enableShareBoards // handle Data Retention settings - enableBoardsDeletion := false - if mmconfig.DataRetentionSettings.EnableBoardsDeletion != nil { - enableBoardsDeletion = true - } + enableBoardsDeletion := mmconfig.DataRetentionSettings.EnableBoardsDeletion != nil + b.server.Config().EnableDataRetention = enableBoardsDeletion b.server.Config().DataRetentionDays = *mmconfig.DataRetentionSettings.BoardsRetentionDays b.server.Config().TeammateNameDisplay = *mmconfig.TeamSettings.TeammateNameDisplay diff --git a/server/integrationtests/board_test.go b/server/integrationtests/board_test.go index 3fa17b6e1..88a0f1109 100644 --- a/server/integrationtests/board_test.go +++ b/server/integrationtests/board_test.go @@ -572,7 +572,7 @@ func TestSearchBoards(t *testing.T) { boards, resp := tc.Client.SearchBoardsForTeam(teamID, tc.Term) th.CheckOK(resp) - boardIDs := []string{} + boardIDs := make([]string, 0, len(boards)) for _, board := range boards { boardIDs = append(boardIDs, board.ID) } @@ -2065,7 +2065,7 @@ func TestDuplicateBoard(t *testing.T) { for _, categoryBoard := range userCategoryBoards { for _, boardMetadata := range categoryBoard.BoardMetadata { if boardMetadata.BoardID == duplicateBoard.ID { - duplicateBoardCategoryID = categoryBoard.Category.ID + duplicateBoardCategoryID = categoryBoard.ID } } } diff --git a/server/integrationtests/pluginteststore.go b/server/integrationtests/pluginteststore.go index 1490b594c..506cb0483 100644 --- a/server/integrationtests/pluginteststore.go +++ b/server/integrationtests/pluginteststore.go @@ -185,8 +185,8 @@ func (s *PluginTestStore) GetUsersByTeam(teamID string, asGuestID string, showEm }, nil } - switch { - case teamID == s.testTeam.ID: + switch teamID { + case s.testTeam.ID: return []*model.User{ s.users["team-member"], s.users["viewer"], @@ -195,7 +195,7 @@ func (s *PluginTestStore) GetUsersByTeam(teamID string, asGuestID string, showEm s.users["admin"], s.users["guest"], }, nil - case teamID == s.otherTeam.ID: + case s.otherTeam.ID: return []*model.User{ s.users["team-member"], s.users["viewer"], @@ -203,7 +203,7 @@ func (s *PluginTestStore) GetUsersByTeam(teamID string, asGuestID string, showEm s.users["editor"], s.users["admin"], }, nil - case teamID == s.emptyTeam.ID: + case s.emptyTeam.ID: return []*model.User{}, nil } return nil, errTestStore @@ -275,22 +275,24 @@ func (s *PluginTestStore) SearchUserChannels(teamID, userID, query string) ([]*m } func (s *PluginTestStore) GetChannel(teamID, channel string) (*mmModel.Channel, error) { - if channel == "valid-channel-id" { + switch channel { + case "valid-channel-id": return &mmModel.Channel{ TeamId: teamID, Id: "valid-channel-id", DisplayName: "Valid Channel", Name: "valid-channel", }, nil - } else if channel == "valid-channel-id-2" { + case "valid-channel-id-2": return &mmModel.Channel{ TeamId: teamID, Id: "valid-channel-id-2", DisplayName: "Valid Channel 2", Name: "valid-channel-2", }, nil + default: + return nil, errTestStore } - return nil, errTestStore } func (s *PluginTestStore) SearchBoardsForUser(term string, field model.BoardSearchField, userID string, includePublicBoards bool) ([]*model.Board, error) { diff --git a/server/model/properties_test.go b/server/model/properties_test.go index eb8d7f880..12e0f6e0a 100644 --- a/server/model/properties_test.go +++ b/server/model/properties_test.go @@ -15,19 +15,20 @@ import ( type MockResolver struct{} func (r MockResolver) GetUserByID(userID string) (*User, error) { - if userID == "user_id_1" { + switch userID { + case "user_id_1": return &User{ ID: "user_id_1", Username: "username_1", }, nil - } else if userID == "user_id_2" { + case "user_id_2": return &User{ ID: "user_id_2", Username: "username_2", }, nil + default: + return nil, nil } - - return nil, nil } func Test_parsePropertySchema(t *testing.T) { diff --git a/server/model/team.go b/server/model/team.go index e278dae5a..cf6a9460e 100644 --- a/server/model/team.go +++ b/server/model/team.go @@ -54,7 +54,7 @@ func TeamsFromJSON(data io.Reader) []*Team { func ValidateTeamID(teamID string, isTemplate bool) error { // Validate inputs to ensure proper file path handling // Only allow GlobalTeamID for template operations to prevent path traversal attacks - if !mm_model.IsValidId(teamID) && !(isTemplate && teamID == GlobalTeamID) { + if !mm_model.IsValidId(teamID) && (!isTemplate || teamID != GlobalTeamID) { return fmt.Errorf("invalid teamID in ValidateTeamID: %s", teamID) //nolint:err113 } return nil diff --git a/server/services/store/sqlstore/data_migrations.go b/server/services/store/sqlstore/data_migrations.go index 1a587a71b..875aa5100 100644 --- a/server/services/store/sqlstore/data_migrations.go +++ b/server/services/store/sqlstore/data_migrations.go @@ -826,9 +826,10 @@ func (s *SQLStore) RunDeDuplicateCategoryBoardsMigration(currentMigration int) e } } - if s.dbType == model.MysqlDBType { + switch s.dbType { + case model.MysqlDBType: return s.runMySQLDeDuplicateCategoryBoardsMigration() - } else if s.dbType == model.PostgresDBType { + case model.PostgresDBType: return s.runPostgresDeDuplicateCategoryBoardsMigration() } diff --git a/server/services/store/sqlstore/data_migrations_test.go b/server/services/store/sqlstore/data_migrations_test.go index 09a029ea8..2bf126b61 100644 --- a/server/services/store/sqlstore/data_migrations_test.go +++ b/server/services/store/sqlstore/data_migrations_test.go @@ -60,7 +60,7 @@ func TestGetBlocksWithSameID(t *testing.T) { // we process the found blocks to remove extra information and be // able to compare both expected and found sets - foundBlocks := []*model.Block{} + foundBlocks := make([]*model.Block, 0, len(blocks)) for _, foundBlock := range blocks { foundBlocks = append(foundBlocks, &model.Block{ID: foundBlock.ID, BoardID: foundBlock.BoardID}) } diff --git a/server/services/store/storetests/boards.go b/server/services/store/storetests/boards.go index e41b6f102..513c689b9 100644 --- a/server/services/store/storetests/boards.go +++ b/server/services/store/storetests/boards.go @@ -942,7 +942,7 @@ func testSearchBoardsForUser(t *testing.T, store store.Store) { boards, err := store.SearchBoardsForUser(tc.Term, tc.SearchField, tc.UserID, tc.IncludePublic) require.NoError(t, err) - boardIDs := []string{} + boardIDs := make([]string, 0, len(boards)) for _, board := range boards { boardIDs = append(boardIDs, board.ID) } diff --git a/server/services/store/storetests/boards_and_blocks.go b/server/services/store/storetests/boards_and_blocks.go index 3e8834bc3..86fcedbb1 100644 --- a/server/services/store/storetests/boards_and_blocks.go +++ b/server/services/store/storetests/boards_and_blocks.go @@ -67,12 +67,12 @@ func testCreateBoardsAndBlocks(t *testing.T, store store.Store) { require.Len(t, bab.Boards, 3) require.Len(t, bab.Blocks, 2) - boardIDs := []string{} + boardIDs := make([]string, 0, len(bab.Boards)) for _, board := range bab.Boards { boardIDs = append(boardIDs, board.ID) } - blockIDs := []string{} + blockIDs := make([]string, 0, len(bab.Blocks)) for _, block := range bab.Blocks { blockIDs = append(blockIDs, block.ID) } @@ -101,12 +101,12 @@ func testCreateBoardsAndBlocks(t *testing.T, store store.Store) { require.Len(t, bab.Blocks, 2) require.Len(t, members, 3) - boardIDs := []string{} + boardIDs := make([]string, 0, len(bab.Boards)) for _, board := range bab.Boards { boardIDs = append(boardIDs, board.ID) } - blockIDs := []string{} + blockIDs := make([]string, 0, len(bab.Blocks)) for _, block := range bab.Blocks { blockIDs = append(blockIDs, block.ID) } @@ -114,7 +114,7 @@ func testCreateBoardsAndBlocks(t *testing.T, store store.Store) { require.ElementsMatch(t, []string{"board-id-4", "board-id-5", "board-id-6"}, boardIDs) require.ElementsMatch(t, []string{"block-id-3", "block-id-4"}, blockIDs) - memberBoardIDs := []string{} + memberBoardIDs := make([]string, 0, len(members)) for _, member := range members { require.Equal(t, userID, member.UserID) memberBoardIDs = append(memberBoardIDs, member.BoardID) diff --git a/server/services/store/storetests/compliance.go b/server/services/store/storetests/compliance.go index e8223117e..a76396c45 100644 --- a/server/services/store/storetests/compliance.go +++ b/server/services/store/storetests/compliance.go @@ -109,7 +109,7 @@ func testGetBoardsComplianceHistory(t *testing.T, store store.Store) { boardsTeam1 := createTestBoards(t, store, team1, testUserID, 11) boardsTeam2 := createTestBoards(t, store, team2, testUserID, 7) - boardsAdded := make([]*model.Board, 0) + boardsAdded := make([]*model.Board, 0, len(boardsTeam1)+len(boardsTeam2)) boardsAdded = append(boardsAdded, boardsTeam1...) boardsAdded = append(boardsAdded, boardsTeam2...) diff --git a/server/web/webserver_test.go b/server/web/webserver_test.go index bc4e2edb9..8e89943f7 100644 --- a/server/web/webserver_test.go +++ b/server/web/webserver_test.go @@ -93,9 +93,9 @@ func Test_NewServer(t *testing.T) { require.Equal(t, test.logger, ws.logger, "logger pointer does not match") if test.localOnly == true { - require.Equal(t, test.expectedServerAddr, ws.Server.Addr, "localhost address not as matching!") + require.Equal(t, test.expectedServerAddr, ws.Addr, "localhost address not as matching!") } else { - require.Equal(t, test.expectedServerAddr, ws.Server.Addr, "server address not matching!") + require.Equal(t, test.expectedServerAddr, ws.Addr, "server address not matching!") } }) }