diff --git a/Dockerfile b/Dockerfile index b856e86..993a781 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM alpine:3.21 -RUN apk add --no-cache ca-certificates && apk upgrade --update-cache --available +RUN apk upgrade --update-cache --available && apk add ca-certificates && rm -rf /var/cache/apk/* RUN adduser --disabled-password --no-create-home --uid=1983 spacelift COPY spacelift-vcs-agent /usr/bin/spacelift-vcs-agent diff --git a/cmd/spacelift-vcs-agent/main.go b/cmd/spacelift-vcs-agent/main.go index c985b24..c6d3ec1 100644 --- a/cmd/spacelift-vcs-agent/main.go +++ b/cmd/spacelift-vcs-agent/main.go @@ -16,7 +16,8 @@ import ( "github.com/bugsnag/bugsnag-go/v2" "github.com/go-kit/log" "github.com/spacelift-io/spcontext" - "github.com/urfave/cli/v2" + "context" + "github.com/urfave/cli/v3" "github.com/spacelift-io/vcs-agent/agent" "github.com/spacelift-io/vcs-agent/logging" @@ -49,78 +50,78 @@ var ( flagAllowedProjects = &cli.StringFlag{ Name: "allowed-projects", - EnvVars: []string{"SPACELIFT_VCS_AGENT_ALLOWED_PROJECTS"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_ALLOWED_PROJECTS"), Usage: "Regexp matching allowed projects for API calls. Projects are in the form: 'group/repository'.", Value: ".*", } flagBugsnagAPIKey = &cli.StringFlag{ Name: "bugsnag-api-key", - EnvVars: []string{"SPACELIFT_VCS_AGENT_BUGSNAG_API_KEY"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_BUGSNAG_API_KEY"), Usage: "Override the Bugsnag API key used for error reporting.", Value: "", } flagBugsnagDisable = &cli.BoolFlag{ Name: "disable-bugsnag", - EnvVars: []string{"SPACELIFT_VCS_AGENT_BUGSNAG_DISABLE"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_BUGSNAG_DISABLE"), Usage: "Disable Bugsnag reporting entirely.", } flagParallelism = &cli.IntFlag{ Name: "parallelism", - EnvVars: []string{"SPACELIFT_VCS_AGENT_PARALLELISM"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_PARALLELISM"), Usage: "Number of streams to create. Each stream can handle one request simultaneously.", Value: 4, } flagPoolToken = &cli.StringFlag{ Name: "token", - EnvVars: []string{"SPACELIFT_VCS_AGENT_POOL_TOKEN"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_POOL_TOKEN"), Usage: "Token received on VCS Agent Pool creation", Required: true, } flagTargetBaseEndpoint = &cli.StringFlag{ Name: "target-base-endpoint", - EnvVars: []string{"SPACELIFT_VCS_AGENT_TARGET_BASE_ENDPOINT"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_TARGET_BASE_ENDPOINT"), Usage: "Target endpoint this agent proxies to. Should include protocol (http/https).", Required: true, } flagVCSVendor = &cli.StringFlag{ Name: "vendor", - EnvVars: []string{"SPACELIFT_VCS_AGENT_VENDOR"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_VENDOR"), Usage: fmt.Sprintf("VCS vendor proxied by this agent. Available vendors: %s", strings.Join(availableVendors, ", ")), Required: true, } flagUseAllowlist = &cli.BoolFlag{ Name: "use-allowlist", - EnvVars: []string{"SPACELIFT_VCS_AGENT_USE_ALLOWLIST"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_USE_ALLOWLIST"), Usage: "Whether to use the allowlist to validate API calls. Incompatible with --blocklist-path.", } flagBlocklistPath = &cli.StringFlag{ Name: "blocklist-path", - EnvVars: []string{"SPACELIFT_VCS_AGENT_BLOCKLIST_PATH"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_BLOCKLIST_PATH"), Usage: "Path to the YAML blocklist file. Incompatible with --use-allowlist.", } flagDebugPrintAll = &cli.BoolFlag{ Name: "debug-print-all", - EnvVars: []string{"SPACELIFT_VCS_AGENT_DEBUG_PRINT_ALL"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_DEBUG_PRINT_ALL"), Usage: "Whether to print all requests and responses to stdout.", } flagHTTPDisableResponseCompression = &cli.BoolFlag{ Name: "http-disable-response-compression", - EnvVars: []string{"SPACELIFT_VCS_AGENT_HTTP_DISABLE_RESPONSE_COMPRESSION"}, + Sources: cli.EnvVars("SPACELIFT_VCS_AGENT_HTTP_DISABLE_RESPONSE_COMPRESSION"), Usage: "Whether to disable HTTP response compression.", } ) -var app = &cli.App{ +var app = &cli.Command{ Flags: []cli.Flag{ flagAllowedProjects, flagBugsnagAPIKey, @@ -132,12 +133,12 @@ var app = &cli.App{ flagDebugPrintAll, flagHTTPDisableResponseCompression, }, - Action: func(cmdCtx *cli.Context) error { + Action: func(cliCtx context.Context, cmd *cli.Command) error { availableVendorsMap := make(map[string]bool) for _, vendor := range availableVendors { availableVendorsMap[vendor] = true } - vendor := cmdCtx.String(flagVCSVendor.Name) + vendor := cmd.String(flagVCSVendor.Name) if !availableVendorsMap[vendor] { stdlog.Fatalf("invalid vendor specified: '%s', available vendors: [%s]", vendor, strings.Join(availableVendors, ", ")) } @@ -146,11 +147,11 @@ var app = &cli.App{ ctx := spcontext.New(log.NewJSONLogger(os.Stdout), opts...) apiKey := BugsnagAPIKey - if apiKeyOverride := cmdCtx.String(flagBugsnagAPIKey.Name); len(apiKeyOverride) > 0 { + if apiKeyOverride := cmd.String(flagBugsnagAPIKey.Name); len(apiKeyOverride) > 0 { apiKey = apiKeyOverride } - if !cmdCtx.Bool(flagBugsnagDisable.Name) { + if !cmd.Bool(flagBugsnagDisable.Name) { ctx.Notifier = bugsnag.New(bugsnag.Configuration{ APIKey: apiKey, Logger: &spcontext.BugsnagLogger{ @@ -163,7 +164,7 @@ var app = &cli.App{ } var poolConfig privatevcs.AgentPoolConfig - configBytes, err := base64.StdEncoding.DecodeString(cmdCtx.String(flagPoolToken.Name)) + configBytes, err := base64.StdEncoding.DecodeString(cmd.String(flagPoolToken.Name)) if err != nil { stdlog.Fatal("invalid pool token: ", err.Error()) } @@ -171,7 +172,7 @@ var app = &cli.App{ stdlog.Fatal("invalid pool token: ", err.Error()) } - if cmdCtx.IsSet(flagAllowedProjects.Name) && vendor == vendorGitHubEnterprise { + if cmd.IsSet(flagAllowedProjects.Name) && vendor == vendorGitHubEnterprise { stdlog.Fatal("--allowed-projects is not currently supported for the GitHub Enterprise integration") } @@ -179,25 +180,25 @@ var app = &cli.App{ var validationStrategy validation.Strategy = new(blocklist.List) - useAllowlist := cmdCtx.Bool(flagUseAllowlist.Name) + useAllowlist := cmd.Bool(flagUseAllowlist.Name) if useAllowlist { - if validationStrategy, err = allowlist.New(cmdCtx.String(flagAllowedProjects.Name)); err != nil { + if validationStrategy, err = allowlist.New(cmd.String(flagAllowedProjects.Name)); err != nil { stdlog.Fatal("could not create request allowlist: ", err.Error()) } } - if cmdCtx.IsSet(flagBlocklistPath.Name) { + if cmd.IsSet(flagBlocklistPath.Name) { if useAllowlist { stdlog.Fatal("--use-allowlist and --blocklist-path are mutually exclusive") } - if validationStrategy, err = blocklist.Load(cmdCtx.String(flagBlocklistPath.Name)); err != nil { + if validationStrategy, err = blocklist.Load(cmd.String(flagBlocklistPath.Name)); err != nil { stdlog.Fatal("could not create request blocklist: ", err.Error()) } } var httpClient agent.RequestDoer = http.DefaultClient - if cmdCtx.Bool(flagDebugPrintAll.Name) { + if cmd.Bool(flagDebugPrintAll.Name) { httpClient = &logging.HTTPClient{ Wrapped: http.DefaultClient, Out: &logging.ConcurrentSafeWriter{Out: os.Stdout}, @@ -206,15 +207,15 @@ var app = &cli.App{ a := agent.New( &poolConfig, - cmdCtx.String(flagTargetBaseEndpoint.Name), + cmd.String(flagTargetBaseEndpoint.Name), vendor, validationStrategy, agentMetadata, httpClient, ) - a.HTTPDisableResponseCompression = cmdCtx.Bool(flagHTTPDisableResponseCompression.Name) + a.HTTPDisableResponseCompression = cmd.Bool(flagHTTPDisableResponseCompression.Name) - parallelismSemaphore := make(chan struct{}, cmdCtx.Int(flagParallelism.Name)) + parallelismSemaphore := make(chan struct{}, cmd.Int(flagParallelism.Name)) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGTERM, syscall.SIGHUP) @@ -267,7 +268,7 @@ var app = &cli.App{ } func main() { - if err := app.Run(os.Args); err != nil { + if err := app.Run(context.Background(), os.Args); err != nil { stdlog.Fatal(err) } } diff --git a/go.mod b/go.mod index df3e96a..19111c8 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,31 @@ module github.com/spacelift-io/vcs-agent -go 1.23 +go 1.24 require ( github.com/bugsnag/bugsnag-go/v2 v2.5.1 - github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf github.com/go-kit/log v0.2.1 github.com/kr/text v0.2.0 - github.com/onsi/gomega v1.36.2 github.com/pkg/errors v0.9.1 - github.com/spacelift-io/spcontext v0.0.6 + github.com/spacelift-io/spcontext v0.0.7 github.com/stretchr/testify v1.10.0 - github.com/urfave/cli/v2 v2.27.5 - google.golang.org/grpc v1.70.0 - google.golang.org/protobuf v1.36.5 + github.com/urfave/cli/v3 v3.3.3 + google.golang.org/grpc v1.72.0 + google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/bugsnag/panicwrap v1.3.4 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect ) diff --git a/go.sum b/go.sum index e649405..d6526f4 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,6 @@ github.com/bugsnag/panicwrap v1.3.4/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywR github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -34,8 +32,6 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -45,10 +41,8 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -64,10 +58,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= -github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -76,11 +68,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spacelift-io/spcontext v0.0.6 h1:7xAi6qZ+YMXZcDoV5nHAPvNDtafyZsXYsq8oG12BO0w= -github.com/spacelift-io/spcontext v0.0.6/go.mod h1:z/au6cdGfO1VxsjVKcqQCe4J9WI1juUwBCnKTGMJf6s= +github.com/spacelift-io/spcontext v0.0.7 h1:ROqOJm5DtOJCyJRkDtqN2uv+IGo0AozGB7G9sTHoFrw= +github.com/spacelift-io/spcontext v0.0.7/go.mod h1:z/au6cdGfO1VxsjVKcqQCe4J9WI1juUwBCnKTGMJf6s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -91,22 +81,22 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= -github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I= +github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -129,8 +119,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -143,12 +133,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -158,8 +148,6 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -169,17 +157,17 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/logging/http_client.go b/logging/http_client.go index 59499b6..fce2ac9 100644 --- a/logging/http_client.go +++ b/logging/http_client.go @@ -41,7 +41,7 @@ func (cli *HTTPClient) Do(req *http.Request) (*http.Response, error) { req.Body = io.NopCloser(bytes.NewReader(data)) dataToLog := maybeJSONFromBody(data) - fmt.Fprintf(reqWriter, interpretControlSequences(string(dataToLog))+"\n") + _, _ = fmt.Fprintf(reqWriter, "%s\n", interpretControlSequences(string(dataToLog))) buffer.Write([]byte("\n")) } @@ -52,7 +52,7 @@ func (cli *HTTPClient) Do(req *http.Request) (*http.Response, error) { return res, resErr } - fmt.Fprintf(resWriter, "%s\n", res.Status) + _, _ = fmt.Fprintf(resWriter, "%s\n", res.Status) printHeaders(resWriter, res.Header) data, err := io.ReadAll(res.Body) if err != nil { @@ -61,8 +61,8 @@ func (cli *HTTPClient) Do(req *http.Request) (*http.Response, error) { res.Body = io.NopCloser(bytes.NewReader(data)) dataToLog := maybeJSONFromBody(data) - fmt.Fprintf(resWriter, interpretControlSequences(string(dataToLog))+"\n") - fmt.Fprintf(buffer, "\n") + _, _ = fmt.Fprintf(resWriter, "%s\n", interpretControlSequences(string(dataToLog))) + _, _ = fmt.Fprintf(buffer, "\n") return res, nil } diff --git a/privatevcs/validation/blocklist/list_test.go b/privatevcs/validation/blocklist/list_test.go index 1b16801..59364a0 100644 --- a/privatevcs/validation/blocklist/list_test.go +++ b/privatevcs/validation/blocklist/list_test.go @@ -4,126 +4,102 @@ import ( "net/http" "testing" - "github.com/franela/goblin" "github.com/go-kit/log" - . "github.com/onsi/gomega" "github.com/spacelift-io/spcontext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/spacelift-io/vcs-agent/privatevcs/validation/blocklist" ) -func TestList(t *testing.T) { - g := goblin.Goblin(t) - RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) - - g.Describe("List", func() { - var sut *blocklist.List - - g.Describe("Load", func() { - var err error - var path string - - g.JustBeforeEach(func() { sut, err = blocklist.Load(path) }) - - g.Describe("with an invalid path", func() { - g.BeforeEach(func() { path = "fixtures/not.there" }) - - g.It("should return an error", func() { - Expect(sut).To(BeNil()) - Expect(err).To(MatchError(`couldn't read the blocklist file "fixtures/not.there": open fixtures/not.there: no such file or directory`)) - }) - }) - - g.Describe("with a duplicate rule", func() { - g.BeforeEach(func() { path = "fixtures/duplicate.yaml" }) - - g.It("should return an error", func() { - Expect(sut).To(BeNil()) - Expect(err).To(MatchError(`invalid blocklist file "fixtures/duplicate.yaml": duplicate rule name "Duplicate"`)) - }) - }) - - g.Describe("with an invalid rule", func() { - g.BeforeEach(func() { path = "fixtures/invalid.yaml" }) - - g.It("should return an error", func() { - Expect(sut).To(BeNil()) - Expect(err).To(MatchError("invalid blocklist file \"fixtures/invalid.yaml\": invalid rule 0: could not compile rule \"Invalid\": invalid path matcher: error parsing regexp: missing closing ]: `[`")) - }) - }) - - g.Describe("with a valid blocklist", func() { - g.BeforeEach(func() { path = "fixtures/valid.yaml" }) - - g.It("should not return an error", func() { - Expect(err).To(BeNil()) - }) - - g.It("should have loaded the rule", func() { - Expect(sut.Rules).To(HaveLen(2)) - }) - }) - }) - - g.Describe("Validate", func() { - var err error - var ctx *spcontext.Context - var req *http.Request - - g.BeforeEach(func() { - ctx = spcontext.New(log.NewNopLogger()) - - req, err = http.NewRequest("GET", "https://example.com/foo", nil) - if err != nil { - panic(err) - } - - sut = new(blocklist.List) - }) - - g.JustBeforeEach(func() { _, err = sut.Validate(ctx, "", req) }) - - g.Describe("with an empty list (default)", func() { - g.It("should pass validation", func() { - Expect(err).To(BeNil()) - }) - }) - - g.Describe("with a non-matching rule", func() { - g.BeforeEach(func() { - sut.Rules = []*blocklist.Rule{{ - Name: "NonMatching", - Method: "POST", - Path: ".*", - }} - - if err := sut.Compile(); err != nil { - panic(err) - } - }) - - g.It("should pass validation", func() { - Expect(err).To(BeNil()) - }) - }) - - g.Describe("with a matching rule", func() { - g.BeforeEach(func() { - sut.Rules = []*blocklist.Rule{{ - Name: "Matching", - Method: "GET", - Path: "/foo", - }} - - if err := sut.Compile(); err != nil { - panic(err) - } - }) - - g.It("should fail validation", func() { - Expect(err).To(MatchError(`request blocked by rule "Matching"`)) - }) - }) - }) +func TestListLoad(t *testing.T) { + t.Run("with an invalid path", func(t *testing.T) { + path := "fixtures/not.there" + + sut, err := blocklist.Load(path) + + assert.Nil(t, sut) + assert.EqualError(t, err, `couldn't read the blocklist file "fixtures/not.there": open fixtures/not.there: no such file or directory`) + }) + + t.Run("with a duplicate rule", func(t *testing.T) { + path := "fixtures/duplicate.yaml" + + sut, err := blocklist.Load(path) + + assert.Nil(t, sut) + assert.EqualError(t, err, `invalid blocklist file "fixtures/duplicate.yaml": duplicate rule name "Duplicate"`) + }) + + t.Run("with an invalid rule", func(t *testing.T) { + path := "fixtures/invalid.yaml" + + sut, err := blocklist.Load(path) + + assert.Nil(t, sut) + assert.EqualError(t, err, "invalid blocklist file \"fixtures/invalid.yaml\": invalid rule 0: could not compile rule \"Invalid\": invalid path matcher: error parsing regexp: missing closing ]: `[`") + }) + + t.Run("with a valid blocklist", func(t *testing.T) { + path := "fixtures/valid.yaml" + + sut, err := blocklist.Load(path) + + assert.NoError(t, err) + assert.Len(t, sut.Rules, 2) }) } + +func TestListValidate(t *testing.T) { + t.Run("with an empty list (default)", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + req, err := http.NewRequest("GET", "https://example.com/foo", nil) + require.NoError(t, err, "failed to create request") + + sut := new(blocklist.List) + + _, err = sut.Validate(ctx, "", req) + + assert.NoError(t, err) + }) + + t.Run("with a non-matching rule", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + req, err := http.NewRequest("GET", "https://example.com/foo", nil) + require.NoError(t, err, "failed to create request") + + sut := new(blocklist.List) + sut.Rules = []*blocklist.Rule{{ + Name: "NonMatching", + Method: "POST", + Path: ".*", + }} + + err = sut.Compile() + require.NoError(t, err, "failed to compile rules") + + _, err = sut.Validate(ctx, "", req) + + assert.NoError(t, err) + }) + + t.Run("with a matching rule", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + req, err := http.NewRequest("GET", "https://example.com/foo", nil) + require.NoError(t, err, "failed to create request") + + sut := new(blocklist.List) + sut.Rules = []*blocklist.Rule{{ + Name: "Matching", + Method: "GET", + Path: "/foo", + }} + + err = sut.Compile() + require.NoError(t, err, "failed to compile rules") + + _, err = sut.Validate(ctx, "", req) + + assert.EqualError(t, err, `request blocked by rule "Matching"`) + }) +} \ No newline at end of file diff --git a/privatevcs/validation/blocklist/rule_test.go b/privatevcs/validation/blocklist/rule_test.go index f7b9da3..cc0729c 100644 --- a/privatevcs/validation/blocklist/rule_test.go +++ b/privatevcs/validation/blocklist/rule_test.go @@ -4,120 +4,120 @@ import ( "net/http" "testing" - "github.com/franela/goblin" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/spacelift-io/vcs-agent/privatevcs/validation/blocklist" ) -func TestRule(t *testing.T) { - g := goblin.Goblin(t) - RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) +func TestRuleValidate(t *testing.T) { + t.Run("with no name (default)", func(t *testing.T) { + sut := new(blocklist.Rule) - g.Describe("Rule", func() { - var sut *blocklist.Rule + err := sut.Validate() - g.BeforeEach(func() { - sut = new(blocklist.Rule) - }) - - g.Describe("Validate", func() { - var err error - - g.JustBeforeEach(func() { err = sut.Validate() }) + assert.EqualError(t, err, "rule name is required") + }) - g.Describe("with no name (default)", func() { - g.It("should return an error", func() { - Expect(err).To(MatchError("rule name is required")) - }) - }) + t.Run("with a name", func(t *testing.T) { + t.Run("with invalid method regexp", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "[" - g.Describe("with a name", func() { - g.BeforeEach(func() { sut.Name = "foo" }) + err := sut.Validate() - g.Describe("with invalid method regexp", func() { - g.BeforeEach(func() { sut.Method = "[" }) + assert.EqualError(t, err, "could not compile rule \"foo\": invalid method matcher: error parsing regexp: missing closing ]: `[`") + }) - g.It("should return an error", func() { - Expect(err).To(MatchError("could not compile rule \"foo\": invalid method matcher: error parsing regexp: missing closing ]: `[`")) - }) - }) + t.Run("with valid method regexp", func(t *testing.T) { + t.Run("with invalid path regexp", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "GET" + sut.Path = "[" - g.Describe("with valid method regexp", func() { - g.BeforeEach(func() { sut.Method = "GET" }) + err := sut.Validate() - g.Describe("with invalid path regexp", func() { - g.BeforeEach(func() { sut.Path = "[" }) + assert.EqualError(t, err, "could not compile rule \"foo\": invalid path matcher: error parsing regexp: missing closing ]: `[`") + }) - g.It("should return an error", func() { - Expect(err).To(MatchError("could not compile rule \"foo\": invalid path matcher: error parsing regexp: missing closing ]: `[`")) - }) - }) + t.Run("with valid path regexp", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "GET" + sut.Path = ".*" - g.Describe("with valid path regexp", func() { - g.BeforeEach(func() { sut.Path = ".*" }) + err := sut.Validate() - g.It("should not return an error", func() { - Expect(err).ToNot(HaveOccurred()) - }) - }) - }) + assert.NoError(t, err) }) }) + }) +} - g.Describe("Matches", func() { - var match bool - var req *http.Request +func TestRuleMatches(t *testing.T) { + // Create a common test request + req, err := http.NewRequest("GET", "https://example.com/foo", nil) + require.NoError(t, err, "failed to create request") - g.BeforeEach(func() { - sut.Name = "foo" + t.Run("with a matching method", func(t *testing.T) { + t.Run("with a matching path", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "GET" + sut.Path = ".*" - var err error - req, err = http.NewRequest("GET", "https://example.com/foo", nil) + err := sut.Validate() + require.NoError(t, err, "failed to validate rule") - if err != nil { - panic(err) - } - }) + match := sut.Matches(req) - g.JustBeforeEach(func() { - if err := sut.Validate(); err != nil { - panic(err) - } - match = sut.Matches(req) - }) + assert.True(t, match) + }) - g.Describe("with a matching method", func() { - g.BeforeEach(func() { sut.Method = "GET" }) + t.Run("with a non-matching path", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "GET" + sut.Path = "/bar" - g.Describe("with a matching path", func() { - g.BeforeEach(func() { sut.Path = ".*" }) + err := sut.Validate() + require.NoError(t, err, "failed to validate rule") - g.It("should return true", func() { Expect(match).To(BeTrue()) }) - }) + match := sut.Matches(req) - g.Describe("with a non-matching path", func() { - g.BeforeEach(func() { sut.Path = "/bar" }) + assert.False(t, match) + }) + }) - g.It("should return false", func() { Expect(match).To(BeFalse()) }) - }) - }) + t.Run("with a non-matching method", func(t *testing.T) { + t.Run("with a matching path", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "POST" + sut.Path = ".*" - g.Describe("with a non-matching method", func() { - g.BeforeEach(func() { sut.Method = "POST" }) + err := sut.Validate() + require.NoError(t, err, "failed to validate rule") - g.Describe("with a matching path", func() { - g.BeforeEach(func() { sut.Path = ".*" }) + match := sut.Matches(req) - g.It("should return false", func() { Expect(match).To(BeFalse()) }) - }) + assert.False(t, match) + }) - g.Describe("with a non-matching path", func() { - g.BeforeEach(func() { sut.Path = "/bar" }) + t.Run("with a non-matching path", func(t *testing.T) { + sut := new(blocklist.Rule) + sut.Name = "foo" + sut.Method = "POST" + sut.Path = "/bar" - g.It("should return false", func() { Expect(match).To(BeFalse()) }) - }) - }) + err := sut.Validate() + require.NoError(t, err, "failed to validate rule") + + match := sut.Matches(req) + + assert.False(t, match) }) }) -} +} \ No newline at end of file diff --git a/privatevcs/validation/codeload_test.go b/privatevcs/validation/codeload_test.go index 27e41a8..4900c20 100644 --- a/privatevcs/validation/codeload_test.go +++ b/privatevcs/validation/codeload_test.go @@ -4,81 +4,75 @@ import ( "net/http" "testing" - "github.com/franela/goblin" "github.com/go-kit/log" - . "github.com/onsi/gomega" "github.com/spacelift-io/spcontext" + "github.com/stretchr/testify/assert" "github.com/spacelift-io/vcs-agent/privatevcs/validation" ) func TestRewriteGitHubTarballRequest(t *testing.T) { - g := goblin.Goblin(t) - RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) + t.Run("when not a GitHub request", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + vendor := validation.GitLab + url := "https://gitlab.com/foo/bar" - g.Describe("RewriteGitHubTarballRequest", func() { - var ctx *spcontext.Context - var req *http.Request - var url string - var vendor validation.Vendor + req, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } - g.BeforeEach(func() { - ctx = spcontext.New(log.NewNopLogger()) - }) + ctx = validation.RewriteGitHubTarballRequest(ctx, vendor, req) + + assert.Equal(t, "gitlab.com", req.URL.Host) + }) - g.JustBeforeEach(func() { - var err error + t.Run("when a GitHub request", func(t *testing.T) { + t.Run("when the request is not a tarball download request", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + vendor := validation.GitHubEnterprise + url := "https://github.corp.com/api/v3/repos/octocats/infra/deployments" - if req, err = http.NewRequest("GET", url, nil); err != nil { - panic(err) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) } ctx = validation.RewriteGitHubTarballRequest(ctx, vendor, req) + + assert.Equal(t, "github.corp.com", req.URL.Host) }) - g.Describe("when not a GitHub request", func() { - g.BeforeEach(func() { - vendor = validation.GitLab - url = "https://gitlab.com/foo/bar" - }) + t.Run("when the request is a tarball download request", func(t *testing.T) { + t.Run("with codeload isolation disabled", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + vendor := validation.GitHubEnterprise + url := "https://github.corp.com/_codeload/octocats/infra/legacy.tar.gz/master" - g.It("should not rewrite the request", func() { - Expect(req.URL.Host).To(Equal("gitlab.com")) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + ctx = validation.RewriteGitHubTarballRequest(ctx, vendor, req) + + assert.Equal(t, "github.corp.com", req.URL.Host) }) - }) - g.Describe("when a GitHub request", func() { - g.BeforeEach(func() { vendor = validation.GitHubEnterprise }) + t.Run("with codeload isolation enabled", func(t *testing.T) { + ctx := spcontext.New(log.NewNopLogger()) + vendor := validation.GitHubEnterprise + url := "https://github.corp.com/octocats/infra/legacy.tar.gz/master" - g.Describe("when the request is not a tarball download request", func() { - g.BeforeEach(func() { url = "https://github.corp.com/api/v3/repos/octocats/infra/deployments" }) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } - g.It("should not rewrite the request", func() { - Expect(req.URL.Host).To(Equal("github.corp.com")) - }) - }) + ctx = validation.RewriteGitHubTarballRequest(ctx, vendor, req) - g.Describe("when the request is a tarball download request", func() { - g.Describe("with codeload isolation disabled", func() { - g.BeforeEach(func() { - url = "https://github.corp.com/_codeload/octocats/infra/legacy.tar.gz/master" - }) - - g.It("should not rewrite the request", func() { - Expect(req.URL.Host).To(Equal("github.corp.com")) - }) - }) - - g.Describe("with codeload isolation enabled", func() { - g.BeforeEach(func() { - url = "https://github.corp.com/octocats/infra/legacy.tar.gz/master" - }) - - g.It("should rewrite the request", func() { - Expect(req.URL.Host).To(Equal("codeload.github.corp.com")) - }) - }) + assert.Equal(t, "codeload.github.corp.com", req.URL.Host) }) }) }) -} +} \ No newline at end of file