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
17 changes: 17 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,20 @@ jobs:
run: make build-${{ matrix.image }}
working-directory: ./

go-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache: true
cache-dependency-path: go/go.sum
- name: golangci-lint
uses: golangci/golangci-lint-action@v8
with:
version: v2.1
working-directory: go
11 changes: 11 additions & 0 deletions go/.golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "2"

linters:
# Default set of linters.
# The value can be:
# - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
# - `all`: enables all linters by default.
# - `none`: disables all linters by default.
# - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
# Default: standard
default: standard
4 changes: 2 additions & 2 deletions go/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ CONTROLLER_TOOLS_VERSION ?= v0.17.1
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
GOLANGCI_LINT_VERSION ?= v1.63.4
GOLANGCI_LINT_VERSION ?= v2.4.0

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
Expand All @@ -157,7 +157,7 @@ $(ENVTEST): $(LOCALBIN)
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary
Expand Down
4 changes: 2 additions & 2 deletions go/cli/cmd/kagent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func main() {
invokeCmd.Flags().BoolVarP(&invokeCfg.Stream, "stream", "S", false, "Stream the response")
invokeCmd.Flags().StringVarP(&invokeCfg.File, "file", "f", "", "File to read the task from")
invokeCmd.Flags().StringVarP(&invokeCfg.URLOverride, "url-override", "u", "", "URL override")
invokeCmd.Flags().MarkHidden("url-override")
invokeCmd.Flags().MarkHidden("url-override") //nolint:errcheck

bugReportCmd := &cobra.Command{
Use: "bug-report",
Expand Down Expand Up @@ -123,7 +123,7 @@ func main() {
Long: `Get a kagent resource`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(os.Stderr, "No resource type provided\n\n")
cmd.Help()
cmd.Help() //nolint:errcheck
os.Exit(1)
},
}
Expand Down
6 changes: 3 additions & 3 deletions go/cli/internal/cli/const_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ func TestGetModelProvider(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.envVarValue == "" {
os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER)
os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER) //nolint:errcheck
} else {
os.Setenv(KAGENT_DEFAULT_MODEL_PROVIDER, tc.expectedHelmKey)
defer os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER)
os.Setenv(KAGENT_DEFAULT_MODEL_PROVIDER, tc.expectedHelmKey) //nolint:errcheck
defer os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER) //nolint:errcheck
}

result := GetModelProvider()
Expand Down
4 changes: 2 additions & 2 deletions go/cli/internal/cli/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func GetAgentCmd(cfg *config.Config, resourceName string) {
return
}
byt, _ := json.MarshalIndent(agent, "", " ")
fmt.Fprintln(os.Stdout, string(byt))
fmt.Fprintln(os.Stdout, string(byt)) //nolint:errcheck
}
}

Expand Down Expand Up @@ -70,7 +70,7 @@ func GetSessionCmd(cfg *config.Config, resourceName string) {
return
}
byt, _ := json.MarshalIndent(session, "", " ")
fmt.Fprintln(os.Stdout, string(byt))
fmt.Fprintln(os.Stdout, string(byt)) //nolint:errcheck
}
}

Expand Down
12 changes: 5 additions & 7 deletions go/cli/internal/cli/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ func InstallCmd(ctx context.Context, cfg *config.Config) *PortForward {

// split helmExtraArgs by "--set" to get additional values
extraValues := strings.Split(helmExtraArgs, "--set")
for _, hev := range extraValues {
values = append(values, hev)
}
values = append(values, extraValues...)

// spinner for installation progress
s := spinner.New(spinner.CharSets[35], 100*time.Millisecond)
Expand Down Expand Up @@ -119,7 +117,7 @@ func InstallCmd(ctx context.Context, cfg *config.Config) *PortForward {

// Stop the spinner completely before printing the success message
s.Stop()
fmt.Fprintln(os.Stdout, "kagent installed successfully")
fmt.Fprintln(os.Stdout, "kagent installed successfully") //nolint:errcheck

pf, err := NewPortForward(ctx, cfg)
if err != nil {
Expand All @@ -146,11 +144,11 @@ func deleteCRDs(ctx context.Context) error {
if out, err := deleteCmd.CombinedOutput(); err != nil {
if !strings.Contains(string(out), "not found") {
errMsg := fmt.Sprintf("Error deleting CRD %s: %s", crd, string(out))
fmt.Fprintln(os.Stderr, errMsg)
fmt.Fprintln(os.Stderr, errMsg) //nolint:errcheck
deleteErrors = append(deleteErrors, errMsg)
}
} else {
fmt.Fprintf(os.Stdout, "Successfully deleted CRD %s\n", crd)
fmt.Fprintf(os.Stdout, "Successfully deleted CRD %s\n", crd) //nolint:errcheck
}
}

Expand Down Expand Up @@ -216,5 +214,5 @@ func UninstallCmd(ctx context.Context, cfg *config.Config) {
}

s.Stop()
fmt.Fprintln(os.Stdout, "\nkagent uninstalled successfully")
fmt.Fprintln(os.Stdout, "\nkagent uninstalled successfully") //nolint:errcheck
}
2 changes: 1 addition & 1 deletion go/cli/internal/cli/invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,6 @@ func InvokeCmd(ctx context.Context, cfg *InvokeCfg) {
return
}

fmt.Fprintf(os.Stdout, "%+v\n", string(jsn))
fmt.Fprintf(os.Stdout, "%+v\n", string(jsn)) //nolint:errcheck
}
}
10 changes: 5 additions & 5 deletions go/cli/internal/cli/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

var (
ErrServerConnection = fmt.Errorf("Error connecting to server. Please run 'install' command first.")
ErrServerConnection = fmt.Errorf("error connecting to server. Please run 'install' command first")
)

func CheckServerConnection(client *client.ClientSet) error {
Expand Down Expand Up @@ -70,7 +70,7 @@ func (p *PortForward) Stop() {
p.cancel()
// This will terminate the kubectl process in case the cancel does not work.
if p.cmd.Process != nil {
p.cmd.Process.Kill()
p.cmd.Process.Kill() //nolint:errcheck
}

// Don't wait for the process - just cancel the context and let it die
Expand All @@ -85,15 +85,15 @@ func StreamA2AEvents(ch <-chan protocol.StreamingMessageEvent, verbose bool) {
fmt.Fprintf(os.Stderr, "Error marshaling A2A event: %v\n", err)
continue
}
fmt.Fprintf(os.Stdout, "%+v\n", string(json))
fmt.Fprintf(os.Stdout, "%+v\n", string(json)) //nolint:errcheck
} else {
json, err := event.MarshalJSON()
if err != nil {
fmt.Fprintf(os.Stderr, "Error marshaling A2A event: %v\n", err)
continue
}
fmt.Fprintf(os.Stdout, "%+v\n", string(json))
fmt.Fprintf(os.Stdout, "%+v\n", string(json)) //nolint:errcheck
}
}
fmt.Fprintln(os.Stdout) // Add a newline after streaming is complete
fmt.Fprintln(os.Stdout) //nolint:errcheck // Add a newline after streaming is complete
}
2 changes: 1 addition & 1 deletion go/cli/internal/cli/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ func VersionCmd(cfg *config.Config) {
versionInfo["backend_version"] = version.KAgentVersion
}

json.NewEncoder(os.Stdout).Encode(versionInfo)
json.NewEncoder(os.Stdout).Encode(versionInfo) //nolint:errcheck
}
4 changes: 4 additions & 0 deletions go/controller/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,10 @@ func main() {
Authorizer: authorizer,
Authenticator: authenticator,
})
if err != nil {
Copy link

Copilot AI Aug 21, 2025

Choose a reason for hiding this comment

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

The error handling is checking for an error from the NewHTTPServer call, but the error variable err was not declared or assigned from that function call. The NewHTTPServer call on line 438-444 should assign its return value to include the error.

Copilot uses AI. Check for mistakes.
setupLog.Error(err, "unable to create HTTP server")
os.Exit(1)
}
if err := mgr.Add(httpServer); err != nil {
setupLog.Error(err, "unable to set up HTTP server")
os.Exit(1)
Expand Down
5 changes: 0 additions & 5 deletions go/controller/internal/a2a/a2a_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,10 @@ import (
"github.com/kagent-dev/kagent/go/internal/a2a"
"github.com/kagent-dev/kagent/go/internal/httpserver/auth"
common "github.com/kagent-dev/kagent/go/internal/utils"
ctrl "sigs.k8s.io/controller-runtime"
a2aclient "trpc.group/trpc-go/trpc-a2a-go/client"
"trpc.group/trpc-go/trpc-a2a-go/server"
)

var (
reconcileLog = ctrl.Log.WithName("a2a_reconcile")
)

type A2AReconciler interface {
ReconcileAgent(
ctx context.Context,
Expand Down
43 changes: 21 additions & 22 deletions go/controller/internal/reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/hashicorp/go-multierror"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -93,11 +92,11 @@ func (a *kagentReconciler) ReconcileKagentAgent(ctx context.Context, req ctrl.Re

func (a *kagentReconciler) handleAgentDeletion(req ctrl.Request) error {
// remove a2a handler if it exists
a.a2aReconciler.ReconcileAgentDeletion(req.NamespacedName.String())
a.a2aReconciler.ReconcileAgentDeletion(req.String())

if err := a.dbClient.DeleteAgent(req.NamespacedName.String()); err != nil {
if err := a.dbClient.DeleteAgent(req.String()); err != nil {
return fmt.Errorf("failed to delete agent %s: %w",
req.NamespacedName.String(), err)
req.String(), err)
}

reconcileLog.Info("Agent was deleted", "namespace", req.Namespace, "name", req.Name)
Expand Down Expand Up @@ -180,7 +179,7 @@ func (a *kagentReconciler) reconcileAgentStatus(ctx context.Context, agent *v1al
}
}

conditionChanged = meta.SetStatusCondition(&agent.Status.Conditions, deployedCondition)
conditionChanged = conditionChanged || meta.SetStatusCondition(&agent.Status.Conditions, deployedCondition)

// Only update the config hash if the config hash has changed and there was no error
configHashChanged := len(configHash) > 0 && !bytes.Equal((agent.Status.ConfigHash)[:], configHash[:])
Expand All @@ -205,15 +204,15 @@ func (a *kagentReconciler) ReconcileKagentMCPService(ctx context.Context, req ct
if k8s_errors.IsNotFound(err) {
// Delete from DB if the service is deleted
dbService := &database.ToolServer{
Name: req.NamespacedName.String(),
Name: req.String(),
GroupKind: schema.GroupKind{Group: "", Kind: "Service"}.String(),
}
if err := a.dbClient.DeleteToolServer(dbService.Name, dbService.GroupKind); err != nil {
reconcileLog.Error(err, "failed to delete tool server for mcp service", "service", req.NamespacedName.String())
reconcileLog.Error(err, "failed to delete tool server for mcp service", "service", req.String())
}
reconcileLog.Info("mcp service was deleted", "service", req.NamespacedName.String())
reconcileLog.Info("mcp service was deleted", "service", req.String())
if err := a.dbClient.DeleteToolsForServer(dbService.Name, dbService.GroupKind); err != nil {
reconcileLog.Error(err, "failed to delete tools for mcp service", "service", req.NamespacedName.String())
reconcileLog.Error(err, "failed to delete tools for mcp service", "service", req.String())
}
return nil
}
Expand Down Expand Up @@ -248,8 +247,8 @@ func (a *kagentReconciler) ReconcileKagentModelConfig(ctx context.Context, req c

var err error
if modelConfig.Spec.APIKeySecret != "" {
secret := &v1.Secret{}
if err := a.kube.Get(ctx, types.NamespacedName{Namespace: modelConfig.Namespace, Name: modelConfig.Spec.APIKeySecret}, secret); err != nil {
secret := &corev1.Secret{}
if err = a.kube.Get(ctx, types.NamespacedName{Namespace: modelConfig.Namespace, Name: modelConfig.Spec.APIKeySecret}, secret); err != nil {
err = fmt.Errorf("failed to get secret %s: %v", modelConfig.Spec.APIKeySecret, err)
}
}
Expand Down Expand Up @@ -301,15 +300,15 @@ func (a *kagentReconciler) ReconcileKagentMCPServer(ctx context.Context, req ctr
if k8s_errors.IsNotFound(err) {
// Delete from DB if the mcp server is deleted
dbServer := &database.ToolServer{
Name: req.NamespacedName.String(),
Name: req.String(),
GroupKind: schema.GroupKind{Group: "kagent.dev", Kind: "MCPServer"}.String(),
}
if err := a.dbClient.DeleteToolServer(dbServer.Name, dbServer.GroupKind); err != nil {
reconcileLog.Error(err, "failed to delete tool server for mcp server", "mcpServer", req.NamespacedName.String())
reconcileLog.Error(err, "failed to delete tool server for mcp server", "mcpServer", req.String())
}
reconcileLog.Info("mcp server was deleted", "mcpServer", req.NamespacedName.String())
reconcileLog.Info("mcp server was deleted", "mcpServer", req.String())
if err := a.dbClient.DeleteToolsForServer(dbServer.Name, dbServer.GroupKind); err != nil {
reconcileLog.Error(err, "failed to delete tools for mcp server", "mcpServer", req.NamespacedName.String())
reconcileLog.Error(err, "failed to delete tools for mcp server", "mcpServer", req.String())
}
return nil
}
Expand Down Expand Up @@ -340,15 +339,15 @@ func (a *kagentReconciler) ReconcileKagentRemoteMCPServer(ctx context.Context, r
if k8s_errors.IsNotFound(err) {
// Delete from DB if the remote mcp server is deleted
dbServer := &database.ToolServer{
Name: req.NamespacedName.String(),
Name: req.String(),
GroupKind: schema.GroupKind{Group: "kagent.dev", Kind: "RemoteMCPServer"}.String(),
}
if err := a.dbClient.DeleteToolServer(dbServer.Name, dbServer.GroupKind); err != nil {
reconcileLog.Error(err, "failed to delete tool server for remote mcp server", "remoteMCPServer", req.NamespacedName.String())
reconcileLog.Error(err, "failed to delete tool server for remote mcp server", "remoteMCPServer", req.String())
}
reconcileLog.Info("remote mcp server was deleted", "remoteMCPServer", req.NamespacedName.String())
reconcileLog.Info("remote mcp server was deleted", "remoteMCPServer", req.String())
if err := a.dbClient.DeleteToolsForServer(dbServer.Name, dbServer.GroupKind); err != nil {
reconcileLog.Error(err, "failed to delete tools for remote mcp server", "remoteMCPServer", req.NamespacedName.String())
reconcileLog.Error(err, "failed to delete tools for remote mcp server", "remoteMCPServer", req.String())
}
return nil
}
Expand Down Expand Up @@ -513,8 +512,8 @@ func (a *kagentReconciler) createMcpTransport(ctx context.Context, s *v1alpha2.R
return nil, err
}

switch {
case s.Protocol == v1alpha2.RemoteMCPServerProtocolSse:
switch s.Protocol {
case v1alpha2.RemoteMCPServerProtocolSse:
return transport.NewSSE(s.URL, transport.WithHeaders(headers))
default:
return transport.NewStreamableHTTP(s.URL, transport.WithHTTPHeaders(headers))
Expand All @@ -527,7 +526,7 @@ func (a *kagentReconciler) listTools(ctx context.Context, tsp transport.Interfac
if err != nil {
return nil, fmt.Errorf("failed to start client for toolServer %s: %v", toolServer.Name, err)
}
defer client.Close()
defer client.Close() //nolint:errcheck
_, err = client.Initialize(ctx, mcp.InitializeRequest{
Params: mcp.InitializeParams{
ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION,
Expand Down
Loading
Loading