diff --git a/go.mod b/go.mod
index d75952476..375d20b51 100644
--- a/go.mod
+++ b/go.mod
@@ -24,8 +24,8 @@ require (
github.com/mattn/go-sqlite3 v1.14.52
github.com/ncw/swift v1.0.53
github.com/okta/okta-jwt-verifier-golang v1.3.1
- github.com/onsi/ginkgo/v2 v2.28.1
- github.com/onsi/gomega v1.39.1
+ github.com/onsi/ginkgo/v2 v2.32.2
+ github.com/onsi/gomega v1.43.0
github.com/pborman/uuid v1.2.1
github.com/prometheus/client_golang v1.24.1
github.com/spf13/cobra v1.10.2
@@ -43,7 +43,7 @@ require (
cloud.google.com/go/compute/metadata v0.9.0 // indirect
filippo.io/edwards25519 v1.2.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
- github.com/Masterminds/semver/v3 v3.4.0 // indirect
+ github.com/Masterminds/semver/v3 v3.5.0 // indirect
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20 // indirect
@@ -78,7 +78,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.2.0 // indirect
- github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
+ github.com/google/pprof v0.0.0-20260906184651-6331bc6350fe // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.22 // indirect
diff --git a/go.sum b/go.sum
index 9a708016a..ee97b1363 100644
--- a/go.sum
+++ b/go.sum
@@ -13,8 +13,8 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg6
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/ErikDubbelboer/gspt v0.0.0-20210805194459-ce36a5128377 h1:Mb5TnfGwwshqu2BNNJnk6gkXbdvbNCi8FeWEW/jAqtI=
github.com/ErikDubbelboer/gspt v0.0.0-20210805194459-ce36a5128377/go.mod h1:01yGrV5aDnYieX2hSBoKGMaRiqHvnLoUy4ngWGZ/owg=
-github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
-github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
+github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 h1:0kQAzHq8vLs7Pptv+7TxjdETLf/nIqJpIB4oC6Ba4vY=
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29/go.mod h1:ZWa7ssZJT30CCDGJ7fk/2SBTq9BIQrrVjrcss0UW2s0=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -141,8 +141,8 @@ github.com/google/go-github/v76 v76.0.0/go.mod h1:38+d/8pYDO4fBLYfBhXF5EKO0wA3Uk
github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
-github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
+github.com/google/pprof v0.0.0-20260906184651-6331bc6350fe h1:QAinXoAFJdGQYztXn3VpFey7KCwpedbZ/EkzbplQ0cY=
+github.com/google/pprof v0.0.0-20260906184651-6331bc6350fe/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -309,10 +309,10 @@ github.com/okta/okta-jwt-verifier-golang v1.3.1 h1:V+9W5KD3nG7xN0UYtnzXtkurGcs71
github.com/okta/okta-jwt-verifier-golang v1.3.1/go.mod h1:cHffA777f7Yi4K+yDzUp89sGD5v8sk04Pc3CiT1OMR8=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
-github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
-github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
-github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
+github.com/onsi/ginkgo/v2 v2.32.2 h1:2o6vyFvR6snrJWgRVztC+OwuqqPEMI1UzYl2s2iU7Cg=
+github.com/onsi/ginkgo/v2 v2.32.2/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
+github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU=
+github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
diff --git a/vendor/github.com/Masterminds/semver/v3/.gitignore b/vendor/github.com/Masterminds/semver/v3/.gitignore
index 6b061e617..35f0e5a3a 100644
--- a/vendor/github.com/Masterminds/semver/v3/.gitignore
+++ b/vendor/github.com/Masterminds/semver/v3/.gitignore
@@ -1 +1,2 @@
-_fuzz/
\ No newline at end of file
+_fuzz/
+.devcontainer/
\ No newline at end of file
diff --git a/vendor/github.com/Masterminds/semver/v3/.golangci.yml b/vendor/github.com/Masterminds/semver/v3/.golangci.yml
index fbc633259..24277f3ac 100644
--- a/vendor/github.com/Masterminds/semver/v3/.golangci.yml
+++ b/vendor/github.com/Masterminds/semver/v3/.golangci.yml
@@ -1,27 +1,42 @@
-run:
- deadline: 2m
-
+version: "2"
linters:
- disable-all: true
+ default: none
enable:
- - misspell
- - govet
- - staticcheck
+ - dupl
- errcheck
- - unparam
+ - gocyclo
+ - gosec
+ - govet
- ineffassign
+ - misspell
- nakedret
- - gocyclo
- - dupl
- - goimports
- revive
- - gosec
- - gosimple
- - typecheck
+ - staticcheck
+ - unparam
- unused
-
-linters-settings:
- gofmt:
- simplify: true
- dupl:
- threshold: 600
+ settings:
+ dupl:
+ threshold: 600
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
+formatters:
+ enable:
+ - goimports
+ settings:
+ gofmt:
+ simplify: true
+ exclusions:
+ generated: lax
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
diff --git a/vendor/github.com/Masterminds/semver/v3/constraints.go b/vendor/github.com/Masterminds/semver/v3/constraints.go
index 8b7a10f83..e8353bc46 100644
--- a/vendor/github.com/Masterminds/semver/v3/constraints.go
+++ b/vendor/github.com/Masterminds/semver/v3/constraints.go
@@ -21,21 +21,43 @@ type Constraints struct {
IncludePrerelease bool
}
+// MaxConstraintLen is the maximum allowed length of a constraint string.
+const MaxConstraintLen = 512
+
+// MaxConstraintGroups is the maximum number of OR groups allowed in a
+// constraint string.
+const MaxConstraintGroups = 32
+
+// ErrConstraintTooLong is returned when a constraint string exceeds the
+// maximum allowed length.
+var ErrConstraintTooLong = fmt.Errorf("constraint string is too long (max %d bytes)", MaxConstraintLen)
+
+// ErrTooManyConstraintGroups is returned when a constraint string contains
+// too many OR groups.
+var ErrTooManyConstraintGroups = fmt.Errorf("too many constraint groups (max %d)", MaxConstraintGroups)
+
// NewConstraint returns a Constraints instance that a Version instance can
// be checked against. If there is a parse error it will be returned.
func NewConstraint(c string) (*Constraints, error) {
+ if len(c) > MaxConstraintLen {
+ return nil, ErrConstraintTooLong
+ }
+
// Rewrite - ranges into a comparison operation.
c = rewriteRange(c)
ors := strings.Split(c, "||")
+ if len(ors) > MaxConstraintGroups {
+ return nil, ErrTooManyConstraintGroups
+ }
lenors := len(ors)
or := make([][]*constraint, lenors)
hasPre := make([]bool, lenors)
for k, v := range ors {
// Validate the segment
if !validConstraintRegex.MatchString(v) {
- return nil, fmt.Errorf("improper constraint: %s", v)
+ return nil, fmt.Errorf("improper constraint: %q", v)
}
cs := findConstraintRegex.FindAllString(v, -1)
@@ -104,9 +126,9 @@ func (cs Constraints) Validate(v *Version) (bool, []error) {
for _, c := range o {
// Before running the check handle the case there the version is
// a prerelease and the check is not searching for prereleases.
- if !(cs.IncludePrerelease || cs.containsPre[i]) && v.pre != "" {
+ if !cs.IncludePrerelease && !cs.containsPre[i] && v.pre != "" {
if !prerelesase {
- em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ em := fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
e = append(e, em)
prerelesase = true
}
@@ -258,7 +280,7 @@ func parseConstraint(c string) (*constraint, error) {
if len(c) > 0 {
m := constraintRegex.FindStringSubmatch(c)
if m == nil {
- return nil, fmt.Errorf("improper constraint: %s", c)
+ return nil, fmt.Errorf("improper constraint: %q", c)
}
cs := &constraint{
@@ -325,7 +347,7 @@ func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
if c.dirty {
@@ -335,7 +357,7 @@ func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error
if c.con.Minor() != v.Minor() && !c.minorDirty {
return true, nil
} else if c.minorDirty {
- return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is equal to %q", v, c.orig)
} else if c.con.Patch() != v.Patch() && !c.patchDirty {
return true, nil
} else if c.patchDirty {
@@ -345,15 +367,15 @@ func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is equal to %q", v, c.orig)
}
- return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is equal to %q", v, c.orig)
}
}
eq := v.Equal(c.con)
if eq {
- return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is equal to %q", v, c.orig)
}
return true, nil
@@ -364,7 +386,7 @@ func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, er
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
var eq bool
@@ -374,17 +396,17 @@ func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, er
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig)
}
if v.Major() > c.con.Major() {
return true, nil
} else if v.Major() < c.con.Major() {
- return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig)
} else if c.minorDirty {
// This is a range case such as >11. When the version is something like
// 11.1.0 is it not > 11. For that we would need 12 or higher
- return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig)
} else if c.patchDirty {
// This is for ranges such as >11.1. A version of 11.1.1 is not greater
// which one of 11.2.1 is greater
@@ -392,7 +414,7 @@ func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, er
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig)
}
// If we have gotten here we are not comparing pre-preleases and can use the
@@ -401,21 +423,21 @@ func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, er
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig)
}
func constraintLessThan(v *Version, c *constraint, includePre bool) (bool, error) {
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
eq := v.Compare(c.con) < 0
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is greater than or equal to %q", v, c.orig)
}
func constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {
@@ -423,21 +445,21 @@ func constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (boo
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
eq := v.Compare(c.con) >= 0
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is less than %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than %q", v, c.orig)
}
func constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
var eq bool
@@ -447,13 +469,13 @@ func constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool,
if eq {
return true, nil
}
- return false, fmt.Errorf("%s is greater than %s", v, c.orig)
+ return false, fmt.Errorf("%q is greater than %q", v, c.orig)
}
if v.Major() > c.con.Major() {
- return false, fmt.Errorf("%s is greater than %s", v, c.orig)
+ return false, fmt.Errorf("%q is greater than %q", v, c.orig)
} else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty {
- return false, fmt.Errorf("%s is greater than %s", v, c.orig)
+ return false, fmt.Errorf("%q is greater than %q", v, c.orig)
}
return true, nil
@@ -469,11 +491,11 @@ func constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) {
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
if v.LessThan(c.con) {
- return false, fmt.Errorf("%s is less than %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than %q", v, c.orig)
}
// ~0.0.0 is a special case where all constraints are accepted. It's
@@ -484,11 +506,11 @@ func constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) {
}
if v.Major() != c.con.Major() {
- return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
+ return false, fmt.Errorf("%q does not have same major version as %q", v, c.orig)
}
if v.Minor() != c.con.Minor() && !c.minorDirty {
- return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig)
+ return false, fmt.Errorf("%q does not have same major and minor version as %q", v, c.orig)
}
return true, nil
@@ -500,7 +522,7 @@ func constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, e
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
if c.dirty {
@@ -512,7 +534,7 @@ func constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, e
return true, nil
}
- return false, fmt.Errorf("%s is not equal to %s", v, c.orig)
+ return false, fmt.Errorf("%q is not equal to %q", v, c.orig)
}
// ^* --> (any)
@@ -528,12 +550,12 @@ func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {
// The existence of prereleases is checked at the group level and passed in.
// Exit early if the version has a prerelease but those are to be ignored.
if v.Prerelease() != "" && !includePre {
- return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v)
}
// This less than handles prereleases
if v.LessThan(c.con) {
- return false, fmt.Errorf("%s is less than %s", v, c.orig)
+ return false, fmt.Errorf("%q is less than %q", v, c.orig)
}
var eq bool
@@ -548,12 +570,12 @@ func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {
if eq {
return true, nil
}
- return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
+ return false, fmt.Errorf("%q does not have same major version as %q", v, c.orig)
}
// ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1
if c.con.Major() == 0 && v.Major() > 0 {
- return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
+ return false, fmt.Errorf("%q does not have same major version as %q", v, c.orig)
}
// If the con Minor is > 0 it is not dirty
if c.con.Minor() > 0 || c.patchDirty {
@@ -561,11 +583,11 @@ func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {
if eq {
return true, nil
}
- return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig)
+ return false, fmt.Errorf("%q does not have same minor version as %q. Expected minor versions to match when constraint major version is 0", v, c.orig)
}
// ^ when the minor is 0 and minor > 0 is =0.0.z
if c.con.Minor() == 0 && v.Minor() > 0 {
- return false, fmt.Errorf("%s does not have same minor version as %s", v, c.orig)
+ return false, fmt.Errorf("%q does not have same minor version as %q", v, c.orig)
}
// At this point the major is 0 and the minor is 0 and not dirty. The patch
@@ -574,7 +596,7 @@ func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {
if eq {
return true, nil
}
- return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig)
+ return false, fmt.Errorf("%q does not equal %q. Expect version and constraint to equal when major and minor versions are 0", v, c.orig)
}
func isX(x string) bool {
diff --git a/vendor/github.com/Masterminds/semver/v3/version.go b/vendor/github.com/Masterminds/semver/v3/version.go
index 7a3ba7388..da428760c 100644
--- a/vendor/github.com/Masterminds/semver/v3/version.go
+++ b/vendor/github.com/Masterminds/semver/v3/version.go
@@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "math"
"regexp"
"strconv"
"strings"
@@ -48,8 +49,16 @@ var (
// ErrInvalidPrerelease is returned when the pre-release is an invalid format
ErrInvalidPrerelease = errors.New("invalid prerelease string")
+
+ // ErrVersionTooLong is returned when a version string exceeds the
+ // maximum allowed length.
+ ErrVersionTooLong = fmt.Errorf("version string is too long (max %d bytes)", MaxVersionLen)
)
+// MaxVersionLen is the maximum allowed length of a version string. This guards
+// against unbounded input causing excessive memory allocations during parsing.
+const MaxVersionLen = 256
+
// semVerRegex is the regular expression used to parse a semantic version.
// This is not the official regex from the semver spec. It has been modified to allow for loose handling
// where versions like 2.1 are detected.
@@ -94,6 +103,10 @@ func StrictNewVersion(v string) (*Version, error) {
return nil, ErrEmptyString
}
+ if len(v) > MaxVersionLen {
+ return nil, ErrVersionTooLong
+ }
+
// Split the parts into [0]major, [1]minor, and [2]patch,prerelease,build
parts := strings.SplitN(v, ".", 3)
if len(parts) != 3 {
@@ -161,6 +174,9 @@ func StrictNewVersion(v string) (*Version, error) {
// attempts to convert it to SemVer. If you want to validate it was a strict
// semantic version at parse time see StrictNewVersion().
func NewVersion(v string) (*Version, error) {
+ if len(v) > MaxVersionLen {
+ return nil, ErrVersionTooLong
+ }
if CoerceNewVersion {
return coerceNewVersion(v)
}
@@ -289,6 +305,8 @@ func coerceNewVersion(v string) (*Version, error) {
// New creates a new instance of Version with each of the parts passed in as
// arguments instead of parsing a version string.
+// Note, New does not validate prerelease or metadata. Incorrect information can
+// be passed in.
func New(major, minor, patch uint64, pre, metadata string) *Version {
v := Version{
major: major,
@@ -301,6 +319,7 @@ func New(major, minor, patch uint64, pre, metadata string) *Version {
v.original = v.String()
+ // TODO: In the next semver major version validate the pre and metadata. Return error if there is one.
return &v
}
@@ -388,6 +407,9 @@ func (v Version) IncPatch() Version {
} else {
vNext.metadata = ""
vNext.pre = ""
+ if v.patch == math.MaxUint64 {
+ panic("patch version increment would overflow uint64")
+ }
vNext.patch = v.patch + 1
}
vNext.original = v.originalVPrefix() + "" + vNext.String()
@@ -404,6 +426,9 @@ func (v Version) IncMinor() Version {
vNext.metadata = ""
vNext.pre = ""
vNext.patch = 0
+ if v.minor == math.MaxUint64 {
+ panic("minor version increment would overflow uint64")
+ }
vNext.minor = v.minor + 1
vNext.original = v.originalVPrefix() + "" + vNext.String()
return vNext
@@ -421,6 +446,9 @@ func (v Version) IncMajor() Version {
vNext.pre = ""
vNext.patch = 0
vNext.minor = 0
+ if v.major == math.MaxUint64 {
+ panic("major version increment would overflow uint64")
+ }
vNext.major = v.major + 1
vNext.original = v.originalVPrefix() + "" + vNext.String()
return vNext
@@ -568,7 +596,16 @@ func (v Version) MarshalText() ([]byte, error) {
// Scan implements the SQL.Scanner interface.
func (v *Version) Scan(value interface{}) error {
var s string
- s, _ = value.(string)
+ switch t := value.(type) {
+ case string:
+ s = t
+ case []byte:
+ s = string(t)
+ case nil:
+ return fmt.Errorf("cannot scan nil into Version")
+ default:
+ return fmt.Errorf("unsupported Scan type %T", value)
+ }
temp, err := NewVersion(s)
if err != nil {
return err
diff --git a/vendor/github.com/google/pprof/profile/merge.go b/vendor/github.com/google/pprof/profile/merge.go
index 8a51690be..5e6c80bf0 100644
--- a/vendor/github.com/google/pprof/profile/merge.go
+++ b/vendor/github.com/google/pprof/profile/merge.go
@@ -328,10 +328,10 @@ func (l *Location) key() locationKey {
lines := make([]string, len(l.Line)*3)
for i, line := range l.Line {
if line.Function != nil {
- lines[i*2] = strconv.FormatUint(line.Function.ID, 16)
+ lines[i*3] = strconv.FormatUint(line.Function.ID, 16)
}
- lines[i*2+1] = strconv.FormatInt(line.Line, 16)
- lines[i*2+2] = strconv.FormatInt(line.Column, 16)
+ lines[i*3+1] = strconv.FormatInt(line.Line, 16)
+ lines[i*3+2] = strconv.FormatInt(line.Column, 16)
}
key.lines = strings.Join(lines, "|")
return key
diff --git a/vendor/github.com/google/pprof/profile/profile.go b/vendor/github.com/google/pprof/profile/profile.go
index 18df65a8d..71f9bae93 100644
--- a/vendor/github.com/google/pprof/profile/profile.go
+++ b/vendor/github.com/google/pprof/profile/profile.go
@@ -344,9 +344,11 @@ func serialize(p *Profile) []byte {
// Write writes the profile as a gzip-compressed marshaled protobuf.
func (p *Profile) Write(w io.Writer) error {
zw := gzip.NewWriter(w)
- defer zw.Close()
- _, err := zw.Write(serialize(p))
- return err
+ if _, err := zw.Write(serialize(p)); err != nil {
+ _ = zw.Close()
+ return err
+ }
+ return zw.Close()
}
// WriteUncompressed writes the profile as a marshaled protobuf.
diff --git a/vendor/github.com/onsi/ginkgo/v2/.gitignore b/vendor/github.com/onsi/ginkgo/v2/.gitignore
index 6faaaf315..c9f054620 100644
--- a/vendor/github.com/onsi/ginkgo/v2/.gitignore
+++ b/vendor/github.com/onsi/ginkgo/v2/.gitignore
@@ -1,6 +1,7 @@
.DS_Store
TODO
tmp/**/*
+integration/tmp_*/
*.coverprofile
.vscode
.idea/
diff --git a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
index 70050f35d..45fa53434 100644
--- a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
@@ -1,3 +1,58 @@
+## 2.32.2
+
+### Fixes
+- fix bug where ginkgo -race -p was taking extra long to exit [c6792b0]
+
+## 2.32.1
+
+### Fixes
+- Defer AfterAll until repeated spec completes [e647b3b]
+
+## 2.32.0
+
+`-fd` generate RSpec-style documentation output. Thank @woodie !
+--sleep-on-failure pauses a failed spec before teardown. Thanks @qinqon !
+
+## 2.31.0
+
+Add a bunch of Claude Skills via the marketplace:
+
+```
+/plugin marketplace add onsi/ginkgo
+/plugin install ginkgo@ginkgo
+```
+
+## 2.30.0
+
+### Features
+Ginkgo now allows `extentions/global.Reset` to support running multiple suites from within a single process. This may take some massaging on your part (see [1672](https://github.com/onsi/ginkgo/issues/1672)) but can dramatically speed up codebases with O(hundreds) of test suites.
+
+Thanks @lawrencejones !
+
+### Fixes
+
+- Fix nested --github-output group for progress report nested inside timeline [4f62d7a]
+
+## 2.29.0
+
+`GinkgoHelperGo` makes it easier to write test helpers that need to run in goroutines. Specifically, it makes managing the failure state and capturing failure panics correctly straightforward.
+
+`ginkgo outline` now includes entries defined in `DescribeTableSubtree`
+
+## 2.28.3
+
+### Maintenance
+Bump all dependencies
+
+## 2.28.2
+
+- Add ArtifactDir() to support Go 1.26 testing.TB interface [f3a36b6]
+- Implement shell completion [94151c8]
+- Add asan CLI option mirroring msan implementation [4d21dbb]
+- Bump uri from 1.0.3 to 1.0.4 in /docs (#1630) [c102161]
+- fix aspect ratio [9619647]
+- update logos [5779304]
+
## 2.28.1
Update all dependencies. This auto-updated the required version of Go to 1.24, consistent with the fact that Go 1.23 has been out of support for almost six months.
diff --git a/vendor/github.com/onsi/ginkgo/v2/README.md b/vendor/github.com/onsi/ginkgo/v2/README.md
index b4c3ce0ad..ad5e45f67 100644
--- a/vendor/github.com/onsi/ginkgo/v2/README.md
+++ b/vendor/github.com/onsi/ginkgo/v2/README.md
@@ -106,6 +106,19 @@ And that's just Ginkgo! [Gomega](https://onsi.github.io/gomega/) brings a rich,
Happy Testing!
+## Using Ginkgo with Claude Code
+
+Ginkgo ships a set of [Claude Code](https://claude.com/claude-code) skills as a plugin, with this repo doubling as the marketplace, so an agent writing specs in *your* project has Ginkgo's idioms, decorators, and gotchas on hand. From inside Claude Code:
+
+```
+/plugin marketplace add onsi/ginkgo
+/plugin install ginkgo@ginkgo
+```
+
+(or non-interactively: `claude plugin marketplace add onsi/ginkgo` then `claude plugin install ginkgo@ginkgo`)
+
+This installs a family of `ginkgo:*` skills that activate automatically while you write and run specs. Start with `ginkgo:overview`; see the [plugin README](plugins/ginkgo/README.md) for the full list.
+
## License
Ginkgo is MIT-Licensed
@@ -120,6 +133,6 @@ Sponsors commit to a [sponsorship](https://github.com/sponsors/onsi) for a year.
Browser testing via
-
+
diff --git a/vendor/github.com/onsi/ginkgo/v2/core_dsl.go b/vendor/github.com/onsi/ginkgo/v2/core_dsl.go
index 1c5a39a1f..fb5761c1f 100644
--- a/vendor/github.com/onsi/ginkgo/v2/core_dsl.go
+++ b/vendor/github.com/onsi/ginkgo/v2/core_dsl.go
@@ -39,7 +39,6 @@ var flagSet types.GinkgoFlagSet
var deprecationTracker = types.NewDeprecationTracker()
var suiteConfig = types.NewDefaultSuiteConfig()
var reporterConfig = types.NewDefaultReporterConfig()
-var suiteDidRun = false
var outputInterceptor internal.OutputInterceptor
var client parallel_support.Client
@@ -259,10 +258,10 @@ for more on how specs are parallelized in Ginkgo.
You can also pass suite-level Label() decorators to RunSpecs. The passed-in labels will apply to all specs in the suite.
*/
func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
- if suiteDidRun {
+ if global.SuiteDidRun {
exitIfErr(types.GinkgoErrors.RerunningSuite())
}
- suiteDidRun = true
+ global.SuiteDidRun = true
err := global.PushClone()
if err != nil {
exitIfErr(err)
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go
index c3f6d3a11..53114904c 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go
@@ -1,9 +1,13 @@
package command
import (
+ "bufio"
"fmt"
"io"
+ "maps"
"os"
+ "path/filepath"
+ "slices"
"strings"
"github.com/onsi/ginkgo/v2/formatter"
@@ -158,6 +162,166 @@ func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) {
}
}
+type completionOptions = struct {
+ Complete bool
+ Install bool
+}
+
+func (p *Program) BuildCompletionCommand() Command {
+ opts := completionOptions{}
+ flags, err := types.NewGinkgoFlagSet(
+ types.GinkgoFlags{
+ {Name: "complete", KeyPath: "Complete", Usage: "Generate completion for arguments after --"},
+ {Name: "install", KeyPath: "Install", Usage: "Install shell completion script into $XDG_DATA_HOME, ~/.local/share"},
+ },
+ &opts,
+ types.GinkgoFlagSections{},
+ )
+ if err != nil {
+ panic(err)
+ }
+ return Command{
+ Name: "completion",
+ Usage: "ginkgo completion [-- ]",
+ Flags: flags,
+ ShortDoc: "Generate shell completion",
+ Documentation: `To use install completion script for your shell (bash, fish, zsh).
+Or load completion code by: {{bold}}source <(ginkgo completion ){{/}}.`,
+ Command: func(args []string, completeArgs []string) {
+ p.handleCompletionAndExit(args, completeArgs, opts)
+ },
+ }
+}
+
+func (p Program) generateShellCompletionScript(shell string) (scriptPath string, script string) {
+ switch shell {
+ case "bash":
+ scriptPath = fmt.Sprintf("bash-completion/completions/%s", p.Name)
+ script = fmt.Sprintf(`__%s_complete_bash() {
+ mapfile -t COMPREPLY < <("${COMP_WORDS[0]}" completion --complete bash -- "${COMP_WORDS[@]:1:COMP_CWORD}")
+}
+complete -o bashdefault -o default -F __%[1]s_complete_bash %[1]s
+`, p.Name)
+
+ case "fish":
+ scriptPath = fmt.Sprintf("fish/vendor_completions.d/%s.fish", p.Name)
+ script = fmt.Sprintf(`function __fish_%[1]s_complete
+ set -l args (commandline -opc) (commandline -ct)
+ set -e args[1]
+ %[1]s completion --complete fish -- $args
+end
+complete -c %[1]s -a "(__fish_%[1]s_complete)"
+`, p.Name)
+
+ case "zsh":
+ scriptPath = fmt.Sprintf("zsh/site-functions/_%s", p.Name)
+ script = fmt.Sprintf(`#compdef %[1]s
+_%[1]s() {
+ local -a completions
+ completions=(${(f)"$("${words[1]}" completion --complete zsh -- "${words[@]:1:$((CURRENT-1))}")"})
+ if (( ${#completions[@]} )); then
+ _describe 'completions' completions
+ else
+ _default
+ fi
+}
+compdef _%[1]s %[1]s
+if [ "$funcstack[1]" = "_%[1]s" ]; then
+ _%[1]s
+fi
+`, p.Name)
+
+ case "":
+ AbortWithUsage("Shell is not specified")
+ default:
+ AbortWith("Shell %q is not supported yet. Choose: bash, fish, zsh", shell)
+ }
+
+ return scriptPath, script
+}
+
+func (p Program) handleCompletionAndExit(args, completeArgs []string, opts completionOptions) {
+ writer := p.OutWriter
+ if writer == nil {
+ writer = os.Stdout
+ }
+ buffer := bufio.NewWriter(writer)
+ defer buffer.Flush()
+
+ var shell string
+ if len(args) > 0 {
+ shell = args[0]
+ }
+
+ if !opts.Complete {
+ scriptPath, script := p.generateShellCompletionScript(shell)
+ if opts.Install {
+ dataHomeDir := os.Getenv("XDG_DATA_HOME")
+ if dataHomeDir == "" {
+ userHomeDir, err := os.UserHomeDir()
+ AbortIfError("Failed to find home", err)
+ dataHomeDir = filepath.Join(userHomeDir, ".local/share")
+ }
+ scriptPath = filepath.Join(dataHomeDir, scriptPath)
+ fmt.Fprintf(buffer, "Installing completion script: %v\n", scriptPath)
+ err := os.WriteFile(scriptPath, []byte(script), 0644)
+ AbortIfError("Failed to install completion script", err)
+ } else {
+ buffer.Write([]byte(script))
+ }
+ Abort(AbortDetails{})
+ }
+
+ var lastArg string
+ var result map[string]string
+ if len(completeArgs) > 0 {
+ lastArg = completeArgs[len(completeArgs)-1]
+ }
+
+ if delim := slices.Index(completeArgs, "--"); delim >= 0 && delim != len(completeArgs)-1 {
+ // No completion for pass-through arguments after "--"
+ } else if len(lastArg) > 0 && lastArg[0] == '-' {
+ // Complete flags
+ cmd := &p.DefaultCommand
+ for i := range p.Commands {
+ if p.Commands[i].Name == completeArgs[0] {
+ cmd = &p.Commands[i]
+ break
+ }
+ }
+ result = cmd.Flags.Completion(lastArg)
+ } else if len(completeArgs) <= 1 {
+ // Complete commands
+ result = make(map[string]string, len(p.Commands)+1)
+ for _, cmd := range append(p.Commands, p.DefaultCommand) {
+ if strings.HasPrefix(cmd.Name, lastArg) {
+ result[cmd.Name] = cmd.Usage
+ }
+ }
+ }
+
+ width := 0
+ for suggest := range result {
+ width = max(width, len(suggest))
+ }
+
+ for _, suggest := range slices.Sorted(maps.Keys(result)) {
+ usage := result[suggest]
+ switch {
+ case shell == "bash" && usage != "" && len(result) > 1:
+ fmt.Fprintf(buffer, "%*s (%s)\n", -width-2, suggest, usage)
+ case shell == "fish":
+ fmt.Fprintf(buffer, "%s\t%s\n", suggest, usage)
+ case shell == "zsh":
+ fmt.Fprintf(buffer, "%s:%s\n", suggest, usage)
+ default:
+ fmt.Fprintln(buffer, suggest)
+ }
+ }
+
+ Abort(AbortDetails{})
+}
+
func (p Program) EmitUsage(writer io.Writer) {
fmt.Fprintln(writer, formatter.F(p.Heading))
fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(p.Heading))))
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go
index 419589b48..596c210cf 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go
@@ -41,6 +41,7 @@ func main() {
{Name: "nodot", Deprecation: types.Deprecations.Nodot()},
},
}
+ program.Commands = append(program.Commands, program.BuildCompletionCommand())
program.RunAndExit(os.Args)
}
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go
index 5d8d00bb1..c380bbf21 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go
@@ -163,17 +163,17 @@ func ginkgoNodeFromCallExpr(fset *token.FileSet, ce *ast.CallExpr, ginkgoPackage
n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt)
n.Labels = labelFromCallExpr(ce)
return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName
- case "Context", "Describe", "When", "DescribeTable":
+ case "Context", "Describe", "When", "DescribeTable", "DescribeTableSubtree":
n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt)
n.Labels = labelFromCallExpr(ce)
n.Pending = pendingFromCallExpr(ce)
return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName
- case "FContext", "FDescribe", "FWhen", "FDescribeTable":
+ case "FContext", "FDescribe", "FWhen", "FDescribeTable", "FDescribeTableSubtree":
n.Focused = true
n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt)
n.Labels = labelFromCallExpr(ce)
return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName
- case "PContext", "PDescribe", "PWhen", "XContext", "XDescribe", "XWhen", "PDescribeTable", "XDescribeTable":
+ case "PContext", "PDescribe", "PWhen", "XContext", "XDescribe", "XWhen", "PDescribeTable", "XDescribeTable", "PDescribeTableSubtree", "XDescribeTableSubtree":
n.Pending = true
n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt)
n.Labels = labelFromCallExpr(ce)
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go
index e99d557d1..206043f1d 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go
@@ -54,6 +54,7 @@ func FromASTFile(fset *token.FileSet, src *ast.File) (*outline, error) {
// Node is not a Ginkgo spec or container, so it was not pushed onto the stack, continue
return true
}
+ expandSubtree(lastVisitedGinkgoNode)
stack = stack[0 : len(stack)-1]
return true
})
@@ -128,3 +129,29 @@ func (o *outline) StringIndent(width int) string {
return b.String()
}
+
+// expandSubtree restructures a DescribeTableSubtree node so that each Entry
+// child gets a copy of the subtree's spec nodes as its children. This mirrors
+// the runtime behavior where each Entry generates a container with the specs
+// defined in the DescribeTableSubtree body.
+func expandSubtree(gn *ginkgoNode) {
+ if !strings.Contains(gn.Name, "DescribeTableSubtree") {
+ return
+ }
+ subNodes, entries := splitSubtreeSubnodes(gn.Nodes)
+ gn.Nodes = entries
+ for _, entry := range entries {
+ entry.Nodes = subNodes
+ }
+}
+
+// splitSubtreeSubnodes splits the child nodes of a DescribeTableSubtree into
+// spec/container nodes (defined in the body) and Entry nodes.
+func splitSubtreeSubnodes(nodes []*ginkgoNode) ([]*ginkgoNode, []*ginkgoNode) {
+ for i, node := range nodes {
+ if strings.Contains(node.Name, "Entry") {
+ return nodes[:i], nodes[i:]
+ }
+ }
+ return nodes, nil
+}
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go
index c5091e6de..7b6c2cc22 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go
@@ -39,6 +39,10 @@ func BuildRunCommand() command.Command {
cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig)
command.AbortIfErrors("Ginkgo detected configuration issues:", errors)
+ if types.ReconcileFdOutputConfiguration(reporterConfig, &suiteConfig, &cliConfig) {
+ fmt.Println("--fd is incompatible with parallel runs (-p/-procs) and -randomize-all; ignoring those flags and running specs in series, in declaration order.")
+ }
+
runner := &SpecRunner{
cliConfig: cliConfig,
goFlagsConfig: goFlagsConfig,
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go
index fe1ca3051..c60d7115f 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go
@@ -37,6 +37,10 @@ func BuildWatchCommand() command.Command {
cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig)
command.AbortIfErrors("Ginkgo detected configuration issues:", errors)
+ if types.ReconcileFdOutputConfiguration(reporterConfig, &suiteConfig, &cliConfig) {
+ fmt.Println("--fd is incompatible with parallel runs (-p/-procs) and -randomize-all; ignoring those flags and running specs in series, in declaration order.")
+ }
+
watcher := &SpecWatcher{
cliConfig: cliConfig,
goFlagsConfig: goFlagsConfig,
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go
index 40d1e1ab5..db3e24847 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go
@@ -72,6 +72,7 @@ type GinkgoTInterface interface {
TempDir() string
Attr(key, value string)
Output() io.Writer
+ ArtifactDir() string
}
/*
@@ -196,3 +197,6 @@ func (g *GinkgoTBWrapper) Attr(key, value string) {
func (g *GinkgoTBWrapper) Output() io.Writer {
return g.GinkgoT.Output()
}
+func (g *GinkgoTBWrapper) ArtifactDir() string {
+ return g.GinkgoT.ArtifactDir()
+}
diff --git a/vendor/github.com/onsi/ginkgo/v2/helpergo_dsl.go b/vendor/github.com/onsi/ginkgo/v2/helpergo_dsl.go
new file mode 100644
index 000000000..9d04cc845
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/v2/helpergo_dsl.go
@@ -0,0 +1,143 @@
+package ginkgo
+
+import (
+ "github.com/onsi/ginkgo/v2/internal/global"
+ ginkgotypes "github.com/onsi/ginkgo/v2/types"
+)
+
+// GinkgoHelperGo synchronously calls the specified “helper” function in a new
+// go routine and with a “defer GinkgoRecover()” already in place, passing the
+// function a “helper Fail”. GinkgoHelperGo is typically called from custom test
+// helpers that in turn need to synchronously execute caller-supplied custom
+// test code in a new Go routine while waiting for this new Go routine to
+// terminate (either successfully or failing).
+//
+// GinkgoHelperGo hides the non-trivial details of correctly unblocking the
+// caller's waiting go routine as well as reporting the correct call sites,
+// depending on whether the test helper failed, or the caller-supplied function
+// had its assertions failing or panicked.
+//
+// Let's take the following example of a test helper named “EnsureSprockets”
+// that runs a set of caller-supplied assertions synchronously on a new Go
+// routine and waits for the outcome before returning to the caller of the test
+// helper. This is just using Ginkgo:
+//
+// func EnsureSprockets(sprockets int, assertions func()) {
+// GinkgoHelper()
+// GinkgoHelperGo(func(helperFail func(string, ...int)) {
+// if sprockets == 0 {
+// helperFail("sprockets must not be zero")
+// }
+// assertions()
+// })
+// }
+//
+// And now for an example that additionally uses Gomega assertions.
+//
+// func EnsureSprockets(sprockets int, assertions func()) {
+// GinkgoHelper()
+// GinkgoHelperGo(func(helperFail func(string, ...int)) {
+// g := gomega.NewGomega(helperFail)
+// g.Expect(sprockets).Not(BeZero())
+// assertions()
+// })
+// }
+//
+// The called helper function should make any custom helper-related assertions
+// using the passed “helper Fail”. Gomega users will want to create a new Gomega
+// wired into this helper Fail. It is expected for the helper function at some
+// point to call into a user-supplied function that might contain its own
+// assertions. In the example above, that would be the function passed as
+// assertions.
+//
+// Any failing assertion using the helper Gomega in the helper function will be
+// reported as a fail at the call site of GinkgoHelperGo. Preferably, only
+// custom test helpers call GinkgoHelperGo and thus mark themselves as
+// [GinkgoHelper] also: in this case, the fail will be shown at the call site of
+// the custom test helper.
+//
+// Any other failing assertions inside the caller-supplied custom test code and
+// thus inside the helper function will instead be reported at the location of
+// the failed assertion.
+//
+// If the caller-supplied custom test code panics, GinkgoHelperGo will fail at
+// its call site, or at the call site of the custom test helper if it uses
+// GinkgoHelper, reporting the usual stack trace for the panic, as a plain
+// GinkgoRecover would also do.
+//
+// Important: the Gomega passed to the called function must only be used in
+// assertions belonging to the test helper, but not any user test code called
+// from the test helper. Thus, do not pass the Gomega passed to the helper
+// function further on to any user test code functions.
+func GinkgoHelperGo(fn func(fail func(message string, callerSkip ...int))) {
+ // userPanicked signals that the called user code panicked, such as due to a
+ // failed Gomega assertion.
+ type userPanicked struct{}
+
+ // helperPanicked signals that some helper code assertion panicked in the
+ // separate Go routine and we are expected to Fail the current test with that
+ // reason, but on the caller's Go routine.
+ type helperPanicked string
+
+ GinkgoHelper()
+
+ // possible types of values sent over the result channel:
+ // - nil (untyped): no problem at all, proceed.
+ // - helperPanicked: the message with which to (re)fail in the caller's
+ // go routine.
+ // - userPanicked: indication to (also) fail on the caller's go routine;
+ // the message doesn't matter as the user code fail takes precedence.
+ ch := make(chan any)
+
+ go func() {
+ isHelperPanic := false
+ helperFail := func(message string, callerSkip ...int) {
+ isHelperPanic = true
+ Fail(message, callerSkip...)
+ }
+ // Please note that we cannot simply recover a helper panic before
+ // GinkgoRecover kicks in as then GinkgoRecover would always report the
+ // stack trace only from the place of rethrown panic ... and that's
+ // pretty useless, because it would just consist of the panic rethrow.
+ defer func() {
+ // We need to unblock and immediately fail the waiting caller's
+ // go routine either for a reason, or just "because" when
+ // GinkgoRecover has already failed the current test on the
+ // separate go routine.
+ if global.Failer.GetState() != ginkgotypes.SpecStatePassed {
+ if isHelperPanic {
+ _, failure := global.Failer.Drain()
+ ch <- helperPanicked(failure.Message)
+ } else {
+ // keep the panic failure already recorded by GinkgoRecover.
+ ch <- userPanicked{}
+ }
+ }
+ close(ch) // causes a nil in case there were no panics anywhere.
+ }()
+ // Nota bene: GinkgoRecover always eats any user panic and channel the
+ // panic value into Ginkgo's Failer.Panic(). We can peek at the last
+ // failure recorded, which should be nil if GinkgoRecover didn't swallow
+ // a user code panic. The "problem" with GinkgoRecover is that it turns
+ // any panic value into a string message, so we loose any specific
+ // typing.
+ defer GinkgoRecover()
+
+ fn(helperFail)
+ }()
+
+ // Did we run into trouble?
+ switch v := (<-ch).(type) {
+ case userPanicked:
+ // The message actually is irrelevant, as it comes only second to
+ // the already registered user panic message. We just need Fail to
+ // panic on the caller's go routine in order to unblock the test.
+ Fail("fn panicked", 1)
+ case helperPanicked:
+ // Report the failure on the new go routine instead on the caller's go
+ // routine.
+ Fail(string(v), 1)
+ default:
+ // It's all fine!
+ }
+}
diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/global/init.go b/vendor/github.com/onsi/ginkgo/v2/internal/global/init.go
index 464e3c97f..14d2552b7 100644
--- a/vendor/github.com/onsi/ginkgo/v2/internal/global/init.go
+++ b/vendor/github.com/onsi/ginkgo/v2/internal/global/init.go
@@ -8,6 +8,12 @@ var Suite *internal.Suite
var Failer *internal.Failer
var backupSuite *internal.Suite
+// SuiteDidRun tracks whether RunSpecs has already been invoked for the current global
+// suite. It lives here (rather than in package ginkgo) so that InitializeGlobals can
+// clear it, allowing extensions/globals.Reset to support running multiple suites
+// sequentially in a single process.
+var SuiteDidRun bool
+
func init() {
InitializeGlobals()
}
@@ -15,6 +21,7 @@ func init() {
func InitializeGlobals() {
Failer = internal.NewFailer()
Suite = internal.NewSuite()
+ SuiteDidRun = false
}
func PushClone() error {
diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/group.go b/vendor/github.com/onsi/ginkgo/v2/internal/group.go
index 5e6611334..781adf6fa 100644
--- a/vendor/github.com/onsi/ginkgo/v2/internal/group.go
+++ b/vendor/github.com/onsi/ginkgo/v2/internal/group.go
@@ -211,6 +211,21 @@ func (g *group) isLastSpecWithPair(specID uint, pair runOncePair) bool {
return lastSpecID == specID
}
+func (g *group) willRunAnotherAttempt(isFinalAttempt bool) bool {
+ if isFinalAttempt {
+ return false
+ }
+
+ if g.suite.currentSpecReport.MaxMustPassRepeatedly > 0 {
+ return g.suite.currentSpecReport.State.Is(types.SpecStatePassed)
+ }
+ if g.suite.currentSpecReport.MaxFlakeAttempts > 0 {
+ return g.suite.currentSpecReport.State.Is(types.SpecStateFailureStates)
+ }
+
+ return false
+}
+
func (g *group) attemptSpec(isFinalAttempt bool, spec Spec) bool {
failedInARunOnceBefore := false
pairs := g.runOncePairs[spec.SubjectID()]
@@ -280,10 +295,11 @@ func (g *group) attemptSpec(isFinalAttempt bool, spec Spec) bool {
}
// it's our last chance to run if we're the last spec for our oncePair
isLastSpecWithPair := g.isLastSpecWithPair(spec.SubjectID(), pair)
+ willRunAnotherAttempt := g.willRunAnotherAttempt(isFinalAttempt)
switch g.suite.currentSpecReport.State {
case types.SpecStatePassed: //this attempt is passing...
- return isLastSpecWithPair //...we should run-once if we'this is our last chance
+ return isLastSpecWithPair && !willRunAnotherAttempt //...we should run-once if this is our last chance
case types.SpecStateSkipped: //the spec was skipped by the user...
if isLastSpecWithPair {
return true //...we're the last spec, so we should run the AfterNode
@@ -292,7 +308,7 @@ func (g *group) attemptSpec(isFinalAttempt bool, spec Spec) bool {
return true //...or, a run-once node at our nesting level was skipped which means this is our last chance to run
}
case types.SpecStateFailed, types.SpecStatePanicked, types.SpecStateTimedout: // the spec has failed...
- if isFinalAttempt {
+ if !willRunAnotherAttempt {
if g.continueOnFailure {
return isLastSpecWithPair || failedInARunOnceBefore //...we're configured to continue on failures - so we should only run if we're the last spec for this pair or if we failed in a runOnceBefore (which means we _are_ the last spec to run)
} else {
diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go
index ab9e11372..360606517 100644
--- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go
+++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go
@@ -32,6 +32,7 @@ type ServerHandler struct {
numSuiteDidBegins int
numSuiteDidEnds int
+ procDidEnd []bool
aggregatedReport types.Report
reportHoldingArea []types.SpecReport
}
@@ -42,6 +43,7 @@ func newServerHandler(parallelTotal int, reporter reporters.Reporter) *ServerHan
lock: &sync.Mutex{},
counterLock: &sync.Mutex{},
alives: make([]func() bool, parallelTotal),
+ procDidEnd: make([]bool, parallelTotal),
beforeSuiteState: BeforeSuiteState{Data: nil, State: types.SpecStateInvalid},
parallelTotal: parallelTotal,
@@ -90,6 +92,9 @@ func (handler *ServerHandler) SpecSuiteDidEnd(report types.Report, _ *Void) erro
defer handler.lock.Unlock()
handler.numSuiteDidEnds += 1
+ if proc := report.SuiteConfig.ParallelProcess; proc >= 1 && proc <= handler.parallelTotal {
+ handler.procDidEnd[proc-1] = true
+ }
if handler.numSuiteDidEnds == 1 {
handler.aggregatedReport = report
} else {
@@ -133,9 +138,17 @@ func (handler *ServerHandler) procIsAlive(proc int) bool {
return alive()
}
+func (handler *ServerHandler) procHasFinished(proc int) bool {
+ handler.lock.Lock()
+ didEnd := handler.procDidEnd[proc-1]
+ handler.lock.Unlock()
+
+ return didEnd || !handler.procIsAlive(proc)
+}
+
func (handler *ServerHandler) haveNonprimaryProcsFinished() bool {
for i := 2; i <= handler.parallelTotal; i++ {
- if handler.procIsAlive(i) {
+ if !handler.procHasFinished(i) {
return false
}
}
diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/suite.go b/vendor/github.com/onsi/ginkgo/v2/internal/suite.go
index 57c1cffe7..6c879855e 100644
--- a/vendor/github.com/onsi/ginkgo/v2/internal/suite.go
+++ b/vendor/github.com/onsi/ginkgo/v2/internal/suite.go
@@ -996,6 +996,7 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
} else {
failure.Message, failure.Location, failure.ForwardedPanic, failure.TimelineLocation = failureFromRun.Message, failureFromRun.Location, failureFromRun.ForwardedPanic, failureFromRun.TimelineLocation
suite.reporter.EmitFailure(outcomeFromRun, failure)
+ suite.pauseOnFailureIfRequested(node)
return outcomeFromRun, failure
}
case <-gracePeriodChannel:
@@ -1079,6 +1080,42 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
}
}
+// pauseOnFailureIfRequested pauses the suite at the moment a failure is identified,
+// when the user has set --sleep-on-failure. This hooks directly into runNode's failure
+// path so the pause happens immediately at the point of failure - before any teardown
+// or cleanup runs - leaving the system live for inspection.
+//
+// We only pause for failures in setup and subject nodes (It, Before*, BeforeSuite...),
+// i.e. nodes that run before teardown. Pausing on a failure in a teardown/cleanup or
+// reporting node would be pointless (the system is already being torn down) and could
+// interfere with interrupt handling, so those are skipped.
+//
+// The pause is interruptible: pressing ^C (or any interrupt) ends the pause early and
+// the suite proceeds to run cleanup as usual. It is a no-op if the feature is disabled.
+func (suite *Suite) pauseOnFailureIfRequested(node Node) {
+ if suite.config.SleepOnFailure <= 0 {
+ return
+ }
+ // only pause before teardown - skip teardown/cleanup/reporting nodes
+ if node.NodeType.Is(types.NodeTypesAllowedDuringCleanupInterrupt | types.NodeTypesAllowedDuringReportInterrupt) {
+ return
+ }
+
+ duration := suite.config.SleepOnFailure
+ report := suite.generateProgressReport(false)
+ report.Message = fmt.Sprintf("{{bold}}{{orange}}Paused on failure for up to %s.{{/}}\nThe spec failed and Ginkgo has paused before running any teardown so you can inspect the live system.\nPress {{bold}}^C{{/}} to end the pause and proceed to cleanup.", duration)
+ suite.emitProgressReport(report)
+
+ timer := time.NewTimer(duration)
+ defer timer.Stop()
+ // wait for the pause to elapse, or for the user to interrupt - in which case we end
+ // the pause early and let runNode return so cleanup can proceed
+ select {
+ case <-timer.C:
+ case <-suite.interruptHandler.Status().Channel:
+ }
+}
+
// TODO: search for usages and consider if reporter.EmitFailure() is necessary
func (suite *Suite) failureForLeafNodeWithMessage(node Node, message string) types.Failure {
return types.Failure{
diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go b/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go
index 5704f0fdf..e6fbaee41 100644
--- a/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go
+++ b/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go
@@ -181,6 +181,15 @@ func (t *ginkgoTestingTProxy) TempDir() string {
return tmpDir
}
+func (t *ginkgoTestingTProxy) ArtifactDir() string {
+ artifactDir, err := os.MkdirTemp("", "ginkgo")
+ if err != nil {
+ t.fail(fmt.Sprintf("Failed to create artifact directory: %v", err), 1)
+ return ""
+ }
+ return artifactDir
+}
+
// FullGinkgoTInterface
func (t *ginkgoTestingTProxy) AddReportEntryVisibilityAlways(name string, args ...any) {
finalArgs := []any{internal.Offset(1), types.ReportEntryVisibilityAlways}
diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go
index ef66b2289..f3e15a913 100644
--- a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go
+++ b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go
@@ -31,6 +31,7 @@ type DefaultReporter struct {
specDenoter string
retryDenoter string
formatter formatter.Formatter
+ fdHierarchy []string
runningInParallel bool
lock *sync.Mutex
@@ -82,6 +83,8 @@ func (r *DefaultReporter) SuiteWillBegin(report types.Report) {
if report.SuiteConfig.ParallelTotal > 1 {
r.emit(r.f("- %d procs ", report.SuiteConfig.ParallelTotal))
}
+ } else if r.conf.FdOutput {
+ return
} else {
banner := r.f("Running Suite: %s - %s", report.SuiteDescription, report.SuitePath)
r.emitBlock(banner)
@@ -124,7 +127,7 @@ func (r *DefaultReporter) SuiteWillBegin(report types.Report) {
func (r *DefaultReporter) SuiteDidEnd(report types.Report) {
failures := report.SpecReports.WithState(types.SpecStateFailureStates)
- if len(failures) > 0 {
+ if !r.conf.FdOutput && len(failures) > 0 {
r.emitBlock("\n")
if len(failures) > 1 {
r.emitBlock(r.f("{{red}}{{bold}}Summarizing %d Failures:{{/}}", len(failures)))
@@ -227,6 +230,10 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
return
}
+ if r.conf.FdOutput {
+ r.didRunFd(report)
+ return
+ }
header := r.specDenoter
if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) {
header = fmt.Sprintf("[%s]", report.LeafNodeType)
@@ -358,6 +365,51 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
r.emitDelimiter(0)
}
+func (r *DefaultReporter) didRunFd(report types.SpecReport) {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ if !report.LeafNodeType.Is(types.NodeTypeIt) {
+ return
+ }
+
+ hierarchy := report.ContainerHierarchyTexts
+
+ // blank line when top-level container changes
+ if len(r.fdHierarchy) > 0 &&
+ (len(hierarchy) == 0 || hierarchy[0] != r.fdHierarchy[0]) {
+ fmt.Fprintln(r.writer)
+ }
+
+ // emit newly-diverged container lines
+ divergeAt := 0
+ for divergeAt < len(r.fdHierarchy) && divergeAt < len(hierarchy) &&
+ r.fdHierarchy[divergeAt] == hierarchy[divergeAt] {
+ divergeAt++
+ }
+ for i := divergeAt; i < len(hierarchy); i++ {
+ fmt.Fprintf(r.writer, "%s%s\n", strings.Repeat(" ", i), hierarchy[i])
+ }
+
+ // leaf label
+ depth := len(hierarchy)
+ indent := strings.Repeat(" ", depth)
+ label := report.LeafNodeText
+
+ switch report.State {
+ case types.SpecStateFailed, types.SpecStatePanicked:
+ label = fmt.Sprintf("%s (FAILED)", label)
+ case types.SpecStatePending:
+ label = fmt.Sprintf("%s (PENDING)", label)
+ case types.SpecStateSkipped:
+ label = fmt.Sprintf("%s (SKIPPED)", label)
+ }
+
+ color := r.highlightColorForState(report.State)
+ fmt.Fprintf(r.writer, "%s%s\n", indent, r.f(color+"%s{{/}}", label))
+ r.fdHierarchy = hierarchy
+}
+
func (r *DefaultReporter) highlightColorForState(state types.SpecState) string {
switch state {
case types.SpecStatePassed:
@@ -423,7 +475,7 @@ func (r *DefaultReporter) emitTimeline(indent uint, report types.SpecReport, tim
case types.ReportEntry:
r.emitReportEntry(indent, x)
case types.ProgressReport:
- r.emitProgressReport(indent, false, isVeryVerbose, x)
+ r.emitProgressReport(indent, isVeryVerbose, false, x)
case types.SpecEvent:
if isVeryVerbose || !x.IsOnlyVisibleAtVeryVerbose() || r.conf.ShowNodeEvents {
r.emitSpecEvent(indent, x, isVeryVerbose)
@@ -533,6 +585,7 @@ func (r *DefaultReporter) emitProgressReport(indent uint, emitGinkgoWriterOutput
indent -= 1
}
+ // Emit only top-level groups because github logging cannot handle nested groups correctly.
if r.conf.GithubOutput && emitGroup {
r.emitBlock(r.fi(indent, "::group::Progress Report"))
}
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/config.go b/vendor/github.com/onsi/ginkgo/v2/types/config.go
index f84703604..854fec6a3 100644
--- a/vendor/github.com/onsi/ginkgo/v2/types/config.go
+++ b/vendor/github.com/onsi/ginkgo/v2/types/config.go
@@ -38,6 +38,7 @@ type SuiteConfig struct {
OutputInterceptorMode string
SourceRoots []string
GracePeriod time.Duration
+ SleepOnFailure time.Duration
ParallelProcess int
ParallelTotal int
@@ -94,6 +95,7 @@ type ReporterConfig struct {
GithubOutput bool
SilenceSkips bool
ForceNewlines bool
+ FdOutput bool
JSONReport string
GoJSONReport string
@@ -215,6 +217,7 @@ type GoFlagsConfig struct {
N bool
ModFile string
ModCacheRW bool
+ ASan bool
MSan bool
PkgDir string
Tags string
@@ -292,6 +295,8 @@ var SuiteConfigFlags = GinkgoFlags{
Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."},
{KeyPath: "S.FailOnEmpty", Name: "fail-on-empty", SectionKey: "failure",
Usage: "If set, ginkgo will mark the test suite as failed if no specs are run."},
+ {KeyPath: "S.SleepOnFailure", Name: "sleep-on-failure", SectionKey: "failure", UsageDefaultValue: "0 - disabled",
+ Usage: "If set, ginkgo will pause for this duration after a spec fails - before its teardown (AfterEach/JustAfterEach/DeferCleanup) runs - so you can inspect the live system. Press ^C to end the pause early and proceed to cleanup. Serial only: cannot be combined with -p/--procs."},
{KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."},
@@ -357,7 +362,8 @@ var ReporterConfigFlags = GinkgoFlags{
Usage: "If set, default reporter will not print out skipped tests."},
{KeyPath: "R.ForceNewlines", Name: "force-newlines", SectionKey: "output",
Usage: "If set, default reporter will ensure a newline appears after each test."},
-
+ {KeyPath: "R.FdOutput", Name: "fd", SectionKey: "output",
+ Usage: "If set, emits RSpec-style 'format documentation' output instead of Ginkgo's default output. --fd is exclusive: it overrides -p/-procs and -randomize-all, forcing specs to run serially in declaration order, since fd's hierarchical output can't be rendered sensibly when specs are parallelized or randomized."},
{KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output",
Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."},
{KeyPath: "R.GoJSONReport", Name: "gojson-report", UsageArgument: "filename.json", SectionKey: "output",
@@ -428,6 +434,14 @@ func VetConfig(flagSet GinkgoFlagSet, suiteConfig SuiteConfig, reporterConfig Re
errors = append(errors, GinkgoErrors.GracePeriodCannotBeZero())
}
+ if suiteConfig.SleepOnFailure < 0 {
+ errors = append(errors, GinkgoErrors.InvalidSleepOnFailureConfiguration())
+ }
+
+ if suiteConfig.SleepOnFailure > 0 && suiteConfig.ParallelTotal > 1 {
+ errors = append(errors, GinkgoErrors.SleepOnFailureInParallelConfiguration())
+ }
+
if len(suiteConfig.FocusFiles) > 0 {
_, err := ParseFileFilters(suiteConfig.FocusFiles)
if err != nil {
@@ -475,6 +489,30 @@ func VetConfig(flagSet GinkgoFlagSet, suiteConfig SuiteConfig, reporterConfig Re
return errors
}
+// ReconcileFdOutputConfiguration forces serial, in-order execution when --fd is combined with
+// -p, -procs (>1), or -randomize-all. fd's RSpec-style hierarchical output assumes specs run
+// one at a time, in declaration order -- parallelism and randomization both break that assumption
+// and produce fragmented, hard-to-read output. Rather than refusing to run, Ginkgo ignores those
+// flags and runs in series instead. suiteConfig and cliConfig are mutated in place; the return
+// value is true if anything was overridden, so callers can let the user know what was ignored.
+func ReconcileFdOutputConfiguration(reporterConfig ReporterConfig, suiteConfig *SuiteConfig, cliConfig *CLIConfig) bool {
+ if !reporterConfig.FdOutput {
+ return false
+ }
+
+ changed := false
+ if cliConfig.ComputedProcs() > 1 {
+ cliConfig.Procs = 1
+ cliConfig.Parallel = false
+ changed = true
+ }
+ if suiteConfig.RandomizeAllSpecs {
+ suiteConfig.RandomizeAllSpecs = false
+ changed = true
+ }
+ return changed
+}
+
// GinkgoCLISharedFlags provides flags shared by the Ginkgo CLI's build, watch, and run commands
var GinkgoCLISharedFlags = GinkgoFlags{
{KeyPath: "C.Recurse", Name: "r", SectionKey: "multiple-suites",
@@ -570,6 +608,8 @@ var GoBuildFlags = GinkgoFlags{
Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."},
{KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build",
Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`},
+ {KeyPath: "Go.ASan", Name: "asan", SectionKey: "go-build",
+ Usage: "enable interoperation with address sanitizer."},
{KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build",
Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."},
{KeyPath: "Go.N", Name: "n", SectionKey: "go-build",
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/errors.go b/vendor/github.com/onsi/ginkgo/v2/types/errors.go
index 623e54b66..636070c12 100644
--- a/vendor/github.com/onsi/ginkgo/v2/types/errors.go
+++ b/vendor/github.com/onsi/ginkgo/v2/types/errors.go
@@ -455,7 +455,7 @@ func (g ginkgoErrors) InvalidEmptyComponentForSemVerConstraint(cl CodeLocation)
Heading: "Invalid Empty Component for ComponentSemVerConstraint",
Message: "ComponentSemVerConstraint requires a non-empty component name",
CodeLocation: cl,
- DocLink: "spec-semantic-version-filtering",
+ DocLink: "spec-semantic-version-filtering",
}
}
@@ -621,6 +621,21 @@ func (g ginkgoErrors) GracePeriodCannotBeZero() error {
}
}
+func (g ginkgoErrors) InvalidSleepOnFailureConfiguration() error {
+ return GinkgoError{
+ Heading: "Ginkgo requires a non-negative --sleep-on-failure.",
+ Message: "Please set --sleep-on-failure to a positive duration (e.g. 5m), or 0 to disable it.",
+ }
+}
+
+func (g ginkgoErrors) SleepOnFailureInParallelConfiguration() error {
+ return GinkgoError{
+ Heading: "Ginkgo only supports --sleep-on-failure in serial mode.",
+ Message: "--sleep-on-failure pauses a failed spec on a live system for inspection, which only makes sense when the suite runs serially. Please run again without -p or --procs, or unset --sleep-on-failure.",
+ DocLink: "spec-timeouts-and-interruptible-nodes",
+ }
+}
+
func (g ginkgoErrors) ConflictingVerbosityConfiguration() error {
return GinkgoError{
Heading: "Conflicting reporter verbosity settings.",
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/flags.go b/vendor/github.com/onsi/ginkgo/v2/types/flags.go
index 8409653f9..eb04c3e78 100644
--- a/vendor/github.com/onsi/ginkgo/v2/types/flags.go
+++ b/vendor/github.com/onsi/ginkgo/v2/types/flags.go
@@ -212,6 +212,24 @@ func (f GinkgoFlagSet) IsZero() bool {
return f.flagSet == nil
}
+func (f GinkgoFlagSet) Completion(arg string) map[string]string {
+ if f.IsZero() {
+ return nil
+ }
+ prefix := strings.TrimLeft(arg, "-")
+ dash := arg[:len(arg)-len(prefix)]
+ if len(dash) < 1 || len(dash) > 3 {
+ return nil
+ }
+ result := make(map[string]string, len(f.flags))
+ for _, flag := range f.flags {
+ if flag.Name != "" && strings.HasPrefix(flag.Name, prefix) {
+ result[dash+flag.Name] = flag.Usage
+ }
+ }
+ return result
+}
+
func (f GinkgoFlagSet) WasSet(name string) bool {
found := false
f.flagSet.Visit(func(f *flag.Flag) {
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go
index 1df09be00..a34f1f3a3 100644
--- a/vendor/github.com/onsi/ginkgo/v2/types/version.go
+++ b/vendor/github.com/onsi/ginkgo/v2/types/version.go
@@ -1,3 +1,3 @@
package types
-const VERSION = "2.28.1"
+const VERSION = "2.32.2"
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index 91e65521b..8f1d34e38 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,35 @@
+## 1.43.0
+
+### Features
+
+Add gomock adaptor extension for using Gomega matchers with gomock
+
+## 1.42.1
+
+Bump Dependencies
+
+## 1.42.0
+
+Add a set of Claude skill as a marketplace plugin
+
+## 1.41.0
+
+### Features
+
+Add `BeASlice` and `BeAnArray` matchers
+
+### Fixes
+
+Object formatting now detects pointer cycles to avoid runaway formatting output.
+
+## 1.40.0
+
+We're adopting a new release strategy to minimize dependency bloat in projects that consume Gomega. It is a limitation of the go mod toolchain that _test_ subdependencies of your project's direct dependencies get pulled in as *indirect* dependencies. In the case of Gomega, this ends up pulling in all of Ginkgo into your `go.mod` even if you are only using Gomega (Gomega uses Ginkgo for its own tests).
+
+Going forward, releases will strip out all tests, tidy up the `go.mod` and then push this stripped down version to a new `master-lite` branch. These stripped-down versions will receive the `vx.y.z` git tag and will be picked up by the go toolchain.
+
+Please open an issue if this new release process causes unexpected changes for your projects.
+
## 1.39.1
Update all dependencies. This auto-updated the required version of Go to 1.24, consistent with the fact that Go 1.23 has been out of support for almost six months.
diff --git a/vendor/github.com/onsi/gomega/README.md b/vendor/github.com/onsi/gomega/README.md
index d45a8c4e5..6eb36fdf8 100644
--- a/vendor/github.com/onsi/gomega/README.md
+++ b/vendor/github.com/onsi/gomega/README.md
@@ -6,6 +6,19 @@ Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega
If you have a question, comment, bug report, feature request, etc. please open a GitHub issue.
+## Using Gomega with Claude Code
+
+Gomega ships a set of [Claude Code](https://claude.com/claude-code) skills as a **plugin**, so an agent writing assertions in *your* suite has Gomega's idioms — the full matcher catalog, `Eventually`/`Consistently`, and the `gstruct`/`ghttp`/`gexec`/`gbytes`/`gleak`/`gmeasure` sub-libraries — on hand. The Gomega repo doubles as the plugin marketplace, so installation is two commands. From inside Claude Code:
+
+```
+/plugin marketplace add onsi/gomega
+/plugin install gomega@gomega
+```
+
+(or non-interactively: `claude plugin marketplace add onsi/gomega` then `claude plugin install gomega@gomega`)
+
+This installs a family of `gomega:*` skills that activate automatically while you write tests. See the [docs](http://onsi.github.io/gomega/#using-gomega-with-claude-code) for the full list.
+
## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang
Learn more about Ginkgo [here](http://onsi.github.io/ginkgo/)
diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go
index 6c23ba338..d56f9a475 100644
--- a/vendor/github.com/onsi/gomega/format/format.go
+++ b/vendor/github.com/onsi/gomega/format/format.go
@@ -262,7 +262,7 @@ func Object(object any, indentation uint) string {
if err, ok := object.(error); ok && !isNilValue(value) { // isNilValue check needed here to avoid nil deref due to boxed nil
commonRepresentation += "\n" + IndentString(err.Error(), indentation) + "\n" + indent
}
- return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), commonRepresentation, formatValue(value, indentation, true))
+ return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), commonRepresentation, formatValue(value, indentation, true, map[uintptr]struct{}{}))
}
/*
@@ -306,7 +306,7 @@ func formatType(v reflect.Value) string {
}
}
-func formatValue(value reflect.Value, indentation uint, isTopLevel bool) string {
+func formatValue(value reflect.Value, indentation uint, isTopLevel bool, visited map[uintptr]struct{}) string {
if indentation > MaxDepth {
return "..."
}
@@ -367,23 +367,28 @@ func formatValue(value reflect.Value, indentation uint, isTopLevel bool) string
case reflect.Func:
return fmt.Sprintf("0x%x", value.Pointer())
case reflect.Ptr:
- return formatValue(value.Elem(), indentation, isTopLevel)
+ ptr := value.Pointer()
+ if _, ok := visited[ptr]; ok {
+ return fmt.Sprintf("0x%x (cyclic reference)", ptr)
+ }
+ visited[ptr] = struct{}{}
+ return formatValue(value.Elem(), indentation, isTopLevel, visited)
case reflect.Slice:
- return truncateLongStrings(formatSlice(value, indentation))
+ return truncateLongStrings(formatSlice(value, indentation, visited))
case reflect.String:
return truncateLongStrings(formatString(value.String(), indentation, isTopLevel))
case reflect.Array:
- return truncateLongStrings(formatSlice(value, indentation))
+ return truncateLongStrings(formatSlice(value, indentation, visited))
case reflect.Map:
- return truncateLongStrings(formatMap(value, indentation))
+ return truncateLongStrings(formatMap(value, indentation, visited))
case reflect.Struct:
if value.Type() == timeType && value.CanInterface() {
t, _ := value.Interface().(time.Time)
return t.Format(time.RFC3339Nano)
}
- return truncateLongStrings(formatStruct(value, indentation))
+ return truncateLongStrings(formatStruct(value, indentation, visited))
case reflect.Interface:
- return formatInterface(value, indentation)
+ return formatInterface(value, indentation, visited)
default:
if value.CanInterface() {
return truncateLongStrings(fmt.Sprintf("%#v", value.Interface()))
@@ -414,7 +419,7 @@ func formatString(object any, indentation uint, isTopLevel bool) string {
}
}
-func formatSlice(v reflect.Value, indentation uint) string {
+func formatSlice(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string {
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) {
return formatString(v.Bytes(), indentation, false)
}
@@ -423,7 +428,7 @@ func formatSlice(v reflect.Value, indentation uint) string {
result := make([]string, l)
longest := 0
for i := range l {
- result[i] = formatValue(v.Index(i), indentation+1, false)
+ result[i] = formatValue(v.Index(i), indentation+1, false, visited)
if len(result[i]) > longest {
longest = len(result[i])
}
@@ -436,14 +441,14 @@ func formatSlice(v reflect.Value, indentation uint) string {
return fmt.Sprintf("[%s]", strings.Join(result, ", "))
}
-func formatMap(v reflect.Value, indentation uint) string {
+func formatMap(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string {
l := v.Len()
result := make([]string, l)
longest := 0
for i, key := range v.MapKeys() {
value := v.MapIndex(key)
- result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1, false), formatValue(value, indentation+1, false))
+ result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1, false, visited), formatValue(value, indentation+1, false, visited))
if len(result[i]) > longest {
longest = len(result[i])
}
@@ -456,7 +461,7 @@ func formatMap(v reflect.Value, indentation uint) string {
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
}
-func formatStruct(v reflect.Value, indentation uint) string {
+func formatStruct(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string {
t := v.Type()
l := v.NumField()
@@ -465,7 +470,7 @@ func formatStruct(v reflect.Value, indentation uint) string {
for i := range l {
structField := t.Field(i)
fieldEntry := v.Field(i)
- representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1, false))
+ representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1, false, visited))
result = append(result, representation)
if len(representation) > longest {
longest = len(representation)
@@ -478,8 +483,8 @@ func formatStruct(v reflect.Value, indentation uint) string {
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
}
-func formatInterface(v reflect.Value, indentation uint) string {
- return fmt.Sprintf("<%s>%s", formatType(v.Elem()), formatValue(v.Elem(), indentation, false))
+func formatInterface(v reflect.Value, indentation uint, visited map[uintptr]struct{}) string {
+ return fmt.Sprintf("<%s>%s", formatType(v.Elem()), formatValue(v.Elem(), indentation, false, visited))
}
func isNilValue(a reflect.Value) bool {
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 87c70692b..3206e05da 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -22,7 +22,7 @@ import (
"github.com/onsi/gomega/types"
)
-const GOMEGA_VERSION = "1.39.1"
+const GOMEGA_VERSION = "1.43.0"
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
index 16ca8f46d..bf5722605 100644
--- a/vendor/github.com/onsi/gomega/matchers.go
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -621,6 +621,18 @@ func BeADirectory() types.GomegaMatcher {
return &matchers.BeADirectoryMatcher{}
}
+// BeASlice succeeds if actual is a value of slice type.
+// This is useful when actual has type any (interface{}) and you want to assert it is a slice.
+func BeASlice() types.GomegaMatcher {
+ return &matchers.BeASliceMatcher{}
+}
+
+// BeAnArray succeeds if actual is a value of array type.
+// This is useful when actual has type any (interface{}) and you want to assert it is an array.
+func BeAnArray() types.GomegaMatcher {
+ return &matchers.BeAnArrayMatcher{}
+}
+
// HaveHTTPStatus succeeds if the Status or StatusCode field of an HTTP response matches.
// Actual must be either a *http.Response or *httptest.ResponseRecorder.
// Expected must be either an int or a string.
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go
new file mode 100644
index 000000000..4fcad5127
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_slice_matcher.go
@@ -0,0 +1,28 @@
+// untested sections: 1
+
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type BeASliceMatcher struct {
+}
+
+func (matcher *BeASliceMatcher) Match(actual any) (success bool, err error) {
+ if actual == nil {
+ return false, fmt.Errorf("BeASlice matcher expects a value, got nil")
+ }
+ return reflect.TypeOf(actual).Kind() == reflect.Slice, nil
+}
+
+func (matcher *BeASliceMatcher) FailureMessage(actual any) (message string) {
+ return format.Message(actual, "to be a slice")
+}
+
+func (matcher *BeASliceMatcher) NegatedFailureMessage(actual any) (message string) {
+ return format.Message(actual, "not to be a slice")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go
new file mode 100644
index 000000000..573aa8198
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_an_array_matcher.go
@@ -0,0 +1,28 @@
+// untested sections: 1
+
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type BeAnArrayMatcher struct {
+}
+
+func (matcher *BeAnArrayMatcher) Match(actual any) (success bool, err error) {
+ if actual == nil {
+ return false, fmt.Errorf("BeAnArray matcher expects a value, got nil")
+ }
+ return reflect.TypeOf(actual).Kind() == reflect.Array, nil
+}
+
+func (matcher *BeAnArrayMatcher) FailureMessage(actual any) (message string) {
+ return format.Message(actual, "to be an array")
+}
+
+func (matcher *BeAnArrayMatcher) NegatedFailureMessage(actual any) (message string) {
+ return format.Message(actual, "not to be an array")
+}
diff --git a/vendor/github.com/onsi/gomega/types/types.go b/vendor/github.com/onsi/gomega/types/types.go
index 685a46f37..e444451ac 100644
--- a/vendor/github.com/onsi/gomega/types/types.go
+++ b/vendor/github.com/onsi/gomega/types/types.go
@@ -66,6 +66,12 @@ func MatchMayChangeInTheFuture(matcher GomegaMatcher, value any) bool {
// AsyncAssertions are returned by Eventually and Consistently and enable matchers to be polled repeatedly to ensure
// they are eventually satisfied
+//
+// The optional optionalDescription argument allows you to annotate the assertion with additional information.
+// It is passed as the second argument and can be a format string followed by arguments, or a func() string.
+// The description is included in failure messages to provide context.
+//
+// For details on annotating assertions, see: https://onsi.github.io/gomega/#annotating-assertions
type AsyncAssertion interface {
Should(matcher GomegaMatcher, optionalDescription ...any) bool
ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool
@@ -86,6 +92,12 @@ type AsyncAssertion interface {
}
// Assertions are returned by Ω and Expect and enable assertions against Gomega matchers
+//
+// The optional optionalDescription argument allows you to annotate the assertion with additional information.
+// It is passed as the second argument and can be a format string followed by arguments, or a func() string.
+// The description is included in failure messages to provide context.
+//
+// For details on annotating assertions, see: https://onsi.github.io/gomega/#annotating-assertions
type Assertion interface {
Should(matcher GomegaMatcher, optionalDescription ...any) bool
ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 69ee3a659..6fbdd185e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -33,7 +33,7 @@ github.com/Azure/go-ansiterm/winterm
# github.com/ErikDubbelboer/gspt v0.0.0-20210805194459-ce36a5128377
## explicit
github.com/ErikDubbelboer/gspt
-# github.com/Masterminds/semver/v3 v3.4.0
+# github.com/Masterminds/semver/v3 v3.5.0
## explicit; go 1.21
github.com/Masterminds/semver/v3
# github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29
@@ -269,8 +269,8 @@ github.com/google/go-github/v76/github
# github.com/google/go-querystring v1.2.0
## explicit; go 1.13
github.com/google/go-querystring/query
-# github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83
-## explicit; go 1.24.0
+# github.com/google/pprof v0.0.0-20260906184651-6331bc6350fe
+## explicit; go 1.25.0
github.com/google/pprof/profile
# github.com/google/s2a-go v0.1.9
## explicit; go 1.20
@@ -494,8 +494,8 @@ github.com/okta/okta-jwt-verifier-golang/discovery
github.com/okta/okta-jwt-verifier-golang/discovery/oidc
github.com/okta/okta-jwt-verifier-golang/errors
github.com/okta/okta-jwt-verifier-golang/utils
-# github.com/onsi/ginkgo/v2 v2.28.1
-## explicit; go 1.24.0
+# github.com/onsi/ginkgo/v2 v2.32.2
+## explicit; go 1.25.0
github.com/onsi/ginkgo/v2
github.com/onsi/ginkgo/v2/config
github.com/onsi/ginkgo/v2/formatter
@@ -518,8 +518,8 @@ github.com/onsi/ginkgo/v2/internal/reporters
github.com/onsi/ginkgo/v2/internal/testingtproxy
github.com/onsi/ginkgo/v2/reporters
github.com/onsi/ginkgo/v2/types
-# github.com/onsi/gomega v1.39.1
-## explicit; go 1.24.0
+# github.com/onsi/gomega v1.43.0
+## explicit; go 1.25.0
github.com/onsi/gomega
github.com/onsi/gomega/format
github.com/onsi/gomega/internal