Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/golangci-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: golangci-lint

on:
pull_request:

permissions:
contents: read

jobs:
golangci-lint:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'

- name: Install Ginkgo
run: go install github.com/onsi/ginkgo/v2/ginkgo

- name: Install Mockery
run: go install github.com/vektra/mockery/v2@v2.53.5

- name: Install golangci-lint
run: make install-golangci-lint

- name: Generate Mockery code
run: make mockery

- name: Generate Gqlgen code
run: make gqlgen

- name: Run golangci-lint
run: make lint
15 changes: 15 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "2"
run:
modules-download-mode: readonly
allow-parallel-runners: true
linters:
disable-all: true
enable:
- govet
- staticcheck
- gocritic
- gosec
- errcheck
- unused
- unconvert
- goconst
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ARCH := $(shell go env GOARCH)
SHELL=/bin/bash
MIGRATIONS_DIR=internal/database/mariadb/migrations/

.PHONY: all test doc gqlgen mockery test-all test-e2e test-app test-db fmt compose-prepare compose-up compose-down compose-restart compose-build check-call-cached check-migration-files
.PHONY: all test doc gqlgen mockery test-all test-e2e test-app test-db fmt lint compose-prepare compose-up compose-down compose-restart compose-build check-call-cached check-migration-files

# Source the .env file to use the env vars with make
-include .env
Expand Down Expand Up @@ -102,6 +102,12 @@ install-gofumpt:
fmt:
gofumpt -l -w .

install-golangci-lint:
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0

lint:
golangci-lint run
Comment on lines +108 to +109
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title/description indicates only adding golangci-lint in CI, but the diff includes substantial functional changes (OpenFGA authz event handlers, pagination/cursor refactors, GraphQL schema removals/additions, rate limiting, removal of Activity/Evidence APIs). Either the PR description/title should be updated to reflect the real scope, or the extra changes should be split into separate PRs for reviewability and safer rollout.

Copilot uses AI. Check for mistakes.

DOCKER_COMPOSE := docker-compose -f docker-compose.yaml
DOCKER_COMPOSE_SERVICES := heureka-app heureka-db valkey
compose-prepare:
Expand Down
6 changes: 2 additions & 4 deletions cmd/heureka/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ import (
"github.com/sirupsen/logrus"
)

var mode string

func main() {
fmt.Println(util.HeurekaFiglet)
fmt.Print(util.HeurekaFiglet)
var cfg util.Config
log.InitLog()

err := envconfig.Process("heureka", &cfg)
if err != nil {
logrus.WithField("error", err).Fatal("Error while reading env config %s", "test")
logrus.WithField("error", err).Fatal(fmt.Sprintf("Error while reading env config %s", "test"))
return
}
cfg.ConfigToConsole()
Expand Down
6 changes: 1 addition & 5 deletions internal/api/graphql/access/auth/noauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import (
"github.com/sirupsen/logrus"
)

const (
noAuthMethodName string = "NoAuthMethod"
)

type NoAuthMethod struct {
logger *logrus.Logger
authMethodName string
Expand All @@ -25,5 +21,5 @@ func NewNoAuthMethod(l *logrus.Logger, authMethodName string, msg string) authMe
}

func (nam NoAuthMethod) Verify(*gin.Context) error {
return verifyError(nam.authMethodName, fmt.Errorf("Auth failed: %s", nam.msg))
return verifyError(nam.authMethodName, fmt.Errorf("auth failed: %s", nam.msg))
}
2 changes: 1 addition & 1 deletion internal/api/graphql/access/auth/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (oam OidcAuthMethod) Verify(c *gin.Context) error {
var claims IDTokenClaims
err = token.Claims(&claims)
if err != nil {
return verifyError(oidcAuthMethodName, fmt.Errorf("Failed to parse token claims: %w", err))
return verifyError(oidcAuthMethodName, fmt.Errorf("failed to parse token claims: %w", err))
}

authctx.UserNameToContext(c, claims.Sub)
Expand Down
12 changes: 6 additions & 6 deletions internal/api/graphql/access/auth/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (tam TokenAuthMethod) Verify(c *gin.Context) error {
return err
}

authctx.UserNameToContext(c, claims.RegisteredClaims.Subject)
authctx.UserNameToContext(c, claims.Subject)

return nil
}
Expand All @@ -59,10 +59,10 @@ func (tam TokenAuthMethod) parseTokenWithClaims(tokenString string) (*TokenClaim
token, err := jwt.ParseWithClaims(tokenString, claims, tam.parse)
if err != nil {
tam.logger.Error("JWT parsing error: ", err)
err = verifyError(tokenAuthMethodName, fmt.Errorf("Token parsing error"))
err = verifyError(tokenAuthMethodName, fmt.Errorf("token parsing error"))
} else if !token.Valid {
tam.logger.Error("Invalid token")
err = verifyError(tokenAuthMethodName, fmt.Errorf("Invalid token"))
err = verifyError(tokenAuthMethodName, fmt.Errorf("invalid token"))
}
return claims, err
}
Expand All @@ -71,17 +71,17 @@ func (tam TokenAuthMethod) verifyTokenExpiration(tc *TokenClaims) error {
var err error
if tc.ExpiresAt == nil {
tam.logger.Error("Missing ExpiresAt in token claims")
err = verifyError(tokenAuthMethodName, fmt.Errorf("Missing ExpiresAt in token claims"))
err = verifyError(tokenAuthMethodName, fmt.Errorf("missing ExpiresAt in token claims"))
} else if tc.ExpiresAt.Before(time.Now()) {
tam.logger.Warn("Expired token")
err = verifyError(tokenAuthMethodName, fmt.Errorf("Expired token"))
err = verifyError(tokenAuthMethodName, fmt.Errorf("expired token"))
}
return err
}

func (tam *TokenAuthMethod) parse(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Invalid JWT parse method")
return nil, fmt.Errorf("invalid JWT parse method")
}
return tam.secret, nil
}
4 changes: 2 additions & 2 deletions internal/api/graphql/access/auth/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ func verifyError(methodName string, e error) error {
func getAuthTokenFromHeader(header string, c *gin.Context) (string, error) {
authHeader := c.GetHeader(header)
if authHeader == "" {
return "", fmt.Errorf("No authorization header")
return "", fmt.Errorf("no authorization header")
}
if len(authHeader) < (len("Bearer ")+1) || !strings.Contains(authHeader, "Bearer ") {
return "", fmt.Errorf("Invalid authorization header")
return "", fmt.Errorf("invalid authorization header")
}
return strings.Split(authHeader, "Bearer ")[1], nil
}
Expand Down
14 changes: 9 additions & 5 deletions internal/api/graphql/access/middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package middleware

import (
"fmt"
"io/ioutil"
"io"
"net/http"
"reflect"

Expand All @@ -14,6 +14,8 @@ import (

"github.com/cloudoperators/heureka/internal/util"

// nolint due to importing all functions from auth package
//nolint: staticcheck
. "github.com/cloudoperators/heureka/internal/api/graphql/access/auth"
authctx "github.com/cloudoperators/heureka/internal/api/graphql/access/context"
)
Expand Down Expand Up @@ -57,20 +59,22 @@ func (a *Auth) Middleware() gin.HandlerFunc {
return
}
authCtx.Next()
return
}
}

func (a *Auth) appendInstance(am authMethod) {
if am != nil && !(reflect.ValueOf(am).Kind() == reflect.Ptr && reflect.ValueOf(am).IsNil()) {
a.chain = append(a.chain, am)
if am != nil {
v := reflect.ValueOf(am)
if v.Kind() != reflect.Ptr || !v.IsNil() {
a.chain = append(a.chain, am)
}
}
}

func newLogger(enableLog bool) *logrus.Logger {
l := logrus.New()
if !enableLog {
l.SetOutput(ioutil.Discard)
l.SetOutput(io.Discard)
}
return l
}
6 changes: 4 additions & 2 deletions internal/api/graphql/access/test/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package test
import (
"context"
"fmt"
"io/ioutil"
"io"
"net/http"
"time"

Expand Down Expand Up @@ -36,7 +36,7 @@ func NewTestServer(auth *middleware.Auth, enableLog bool) *TestServer {
port := util2.GetRandomFreePort()
log := logrus.New()
if !enableLog {
log.SetOutput(ioutil.Discard)
log.SetOutput(io.Discard)
}
return &TestServer{
port: port,
Expand All @@ -57,6 +57,8 @@ func (ts *TestServer) StartInBackground() {

ts.ctx, ts.cancel = context.WithCancel(context.Background())

// nolint due to unset values for timeouts
//nolint:gosec
ts.srv = &http.Server{Addr: fmt.Sprintf(":%s", ts.port), Handler: r}
util2.FirstListenThenServe(ts.srv, ts.log)
}
Expand Down
6 changes: 4 additions & 2 deletions internal/api/graphql/access/test/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

"github.com/golang-jwt/jwt/v5"

// nolint due to importing all functions from gomega package
//nolint: staticcheck
. "github.com/onsi/gomega"
)

Expand Down Expand Up @@ -44,15 +46,15 @@ func unmarshalResponseData(resp *http.Response, respData interface{}) {

func ExpectErrorMessage(resp *http.Response, expectedMsg string) {
var respData struct {
Error string `json:"error" required:true`
Error string `json:"error"`
}
unmarshalResponseData(resp, &respData)
Expect(respData.Error).To(Equal(expectedMsg))
}

func ExpectRegexErrorMessage(resp *http.Response, expectedRegexMsg string, args ...interface{}) {
var respData struct {
Error string `json:"error" required:true`
Error string `json:"error"`
}
unmarshalResponseData(resp, &respData)
Expect(respData.Error).Should(MatchRegexp(expectedRegexMsg, args...))
Expand Down
5 changes: 2 additions & 3 deletions internal/api/graphql/graph/baseResolver/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func SingleComponentBaseResolver(app app.Heureka, ctx context.Context, parent *m
return nil, nil
}

var cr entity.ComponentResult = components.Elements[0]
cr := components.Elements[0]
component := model.NewComponent(cr.Component)

return &component, nil
Expand Down Expand Up @@ -158,8 +158,7 @@ func ComponentIssueCountsBaseResolver(app app.Heureka, ctx context.Context, filt
}
}

switch parent.ParentName {
case model.ImageNodeName:
if parent.ParentName == model.ImageNodeName {
componentId = []*int64{pid}
}
}
Expand Down
15 changes: 8 additions & 7 deletions internal/api/graphql/graph/baseResolver/component_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package baseResolver

import (
"context"
"fmt"

"github.com/cloudoperators/heureka/internal/api/graphql/graph/model"
"github.com/cloudoperators/heureka/internal/app"
Expand All @@ -13,7 +14,7 @@ import (
"github.com/cloudoperators/heureka/internal/util"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr"
)

func SingleComponentInstanceBaseResolver(app app.Heureka, ctx context.Context, parent *model.NodeParent) (*model.ComponentInstance, error) {
Expand Down Expand Up @@ -48,7 +49,7 @@ func SingleComponentInstanceBaseResolver(app app.Heureka, ctx context.Context, p
return nil, nil
}

var cir entity.ComponentInstanceResult = componentInstances.Elements[0]
cir := componentInstances.Elements[0]
componentInstance := model.NewComponentInstance(cir.ComponentInstance)

return &componentInstance, nil
Expand Down Expand Up @@ -101,7 +102,7 @@ func ComponentInstanceBaseResolver(app app.Heureka, ctx context.Context, filter
Project: filter.Project,
Pod: filter.Pod,
Container: filter.Container,
Type: lo.Map(filter.Type, func(item *model.ComponentInstanceTypes, _ int) *string { return pointer.String(item.String()) }),
Type: lo.Map(filter.Type, func(item *model.ComponentInstanceTypes, _ int) *string { return ptr.To(item.String()) }),
IssueMatchId: imId,
ServiceId: serviceId,
ServiceCcrn: filter.ServiceCcrn,
Expand Down Expand Up @@ -190,7 +191,7 @@ func ContextBaseResolver(app app.Heureka, ctx context.Context, filter *model.Com
requestedFields := GetPreloads(ctx)
logrus.WithFields(logrus.Fields{
"requestedFields": requestedFields,
}).Debug("Called ComponentInstanceFilterBaseResolver (%s)", filter)
}).Debug(fmt.Sprintf("Called ComponentInstanceFilterBaseResolver (%v)", filter))

if filter == nil {
filter = &model.ComponentInstanceFilter{}
Expand All @@ -210,7 +211,7 @@ func ContextBaseResolver(app app.Heureka, ctx context.Context, filter *model.Com
Project: filter.Project,
Pod: filter.Pod,
Container: filter.Container,
Type: lo.Map(filter.Type, func(item *model.ComponentInstanceTypes, _ int) *string { return pointer.String(item.String()) }),
Type: lo.Map(filter.Type, func(item *model.ComponentInstanceTypes, _ int) *string { return ptr.To(item.String()) }),
Context: contextFilters,
Search: filter.Search,
State: model.GetStateFilterType(filter.State),
Expand Down Expand Up @@ -246,7 +247,7 @@ func ComponentInstanceFilterBaseResolver(
requestedFields := GetPreloads(ctx)
logrus.WithFields(logrus.Fields{
"requestedFields": requestedFields,
}).Debug("Called ComponentInstanceFilterBaseResolver (%s)", filterDisplay)
}).Debug(fmt.Sprintf("Called ComponentInstanceFilterBaseResolver (%v)", filterDisplay))

if filter == nil {
filter = &model.ComponentInstanceFilter{}
Expand All @@ -261,7 +262,7 @@ func ComponentInstanceFilterBaseResolver(
Project: filter.Project,
Pod: filter.Pod,
Container: filter.Container,
Type: lo.Map(filter.Type, func(item *model.ComponentInstanceTypes, _ int) *string { return pointer.String(item.String()) }),
Type: lo.Map(filter.Type, func(item *model.ComponentInstanceTypes, _ int) *string { return ptr.To(item.String()) }),
Search: filter.Search,
State: model.GetStateFilterType(filter.State),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func SingleComponentVersionBaseResolver(app app.Heureka, ctx context.Context, pa
return nil, nil
}

var cvr entity.ComponentVersionResult = componentVersions.Elements[0]
cvr := componentVersions.Elements[0]
componentVersion := model.NewComponentVersion(cvr.ComponentVersion)

return &componentVersion, nil
Expand Down Expand Up @@ -126,7 +126,7 @@ func ComponentVersionBaseResolver(app app.Heureka, ctx context.Context, filter *
}

componentVersions, err := app.ListComponentVersions(f, opt)
//@todo propper error handling
// @todo propper error handling
if err != nil {
return nil, NewResolverError("ComponentVersionBaseResolver", err.Error())
}
Expand Down
Loading
Loading