Skip to content

Commit fe2f194

Browse files
msafarikMarek Safarik
andauthored
CI/CD (#14)
* github actions: lint, gosec, sourcery, staticcheck Signed-off-by: Marek Safarik <msafarik@redhat.com> * fix gopath Signed-off-by: Marek Safarik <msafarik@redhat.com> * run checks only on stable fedora release Signed-off-by: Marek Safarik <msafarik@redhat.com> * Fix golangci-li errors Signed-off-by: Marek Safarik <msafarik@redhat.com> * goces Signed-off-by: Marek Safarik <msafarik@redhat.com> * Removed texlive-colourchange-doc package Signed-off-by: Marek Safarik <msafarik@redhat.com> * fix: golangci-lint after review (version upgrade and replacement go install with golangci-lint) Signed-off-by: Marek Safarik <msafarik@redhat.com> * golangci-lint version upgrade to v9 Signed-off-by: Marek Safarik <msafarik@redhat.com> * upgrade golangci-lint to v2 Signed-off-by: Marek Safarik <msafarik@redhat.com> --------- Signed-off-by: Marek Safarik <msafarik@redhat.com> Co-authored-by: Marek Safarik <msafarik@redhat.com>
1 parent 6da1f6b commit fe2f194

File tree

13 files changed

+265
-62
lines changed

13 files changed

+265
-62
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: golangci-lint
3+
4+
"on":
5+
push:
6+
paths-ignore:
7+
- '**.md'
8+
- '**.sh'
9+
pull_request:
10+
paths-ignore:
11+
- '**.md'
12+
- '**.sh'
13+
14+
jobs:
15+
golangci-lint:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v6
19+
20+
- name: Show OS information
21+
run: cat /etc/os-release
22+
23+
- name: Install Go
24+
run: dnf -y install golang
25+
26+
- name: Show Go version
27+
run: go version
28+
29+
- name: golangci-lint
30+
uses: golangci/golangci-lint-action@v9
31+
with:
32+
version: latest
33+
34+
container:
35+
image: fedora:latest
36+
env:
37+
GOPATH: /root/go
38+
PATH: /root/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

.github/workflows/gosec.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: gosec
3+
4+
"on":
5+
push:
6+
paths-ignore:
7+
- '**.md'
8+
- '**.sh'
9+
pull_request:
10+
paths-ignore:
11+
- '**.md'
12+
- '**.sh'
13+
14+
jobs:
15+
gosec:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v5
19+
20+
- name: Show OS information
21+
run: cat /etc/os-release
22+
23+
- name: Install Go
24+
run: dnf -y install golang
25+
26+
- name: Install gosec
27+
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
28+
29+
- name: Run gosec
30+
run: gosec -exclude=G706 ./...
31+
32+
container:
33+
image: fedora:latest
34+
env:
35+
GOPATH: /root/go
36+
PATH: /root/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

.github/workflows/install-dependencies

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ case "${DISTRO}" in
229229
texlive-graphicxpsd \
230230
texlive-ae \
231231
texlive-colourchange \
232-
texlive-colourchange-doc \
233232
texlive-todonotes \
234233
texlive-babel-english \
235234
texlive-tocbibind \

.github/workflows/sourcery.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
name: sourcery-ai
3+
4+
"on":
5+
pull_request:
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
11+
jobs:
12+
sourcery:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v5
16+
with:
17+
fetch-depth: 0
18+
19+
- name: Sourcery AI Code Review
20+
uses: sourcery-ai/action@v1
21+
with:
22+
token: ${{ secrets.SOURCERY_TOKEN }}

.github/workflows/staticcheck.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: staticcheck
3+
4+
"on":
5+
push:
6+
paths-ignore:
7+
- '**.md'
8+
- '**.sh'
9+
pull_request:
10+
paths-ignore:
11+
- '**.md'
12+
- '**.sh'
13+
14+
jobs:
15+
staticcheck:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v5
19+
20+
- name: Show OS information
21+
run: cat /etc/os-release
22+
23+
- name: Install Go
24+
run: dnf -y install golang
25+
26+
- name: Install staticcheck
27+
run: go install honnef.co/go/tools/cmd/staticcheck@latest
28+
29+
- name: Run staticcheck
30+
run: staticcheck ./...
31+
32+
container:
33+
image: fedora:latest
34+
env:
35+
GOPATH: /root/go
36+
PATH: /root/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

.golangci.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
version: "2"
3+
4+
linters:
5+
enable:
6+
# Default linters
7+
- errcheck
8+
- govet
9+
- staticcheck
10+
- unused
11+
# Additional linters
12+
- bodyclose
13+
- dupl
14+
- gocognit
15+
- goconst
16+
- gocritic
17+
- gocyclo
18+
- gosec
19+
- misspell
20+
- nakedret
21+
- prealloc
22+
- revive
23+
- unconvert
24+
- unparam
25+
- whitespace
26+
settings:
27+
gocyclo:
28+
min-complexity: 15
29+
gocognit:
30+
min-complexity: 20
31+
dupl:
32+
threshold: 100
33+
goconst:
34+
min-len: 3
35+
min-occurrences: 3
36+
misspell:
37+
locale: US
38+
errcheck:
39+
exclude-functions:
40+
- (net/http.ResponseWriter).Write
41+
- fmt.Fprintf
42+
- (io.Closer).Close
43+
gosec:
44+
excludes:
45+
- G706
46+
revive:
47+
rules:
48+
- name: blank-imports
49+
- name: context-as-argument
50+
- name: dot-imports
51+
- name: error-return
52+
- name: error-strings
53+
- name: increment-decrement
54+
- name: var-naming
55+
- name: package-comments
56+
disabled: true
57+
58+
formatters:
59+
enable:
60+
- gofmt
61+
- goimports

cmd/client/main.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ func main() {
3838

3939
apiKey := strings.TrimSpace(os.Getenv("ANTHROPIC_API_KEY"))
4040
if apiKey == "" {
41-
log.Fatal("ANTHROPIC_API_KEY environment variable not set")
41+
log.Println("ANTHROPIC_API_KEY environment variable not set")
42+
return
4243
}
4344

4445
serverPath := os.Getenv("MCP_SERVER_PATH")
@@ -51,7 +52,7 @@ func main() {
5152
port = defaultPort
5253
}
5354

54-
if _, err := os.Stat(serverPath); os.IsNotExist(err) {
55+
if _, err := os.Stat(serverPath); os.IsNotExist(err) { // #nosec G703 -- serverPath from env/default, not user input
5556
log.Printf("Warning: MCP server not found at %s", serverPath)
5657
log.Printf("Build the server first: go build -o bin/server cmd/server/main.go")
5758
return
@@ -63,24 +64,28 @@ func main() {
6364
})
6465

6566
if err := agentInstance.Connect(ctx); err != nil {
66-
log.Fatalf("Failed to connect to MCP server: %v", err)
67+
log.Printf("Failed to connect to MCP server: %v", err)
68+
return
6769
}
6870
log.Printf("Connected to MCP server")
6971
defer agentInstance.Close()
7072

7173
if err := agentInstance.GetTools(ctx); err != nil {
72-
log.Fatalf("Failed to get MCP tools: %v", err)
74+
log.Printf("Failed to get MCP tools: %v", err)
75+
return
7376
}
7477

75-
srv, err := web.NewServer(agentInstance, ctx)
78+
srv, err := web.NewServer(ctx, agentInstance)
7679
if err != nil {
77-
log.Fatalf("Failed to create web server: %v", err)
80+
log.Printf("Failed to create web server: %v", err)
81+
return
7882
}
7983

8084
addr := fmt.Sprintf(":%s", port)
8185
log.Printf("Starting Keylime MCP Agent at http://localhost%s", addr)
8286

8387
if err := srv.Start(addr); err != nil {
84-
log.Fatalf("Server error: %v", err)
88+
log.Printf("Server error: %v", err)
89+
return
8590
}
8691
}

cmd/server/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ func main() {
3030
if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
3131
log.Fatal(err)
3232
}
33-
3433
}
3534

3635
func loadConfig() keylime.Config {

internal/agent/agent.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package agent
33
import (
44
"context"
55
"fmt"
6+
"log"
67
"os/exec"
78
"strings"
89

@@ -31,7 +32,7 @@ You have a maximum of 5 conversation turns to complete the task. When given a ta
3132
)
3233

3334
type Config struct {
34-
APIKey string
35+
APIKey string // #nosec G117 -- field name for API key config, value is not hardcoded
3536
ServerPath string
3637
Model anthropic.Model
3738
MaxTokens int64
@@ -88,7 +89,7 @@ func (a *Agent) Connect(ctx context.Context) error {
8889
Name: mcpClientName,
8990
Version: mcpClientVersion,
9091
}, nil)
91-
cmd := exec.Command(a.config.ServerPath)
92+
cmd := exec.Command(a.config.ServerPath) // #nosec G204 -- ServerPath is from trusted config, not user input
9293
transport := &mcp.CommandTransport{Command: cmd}
9394
session, err := client.Connect(ctx, transport, nil)
9495
if err != nil {
@@ -148,10 +149,14 @@ func convertMCPToolToClaudeTool(tool *mcp.Tool) anthropic.ToolUnionParam {
148149

149150
func (a *Agent) Close() {
150151
if a.mcpSession != nil {
151-
a.mcpSession.Close()
152+
if err := a.mcpSession.Close(); err != nil {
153+
log.Printf("Warning: failed to close MCP session: %v", err)
154+
}
152155
}
153156
if a.mcpCmd != nil && a.mcpCmd.Process != nil {
154-
a.mcpCmd.Process.Kill()
157+
if err := a.mcpCmd.Process.Kill(); err != nil {
158+
log.Printf("Warning: failed to kill MCP process: %v", err)
159+
}
155160
}
156161
}
157162

@@ -223,13 +228,14 @@ func (a *Agent) ExecuteTool(ctx context.Context, toolRequest *ToolRequest, onMes
223228
var resultText string
224229
var isError bool
225230

226-
if err != nil {
231+
switch {
232+
case err != nil:
227233
resultText = fmt.Sprintf("Error: %v", err)
228234
isError = true
229-
} else if result.IsError {
235+
case result.IsError:
230236
resultText = fmt.Sprintf("Tool '%s' execution failed: %s", toolRequest.Name, extractTextContent(result.Content))
231237
isError = true
232-
} else {
238+
default:
233239
resultText = extractTextContent(result.Content)
234240
}
235241

0 commit comments

Comments
 (0)