From 4b55ca0f220ffb8e26b7356bce44cc3c82bfcb9a Mon Sep 17 00:00:00 2001 From: S3B4SZ17 Date: Thu, 12 Mar 2026 22:32:41 -0600 Subject: [PATCH 1/3] feat adding better output management of the tool responses to a json file Signed-off-by: S3B4SZ17 --- .github/workflows/build.yml | 4 +- .github/workflows/pr.yml | 4 +- .github/workflows/release.yml | 4 +- Makefile | 3 + cmd/woodpecker-mcp-verifier/cmd/root.go | 48 ++++--- cmd/woodpecker-mcp-verifier/docs/README.md | 2 +- .../vschema/ai-verifier.go | 4 +- internal/mcp-verifier/main.go | 42 +++++-- internal/mcp-verifier/model.go | 27 +++- internal/mcp-verifier/oauth/oauth.go | 2 +- internal/mcp-verifier/outputs.go | 118 ++++++++++++++++++ 11 files changed, 222 insertions(+), 36 deletions(-) create mode 100644 internal/mcp-verifier/outputs.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0af859f..f78358b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,9 @@ jobs: go-version: ${{ env.go_version }} - name: Build - run: make build + run: | + make build + make build-woodpecker-mcp-verifier - name: Test run: make test diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7678ac7..74309d9 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -17,7 +17,9 @@ jobs: go-version: ${{ env.go_version }} - name: Build - run: make build + run: | + make build + make build-woodpecker-mcp-verifier - name: Test run: make test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ecdd522..2f47647 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,9 @@ jobs: go-version: ${{ env.go_version }} - name: Build - run: make build + run: | + make build + make build-woodpecker-mcp-verifier - name: Test run: make test diff --git a/Makefile b/Makefile index 41404a9..c114b9b 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,9 @@ build-woodpecker-ai-verifier: ## Build woodpecker AI verifier container build-woodpecker-ai-app: ## Build woodpecker AI app container @docker build -f build/Dockerfile.woodpecker-ai-app . +build-woodpecker-mcp-verifier: ## Builds the woodpecker MCP verifier client tool + @go build -o "bin/woodpecker-mcp-verifier" -ldflags $(LD_FLAGS) cmd/woodpecker-mcp-verifier/main.go + # ==================================================================================== # # QUALITY # ==================================================================================== # diff --git a/cmd/woodpecker-mcp-verifier/cmd/root.go b/cmd/woodpecker-mcp-verifier/cmd/root.go index 7847774..94deffa 100644 --- a/cmd/woodpecker-mcp-verifier/cmd/root.go +++ b/cmd/woodpecker-mcp-verifier/cmd/root.go @@ -3,6 +3,7 @@ package cmd import ( "context" + "fmt" "strings" "github.com/operantai/woodpecker/cmd/woodpecker-mcp-verifier/utils" @@ -19,10 +20,13 @@ var ( Short: "Run a MCP client verifier as a Woodpecker components", Long: "Run a MCP client verifier as a Woodpecker components", } - protocol utils.MCMCPprotocol - cmdArgs []string + protocol utils.MCMCPprotocol + cmdArgs []string + serverURL, payloadPath, appName string ) +const experimentType = "woodpecker" + // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { @@ -32,29 +36,39 @@ func Execute() { } } -// cleanCmd represents the clean command var runCmd = &cobra.Command{ Use: "run", - Short: "Run a MCP client verifier as a Woodpecker component", - Long: "Run a MCP client verifier as a Woodpecker component", - Run: func(cmd *cobra.Command, args []string) { - output.WriteInfo("MCP client verifier starting ...") - var serverURL, payloadPath string + Short: "Run a MCP client verifier as a Woodpecker experiment", + Long: "Run a MCP client verifier as a Woodpecker experiment", + PreRunE: func(cmd *cobra.Command, args []string) error { + // Mutually exclusive: either --url or --cmd_args for either + // streamable-http or stdio var err error if serverURL, err = cmd.Flags().GetString("url"); err != nil { - output.WriteFatal("%v", err) + return err + } + if cmdArgs, err = cmd.Flags().GetStringSlice("cmd_args"); err != nil { + return err } + if serverURL != "" && len(cmdArgs) > 0 { + return fmt.Errorf("--url and --cmd_args are mutually exclusive") + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + output.WriteInfo("MCP client verifier starting ...") + payloadPath = viper.GetString("payload-path") - if err := mcpverifier.RunClient(context.Background(), serverURL, protocol, &cmdArgs, payloadPath); err != nil { - output.WriteFatal("%v", err) + if err := mcpverifier.RunClient(context.Background(), serverURL, protocol, &cmdArgs, payloadPath, experimentType, appName); err != nil { + return err } + return nil }, } func init() { - rootCmd.AddCommand(runCmd) // Tells Viper to use this prefix when reading environment variables viper.SetEnvPrefix("woodpecker") viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) @@ -64,9 +78,6 @@ func init() { runCmd.Flags().VarP(&protocol, "protocol", "p", "The MCP protocol being used") runCmd.Flags().StringP("payload-path", "t", "/app/payload.json", "The path to the json payload content") runCmd.Flags().StringSliceP("cmd_args", "c", cmdArgs, `If STDIO protocol, a comma separated list of cmd and args. i.e -c "uv,run,server"`) - if err := runCmd.MarkFlagRequired("url"); err != nil { - output.WriteFatal("%v", err) - } if err := runCmd.MarkFlagRequired("protocol"); err != nil { output.WriteFatal("%v", err) } @@ -75,9 +86,12 @@ func init() { } // Sets App name - appName := viper.GetString("APP_NAME") + appName = viper.GetString("APP_NAME") if appName == "" { output.WriteInfo("Setting WOODPECKER_APP_NAME to woodpecker-mcp-verifier") - viper.Set("APP_NAME", "woodpecker-mcp-verifier") + appName = "mcp-verifier" + viper.Set("APP_NAME", fmt.Sprintf("%s-%s", experimentType, appName)) } + + rootCmd.AddCommand(runCmd) } diff --git a/cmd/woodpecker-mcp-verifier/docs/README.md b/cmd/woodpecker-mcp-verifier/docs/README.md index 38c2362..b601b2e 100644 --- a/cmd/woodpecker-mcp-verifier/docs/README.md +++ b/cmd/woodpecker-mcp-verifier/docs/README.md @@ -14,7 +14,7 @@ The tool is an MCP client that will perform the following actions: In order to run the tool here are some of the input parameters you can pass: ```bash -go run cmd/woodpecker-mcp-verifier/main.go run -h +woodpecker-mcp-verifier -h Run a MCP client verifier as a Woodpecker component diff --git a/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go b/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go index f2a7aeb..38c15ea 100644 --- a/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go +++ b/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go @@ -37,8 +37,8 @@ func (a *AIFormatter) AnalyzeSchema(inputSchema any) (map[string]any, error) { return nil, err } - output.WriteInfo("AI response ...") - output.WriteJSON(result) + output.WriteInfo("Generating AI response ...") + // output.WriteJSON(result) return result, nil } diff --git a/internal/mcp-verifier/main.go b/internal/mcp-verifier/main.go index 79ddb36..e0d08f4 100644 --- a/internal/mcp-verifier/main.go +++ b/internal/mcp-verifier/main.go @@ -24,13 +24,14 @@ import ( "golang.org/x/sync/errgroup" ) +const tmpFileDir = "/tmp/woodpecker" + // RunClient entry point to start the MCP client connection -func RunClient(ctx context.Context, serverURL string, protocol utils.MCMCPprotocol, cmdArgs *[]string, payloadPath string) error { - output.WriteInfo("Connecting to server: %s", serverURL) +func RunClient(ctx context.Context, serverURL string, protocol utils.MCMCPprotocol, cmdArgs *[]string, payloadPath, experimentType, name string) error { output.WriteInfo("Using protocol: %s", protocol) sValidator := vschema.NewVSchema() - mcpClient, err := NewMCPClient(WithValidator(sValidator), WithAIFormatter(viper.GetBool("USE_AI_FORMATTER"))) + mcpClient, err := NewMCPClient(WithValidator(sValidator), WithAIFormatter(viper.GetBool("USE_AI_FORMATTER")), WithExperimentType(experimentType), WithName(name)) if err != nil { return err } @@ -70,6 +71,11 @@ func RunClient(ctx context.Context, serverURL string, protocol utils.MCMCPprotoc } } + mergedPath, err := mergeTempJSONFilesStreaming(tmpFileDir, experimentType, name) + if err != nil { + return err + } + output.WriteInfo("Results saved in: %s", mergedPath) return nil } @@ -185,13 +191,31 @@ func (m *mcpClient) ToolCallWithPayload(ctx context.Context, cs IMCPClientSessio if err != nil { return err } - resp := map[string]any{ - "tool": tool.Name, - "response": string(data), - "tags": mPayload.Tags, + resp := make(map[string][]ToolResponses) + + resp[tool.Name] = []ToolResponses{{ + ToolName: tool.Name, + Response: string(data), + Tags: mPayload.Tags, + Parameters: params, + }, + } + resultJSON, err := json.Marshal(resp) + if err != nil { + return fmt.Errorf("failed to marshal experiment results: %w", err) + } + output.WriteInfo("Saving %s response ...", tool.Name) + // output.WriteJSON(resp) + file, err := createTempFile(m.experimentType, m.name) + if err != nil { + return fmt.Errorf("unable to create file cache for experiment results %w", err) } - output.WriteInfo("Tool response ...") - output.WriteJSON(resp) + + _, err = file.Write(resultJSON) + if err != nil { + return fmt.Errorf("failed to write experiment results: %w", err) + } + } return nil } diff --git a/internal/mcp-verifier/model.go b/internal/mcp-verifier/model.go index dfa15fb..f1972e4 100644 --- a/internal/mcp-verifier/model.go +++ b/internal/mcp-verifier/model.go @@ -60,9 +60,11 @@ type IMCPClient interface { } type mcpClient struct { - validator vschema.IvSchema - aiFormatter vschema.IAIFormatter - useAi bool + validator vschema.IvSchema + aiFormatter vschema.IAIFormatter + useAi bool + name string + experimentType string } type Option func(*mcpClient) @@ -79,6 +81,18 @@ func WithAIFormatter(useAI bool) Option { } } +func WithName(name string) Option { + return func(mc *mcpClient) { + mc.name = name + } +} + +func WithExperimentType(experimentType string) Option { + return func(mc *mcpClient) { + mc.experimentType = experimentType + } +} + func NewMCPClient(options ...Option) (IMCPClient, error) { mc := &mcpClient{} @@ -112,3 +126,10 @@ type IMCPClientSession interface { // The params.Arguments can be any value that marshals into a JSON object. CallTool(ctx context.Context, params *mcp.CallToolParams) (*mcp.CallToolResult, error) } + +type ToolResponses struct { + ToolName string `json:"toolName"` + Response string `json:"response"` + Tags []string `json:"tags"` + Parameters any `json:"parameters"` +} diff --git a/internal/mcp-verifier/oauth/oauth.go b/internal/mcp-verifier/oauth/oauth.go index 9793fbb..9d102a3 100644 --- a/internal/mcp-verifier/oauth/oauth.go +++ b/internal/mcp-verifier/oauth/oauth.go @@ -472,7 +472,7 @@ func checkCredsPath(appName string) (configPath string, err error) { file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) if errors.Is(err, os.ErrExist) { - output.WriteInfo("File: %s already exists. Using cached toke.", filePath) + output.WriteInfo("File: %s already exists. Using cached token.", filePath) return filePath, nil } else if err != nil { diff --git a/internal/mcp-verifier/outputs.go b/internal/mcp-verifier/outputs.go new file mode 100644 index 0000000..c4cbf94 --- /dev/null +++ b/internal/mcp-verifier/outputs.go @@ -0,0 +1,118 @@ +package mcpverifier + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "time" +) + +func createTempFile(experimentType, experiment string) (*os.File, error) { + if _, err := os.Stat(tmpFileDir); err != nil { + if os.IsNotExist(err) { + if err := os.Mkdir(tmpFileDir, 0700); err != nil { + return nil, err + } + } + } + file, err := os.CreateTemp(tmpFileDir, fmt.Sprintf("%s-%s-*.json", experimentType, experiment)) + if err != nil { + return nil, err + } + return file, nil +} + +func mergeTempJSONFilesStreaming(dir, experimentType, experiment string) (string, error) { + files, err := os.ReadDir(dir) + if err != nil { + return "", err + } + + fileCh := make(chan string, 100) + dataCh := make(chan map[string][]ToolResponses, 100) + + workerCount := runtime.NumCPU() + var wg sync.WaitGroup + + // Worker pool + for range workerCount { + wg.Add(1) + + go func() { + defer wg.Done() + + // Will wait till there is a file saved in the channel + // feed by the other concurrent read on `range files` + for path := range fileCh { + data, err := os.ReadFile(path) + if err != nil { + continue // skip corrupted files + } + + var tmp map[string][]ToolResponses + if err := json.Unmarshal(data, &tmp); err != nil { + continue + } + + dataCh <- tmp + + // fmt.Printf("Removing file: %s", path) + // cleanup temp file + _ = os.Remove(path) + } + }() + } + + // Feed files to workers + go func() { + prefix := fmt.Sprintf("%s-%s", experimentType, experiment) + + for _, f := range files { + if f.IsDir() { + continue + } + + if !strings.HasPrefix(f.Name(), prefix) { + continue + } + + fileCh <- filepath.Join(dir, f.Name()) + } + + close(fileCh) + }() + + // Close data channel after workers finish + go func() { + wg.Wait() + close(dataCh) + }() + + // Now we merge the files from the data channel + merged := make(map[string][]ToolResponses) + + for m := range dataCh { + for k, v := range m { + merged[k] = append(merged[k], v...) + } + } + + timestamp := time.Now().UTC().Format("20060102-150405.000") + outPath := filepath.Join(dir, fmt.Sprintf("%s-%s-%s.json", experimentType, experiment, timestamp)) + + outJSON, err := json.Marshal(merged) + if err != nil { + return "", err + } + + err = os.WriteFile(outPath, outJSON, 0644) + if err != nil { + return "", err + } + + return outPath, nil +} From 884c14da77e5f250b65340e9093575009c63a349 Mon Sep 17 00:00:00 2001 From: S3B4SZ17 Date: Fri, 13 Mar 2026 08:34:15 -0600 Subject: [PATCH 2/3] fix MCP Go SDK Vulnerable to Improper Handling of Case Sensitivity Signed-off-by: S3B4SZ17 --- cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go | 1 - go.mod | 6 ++++-- go.sum | 12 ++++++++---- internal/mcp-verifier/main.go | 1 - internal/mcp-verifier/outputs.go | 1 - tests/woodpecker_suite_test.go | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go b/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go index 38c15ea..4af0cf4 100644 --- a/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go +++ b/cmd/woodpecker-mcp-verifier/vschema/ai-verifier.go @@ -38,7 +38,6 @@ func (a *AIFormatter) AnalyzeSchema(inputSchema any) (map[string]any, error) { } output.WriteInfo("Generating AI response ...") - // output.WriteJSON(result) return result, nil } diff --git a/go.mod b/go.mod index ce7d3bc..47cfa09 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/mattn/go-runewidth v0.0.16 - github.com/modelcontextprotocol/go-sdk v1.2.0 + github.com/modelcontextprotocol/go-sdk v1.3.1 github.com/onsi/ginkgo/v2 v2.27.2 github.com/onsi/gomega v1.38.2 github.com/spf13/cobra v1.7.0 @@ -56,7 +56,7 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/jsonschema-go v0.3.0 // indirect + github.com/google/jsonschema-go v0.4.2 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -80,6 +80,8 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/segmentio/asm v1.1.3 // indirect + github.com/segmentio/encoding v0.5.3 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect diff --git a/go.sum b/go.sum index 711b20b..425f0e0 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q= -github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= +github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= +github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -141,8 +141,8 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= -github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s= -github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10= +github.com/modelcontextprotocol/go-sdk v1.3.1 h1:TfqtNKOIWN4Z1oqmPAiWDC2Jq7K9OdJaooe0teoXASI= +github.com/modelcontextprotocol/go-sdk v1.3.1/go.mod h1:DgVX498dMD8UJlseK1S5i1T4tFz2fkBk4xogC3D15nw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -179,6 +179,10 @@ github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWN github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= +github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= +github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= +github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= diff --git a/internal/mcp-verifier/main.go b/internal/mcp-verifier/main.go index e0d08f4..349f6f9 100644 --- a/internal/mcp-verifier/main.go +++ b/internal/mcp-verifier/main.go @@ -205,7 +205,6 @@ func (m *mcpClient) ToolCallWithPayload(ctx context.Context, cs IMCPClientSessio return fmt.Errorf("failed to marshal experiment results: %w", err) } output.WriteInfo("Saving %s response ...", tool.Name) - // output.WriteJSON(resp) file, err := createTempFile(m.experimentType, m.name) if err != nil { return fmt.Errorf("unable to create file cache for experiment results %w", err) diff --git a/internal/mcp-verifier/outputs.go b/internal/mcp-verifier/outputs.go index c4cbf94..130628c 100644 --- a/internal/mcp-verifier/outputs.go +++ b/internal/mcp-verifier/outputs.go @@ -60,7 +60,6 @@ func mergeTempJSONFilesStreaming(dir, experimentType, experiment string) (string dataCh <- tmp - // fmt.Printf("Removing file: %s", path) // cleanup temp file _ = os.Remove(path) } diff --git a/tests/woodpecker_suite_test.go b/tests/woodpecker_suite_test.go index 9e26dcc..7f6be4e 100644 --- a/tests/woodpecker_suite_test.go +++ b/tests/woodpecker_suite_test.go @@ -7,7 +7,7 @@ import ( . "github.com/onsi/gomega" ) -func TestMCPClientVerifier(t *testing.T) { +func TestWoodpeckerVerifier(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Woodpecker Test Suite") } From 6ccf1f8766837c36de293044b19e9602cb7d81d9 Mon Sep 17 00:00:00 2001 From: S3B4SZ17 Date: Fri, 13 Mar 2026 10:00:26 -0600 Subject: [PATCH 3/3] feat updating goreleaser to include the mcp-verifier in the bbuilds Signed-off-by: S3B4SZ17 --- .goreleaser.yaml | 11 +++++++++ cmd/woodpecker-mcp-verifier/cmd/version.go | 28 ++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 cmd/woodpecker-mcp-verifier/cmd/version.go diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 54c9f1c..ae9229e 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,6 +13,17 @@ builds: - "-X github.com/operantai/woodpecker/cmd/woodpecker/cmd.GitCommit={{.Commit}}" - "-X github.com/operantai/woodpecker/cmd/woodpecker/cmd.Version={{.Version}}" - "-X github.com/operantai/woodpecker/cmd/woodpecker/cmd.BuildDate={{ .Date }}" + - env: + - CGO_ENABLED=0 + main: ./cmd/woodpecker-mcp-verifier + goos: + - linux + - windows + - darwin + ldflags: + - "-X github.com/operantai/woodpecker/cmd/woodpecker-mcp-verifier/cmd.GitCommit={{.Commit}}" + - "-X github.com/operantai/woodpecker/cmd/woodpecker-mcp-verifier/cmd.Version={{.Version}}" + - "-X github.com/operantai/woodpecker/cmd/woodpecker-mcp-verifier/cmd.BuildDate={{ .Date }}" archives: - format: tar.gz diff --git a/cmd/woodpecker-mcp-verifier/cmd/version.go b/cmd/woodpecker-mcp-verifier/cmd/version.go new file mode 100644 index 0000000..8a40ecb --- /dev/null +++ b/cmd/woodpecker-mcp-verifier/cmd/version.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var ( + // Build info which gets populated by ldflags at build time + Version string + GitCommit string + BuildDate string +) + +// versionCmd represents the version command +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Output CLI version information", + Long: "Output CLI version information", + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("version %s, build %s, built on %s\n", Version, GitCommit, BuildDate) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/go.mod b/go.mod index 47cfa09..541ed72 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.11 require ( github.com/charmbracelet/lipgloss v1.1.0 - github.com/docker/docker v28.2.2+incompatible + github.com/docker/docker v28.3.3+incompatible github.com/docker/go-connections v0.5.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index 425f0e0..06b9c33 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= -github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=