Skip to content
Merged
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
68 changes: 45 additions & 23 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
# SPDX-License-Identifier: MIT
version: "2"
linters:
disable-all: true
fast: false
default: none
enable:
- gci
- goconst
- gocritic
- gocyclo
- gofmt
- gofumpt
- goimports
- godox
- govet
- gosec
- gosimple
- govet
- importas
- ineffassign
- loggercheck
Expand All @@ -28,17 +22,45 @@ linters:
- unused
- wastedassign
- whitespace

linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/cloudbase/garm)

goimports:
local-prefixes: github.com/cloudbase/garm

gosec:
excludes:
- G115
settings:
gosec:
excludes:
- G101
- G115
- G117
revive:
rules:
- name: var-naming
disabled: true
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
settings:
gci:
sections:
- standard
- default
- prefix(github.com/cloudbase/garm)
goimports:
local-prefixes:
- github.com/cloudbase/garm
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ $(LOCALBIN):
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint

## Tool Versions
GOLANGCI_LINT_VERSION ?= v1.64.8
GOLANGCI_LINT_VERSION ?= v2.10.1

.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. If wrong version is installed, it will be overwritten.
$(GOLANGCI_LINT): $(LOCALBIN)
test -s $(LOCALBIN)/golangci-lint && $(LOCALBIN)/golangci-lint --version | grep -q $(GOLANGCI_LINT_VERSION) || \
GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
2 changes: 1 addition & 1 deletion apiserver/controllers/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func (a *APIController) WSHandler(writer http.ResponseWriter, req *http.Request)
return
}
<-client.Done()
slog.Info("client disconnected", "client_id", client.ID())
slog.Info("client disconnected", "client_id", client.ID()) //nolint:gosec // G706 - structured logging with typed field
}

// NotFoundHandler is returned when an invalid URL is acccessed
Expand Down
10 changes: 5 additions & 5 deletions apiserver/controllers/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func (a *APIController) InstanceGithubRegistrationTokenHandler(w http.ResponseWr

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(token)); err != nil {
if _, err := w.Write([]byte(token)); err != nil { //nolint:gosec // G705 - server-generated token, not user input
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
Expand Down Expand Up @@ -245,7 +245,7 @@ func (a *APIController) JITCredentialsFileHandler(w http.ResponseWriter, r *http
w.Header().Set("Content-Type", "octet-stream")
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data)))
w.WriteHeader(http.StatusOK)
if _, err := w.Write(data); err != nil {
if _, err := w.Write(data); err != nil { //nolint:gosec // G705 - server-generated data, not user input
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
Expand All @@ -261,7 +261,7 @@ func (a *APIController) SystemdServiceNameHandler(w http.ResponseWriter, r *http

w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(serviceName)); err != nil {
if _, err := w.Write([]byte(serviceName)); err != nil { //nolint:gosec // G705 - server-generated data, not user input
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
Expand All @@ -278,7 +278,7 @@ func (a *APIController) SystemdUnitFileHandler(w http.ResponseWriter, r *http.Re

w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write(data); err != nil {
if _, err := w.Write(data); err != nil { //nolint:gosec // G705 - server-generated data, not user input
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
Expand Down Expand Up @@ -372,7 +372,7 @@ func (a *APIController) RunnerInstallScriptHandler(w http.ResponseWriter, r *htt

w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write(installScript); err != nil {
if _, err := w.Write(installScript); err != nil { //nolint:gosec // G705 - server-generated script, not user input
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
2 changes: 1 addition & 1 deletion apiserver/routers/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func requestLogger(h http.Handler) http.Handler {
// gathers metrics from the upstream handlers
metrics := httpsnoop.CaptureMetrics(h, w, r)

slog.Info(
slog.Info( //nolint:gosec // G706 - structured logging with typed fields
"access_log",
slog.String("method", r.Method),
slog.String("uri", r.URL.RequestURI()),
Expand Down
2 changes: 1 addition & 1 deletion cmd/garm-cli/cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (c *rawClient) NewRequest(method, path string, body io.Reader) (*http.Reque
return nil, fmt.Errorf("failed to join URL: %w", err)
}

req, err := http.NewRequest(method, url, body)
req, err := http.NewRequest(method, url, body) //nolint:gosec // G704 - URL is constructed from configured base URL
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion database/sql/file_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (s *sqlDatabase) CreateFileObject(ctx context.Context, param params.CreateF
}
defer func() {
tmpFile.Close()
os.Remove(tmpFile.Name())
os.Remove(tmpFile.Name()) //nolint:gosec // G703 - path from os.CreateTemp, not user input
}()
if _, err := io.Copy(tmpFile, reader); err != nil {
return params.FileObject{}, fmt.Errorf("failed to copy data: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion test/integration/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func getTestFileContents(relPath string) ([]byte, error) {
if baseDir == "" {
return nil, fmt.Errorf("variable GARM_CHECKOUT_DIR not set")
}
contents, err := os.ReadFile(filepath.Join(baseDir, "testdata", relPath))
contents, err := os.ReadFile(filepath.Join(baseDir, "testdata", relPath)) //nolint:gosec // G703 - test helper reading from known testdata dir
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion test/integration/list_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (suite *GarmSuite) appendCtrlInfoToGitHubEnv(controllerInfo *params.Control
t.Cleanup(func() {
file.Close()
})
if _, err := file.WriteString(fmt.Sprintf("export GARM_CONTROLLER_ID=%s\n", controllerInfo.ControllerID)); err != nil {
if _, err := fmt.Fprintf(file, "export GARM_CONTROLLER_ID=%s\n", controllerInfo.ControllerID); err != nil {
return err
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion util/github/scalesets/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (s *ScaleSetClient) Do(req *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("http client is not initialized")
}

resp, err := s.httpClient.Do(req)
resp, err := s.httpClient.Do(req) //nolint:gosec // G704 - URL is constructed from GitHub API endpoints
if err != nil {
return nil, fmt.Errorf("failed to dispatch HTTP request: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion util/github/scalesets/scalesets.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (s *ScaleSetClient) DeleteRunnerScaleSet(ctx context.Context, runnerScaleSe
}

client := &http.Client{}
resp, err := client.Do(req)
resp, err := client.Do(req) //nolint:gosec // G704 - URL is constructed from GitHub API endpoints
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion webapp/assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,5 @@ func ServeSPAWithPath(w http.ResponseWriter, r *http.Request, webappPath string)
w.Header().Set("Cache-Control", "no-cache, must-revalidate")
}

w.Write(content)
w.Write(content) //nolint:gosec // G705 - serving embedded static assets, not user input
}
12 changes: 6 additions & 6 deletions workers/provider/instance_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,12 @@ func (i *instanceManager) consolidateState() error {
switch i.instance.Status {
case commonParams.InstancePendingCreate:
// kick off the creation process
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceCreating, nil); err != nil {
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceCreating, nil, false); err != nil {
return fmt.Errorf("setting instance status to creating: %w", err)
}
if err := i.handleCreateInstanceInProvider(i.instance); err != nil {
slog.ErrorContext(i.ctx, "creating instance in provider", "error", err)
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceError, []byte(err.Error())); err != nil {
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceError, []byte(err.Error()), true); err != nil {
return fmt.Errorf("setting instance status to error: %w", err)
}
}
Expand All @@ -325,7 +325,7 @@ func (i *instanceManager) consolidateState() error {
}

prevStatus := i.instance.Status
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceDeleting, nil); err != nil {
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceDeleting, nil, true); err != nil {
if errors.Is(err, runnerErrors.ErrNotFound) {
return nil
}
Expand All @@ -336,14 +336,14 @@ func (i *instanceManager) consolidateState() error {
slog.ErrorContext(i.ctx, "deleting instance in provider", "error", err, "forced", i.instance.Status == commonParams.InstancePendingForceDelete)
if prevStatus == commonParams.InstancePendingDelete {
i.incrementBackOff()
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstancePendingDelete, []byte(err.Error())); err != nil {
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstancePendingDelete, []byte(err.Error()), true); err != nil {
return fmt.Errorf("setting instance status to error: %w", err)
}

return fmt.Errorf("error removing instance. Will retry: %w", err)
}
}
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceDeleted, nil); err != nil {
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstanceDeleted, nil, false); err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) {
return fmt.Errorf("setting instance status to deleted: %w", err)
}
Expand All @@ -352,7 +352,7 @@ func (i *instanceManager) consolidateState() error {
case commonParams.InstanceError:
// Instance is in error state. We wait for next status or potentially retry
// spawning the instance with a backoff timer.
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstancePendingDelete, nil); err != nil {
if err := i.helper.SetInstanceStatus(i.instance.Name, commonParams.InstancePendingDelete, nil, true); err != nil {
return fmt.Errorf("setting instance status to error: %w", err)
}
case commonParams.InstanceDeleted:
Expand Down
12 changes: 9 additions & 3 deletions workers/provider/provider_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

type providerHelper interface {
SetInstanceStatus(instanceName string, status commonParams.InstanceStatus, providerFault []byte) error
SetInstanceStatus(instanceName string, status commonParams.InstanceStatus, providerFault []byte, force bool) error
InstanceTokenGetter() auth.InstanceTokenGetter
updateArgsFromProviderInstance(instanceName string, providerInstance commonParams.ProviderInstance) (params.Instance, error)
GetControllerInfo() (params.ControllerInfo, error)
Expand Down Expand Up @@ -59,7 +59,7 @@ func (p *Provider) GetControllerInfo() (params.ControllerInfo, error) {
return info, nil
}

func (p *Provider) SetInstanceStatus(instanceName string, status commonParams.InstanceStatus, providerFault []byte) error {
func (p *Provider) SetInstanceStatus(instanceName string, status commonParams.InstanceStatus, providerFault []byte, force bool) error {
p.mux.Lock()
defer p.mux.Unlock()

Expand All @@ -72,7 +72,13 @@ func (p *Provider) SetInstanceStatus(instanceName string, status commonParams.In
ProviderFault: providerFault,
}

_, err := p.store.UpdateInstance(p.ctx, instanceName, updateParams)
var err error
switch force {
case true:
_, err = p.store.ForceUpdateInstance(p.ctx, instanceName, updateParams)
default:
_, err = p.store.UpdateInstance(p.ctx, instanceName, updateParams)
}
if err != nil {
return fmt.Errorf("updating instance %s: %w", instanceName, err)
}
Expand Down
Loading