diff --git a/.github/assets/gitea-alerts.png b/.github/assets/gitea-alerts.png
new file mode 100644
index 00000000..67491f0e
Binary files /dev/null and b/.github/assets/gitea-alerts.png differ
diff --git a/README.md b/README.md
index bf9ac39b..9b3d5910 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,6 @@
[![Docker pulls](https://img.shields.io/docker/pulls/twinproduction/gatus.svg)](https://cloud.docker.com/repository/docker/twinproduction/gatus)
[![Follow TwiN](https://img.shields.io/github/followers/TwiN?label=Follow&style=social)](https://github.com/TwiN)
-
Gatus is a developer-oriented health dashboard that gives you the ability to monitor your services using HTTP, ICMP, TCP, and even DNS
queries as well as evaluate the result of said queries by using a list of conditions on values like the status code,
the response time, the certificate expiration, the body and many others. The icing on top is that each of these health
@@ -54,6 +53,7 @@ Have any feedback or questions? [Create a discussion](https://github.com/TwiN/ga
- [Alerting](#alerting)
- [Configuring Discord alerts](#configuring-discord-alerts)
- [Configuring Email alerts](#configuring-email-alerts)
+ - [Configuring Gitea alerts](#configuring-gitea-alerts)
- [Configuring GitHub alerts](#configuring-github-alerts)
- [Configuring GitLab alerts](#configuring-gitlab-alerts)
- [Configuring Google Chat alerts](#configuring-google-chat-alerts)
@@ -109,6 +109,7 @@ Have any feedback or questions? [Create a discussion](https://github.com/TwiN/ga
- [Configuring a startup delay](#configuring-a-startup-delay)
- [Keeping your configuration small](#keeping-your-configuration-small)
- [Proxy client configuration](#proxy-client-configuration)
+ - [How to fix 431 Request Header Fields Too Large error](#how-to-fix-431-request-header-fields-too-large-error)
- [Badges](#badges)
- [Uptime](#uptime)
- [Health](#health)
@@ -660,8 +661,45 @@ endpoints:
> ⚠ Some mail servers are painfully slow.
+#### Configuring Gitea alerts
+
+| Parameter | Description | Default |
+|:---------------------------------|:-----------------------------------------------------------------------------------------------------------|:--------------|
+| `alerting.gitea` | Configuration for alerts of type `gitea` | `{}` |
+| `alerting.gitea.repository-url` | Gitea repository URL (e.g. `https://gitea.com/TwiN/example`) | Required `""` |
+| `alerting.gitea.token` | Personal access token to use for authentication.
Must have at least RW on issues and RO on metadata. | Required `""` |
+| `alerting.github.default-alert` | Default alert configuration.
See [Setting a default alert](#setting-a-default-alert). | N/A |
+
+The Gitea alerting provider creates an issue prefixed with `alert(gatus):` and suffixed with the endpoint's display
+name for each alert. If `send-on-resolved` is set to `true` on the endpoint alert, the issue will be automatically
+closed when the alert is resolved.
+
+```yaml
+alerting:
+ gitea:
+ repository-url: "https://gitea.com/TwiN/test"
+ token: "349d63f16......"
+
+endpoints:
+ - name: example
+ url: "https://twin.sh/health"
+ interval: 5m
+ conditions:
+ - "[STATUS] == 200"
+ - "[BODY].status == UP"
+ - "[RESPONSE_TIME] < 75"
+ alerts:
+ - type: gitea
+ failure-threshold: 2
+ success-threshold: 3
+ send-on-resolved: true
+ description: "Everything's burning AAAAAHHHHHHHHHHHHHHH"
+```
+
+![Gitea alert](.github/assets/gitea-alerts.png)
#### Configuring GitHub alerts
+
| Parameter | Description | Default |
|:---------------------------------|:-----------------------------------------------------------------------------------------------------------|:--------------|
| `alerting.github` | Configuration for alerts of type `github` | `{}` |
@@ -697,7 +735,6 @@ endpoints:
![GitHub alert](.github/assets/github-alerts.png)
-
#### Configuring GitLab alerts
| Parameter | Description | Default |
|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------|:--------------|
diff --git a/alerting/alert/type.go b/alerting/alert/type.go
index 51febc00..d4a620d9 100644
--- a/alerting/alert/type.go
+++ b/alerting/alert/type.go
@@ -23,6 +23,9 @@ const (
// TypeGitLab is the Type for the gitlab alerting provider
TypeGitLab Type = "gitlab"
+ // TypeGitea is the Type for the gitea alerting provider
+ TypeGitea Type = "gitea"
+
// TypeGoogleChat is the Type for the googlechat alerting provider
TypeGoogleChat Type = "googlechat"
diff --git a/alerting/config.go b/alerting/config.go
index c17d5649..e198b592 100644
--- a/alerting/config.go
+++ b/alerting/config.go
@@ -11,6 +11,7 @@ import (
"github.com/TwiN/gatus/v5/alerting/provider/custom"
"github.com/TwiN/gatus/v5/alerting/provider/discord"
"github.com/TwiN/gatus/v5/alerting/provider/email"
+ "github.com/TwiN/gatus/v5/alerting/provider/gitea"
"github.com/TwiN/gatus/v5/alerting/provider/github"
"github.com/TwiN/gatus/v5/alerting/provider/gitlab"
"github.com/TwiN/gatus/v5/alerting/provider/googlechat"
@@ -49,6 +50,9 @@ type Config struct {
// GitLab is the configuration for the gitlab alerting provider
GitLab *gitlab.AlertProvider `yaml:"gitlab,omitempty"`
+ // Gitea is the configuration for the gitea alerting provider
+ Gitea *gitea.AlertProvider `yaml:"gitea,omitempty"`
+
// GoogleChat is the configuration for the googlechat alerting provider
GoogleChat *googlechat.AlertProvider `yaml:"googlechat,omitempty"`
diff --git a/alerting/provider/gitea/gitea.go b/alerting/provider/gitea/gitea.go
new file mode 100644
index 00000000..489c0a86
--- /dev/null
+++ b/alerting/provider/gitea/gitea.go
@@ -0,0 +1,167 @@
+package gitea
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "code.gitea.io/sdk/gitea"
+ "github.com/TwiN/gatus/v5/alerting/alert"
+ "github.com/TwiN/gatus/v5/client"
+ "github.com/TwiN/gatus/v5/config/endpoint"
+)
+
+// AlertProvider is the configuration necessary for sending an alert using Discord
+type AlertProvider struct {
+ RepositoryURL string `yaml:"repository-url"` // The URL of the Gitea repository to create issues in
+ Token string `yaml:"token"` // Token requires at least RW on issues and RO on metadata
+
+ // DefaultAlert is the default alert configuration to use for endpoints with an alert of the appropriate type
+ DefaultAlert *alert.Alert `yaml:"default-alert,omitempty"`
+
+ // ClientConfig is the configuration of the client used to communicate with the provider's target
+ ClientConfig *client.Config `yaml:"client,omitempty"`
+
+ // Assignees is a list of users to assign the issue to
+ Assignees []string `yaml:"assignees,omitempty"`
+
+ username string
+ repositoryOwner string
+ repositoryName string
+ giteaClient *gitea.Client
+}
+
+// IsValid returns whether the provider's configuration is valid
+func (provider *AlertProvider) IsValid() bool {
+ if provider.ClientConfig == nil {
+ provider.ClientConfig = client.GetDefaultConfig()
+ }
+
+ if len(provider.Token) == 0 || len(provider.RepositoryURL) == 0 {
+ return false
+ }
+ // Validate format of the repository URL
+ repositoryURL, err := url.Parse(provider.RepositoryURL)
+ if err != nil {
+ return false
+ }
+ baseURL := repositoryURL.Scheme + "://" + repositoryURL.Host
+ pathParts := strings.Split(repositoryURL.Path, "/")
+ if len(pathParts) != 3 {
+ return false
+ }
+ provider.repositoryOwner = pathParts[1]
+ provider.repositoryName = pathParts[2]
+
+ opts := []gitea.ClientOption{
+ gitea.SetToken(provider.Token),
+ }
+
+ if provider.ClientConfig != nil && provider.ClientConfig.Insecure {
+ // add new http client for skip verify
+ httpClient := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ },
+ }
+ opts = append(opts, gitea.SetHTTPClient(httpClient))
+ }
+
+ provider.giteaClient, err = gitea.NewClient(baseURL, opts...)
+ if err != nil {
+ return false
+ }
+
+ user, _, err := provider.giteaClient.GetMyUserInfo()
+ if err != nil {
+ return false
+ }
+
+ provider.username = user.UserName
+
+ return true
+}
+
+// Send creates an issue in the designed RepositoryURL if the resolved parameter passed is false,
+// or closes the relevant issue(s) if the resolved parameter passed is true.
+func (provider *AlertProvider) Send(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) error {
+ title := "alert(gatus): " + ep.DisplayName()
+ if !resolved {
+ _, _, err := provider.giteaClient.CreateIssue(
+ provider.repositoryOwner,
+ provider.repositoryName,
+ gitea.CreateIssueOption{
+ Title: title,
+ Body: provider.buildIssueBody(ep, alert, result),
+ Assignees: provider.Assignees,
+ },
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create issue: %w", err)
+ }
+ return nil
+ }
+
+ issues, _, err := provider.giteaClient.ListRepoIssues(
+ provider.repositoryOwner,
+ provider.repositoryName,
+ gitea.ListIssueOption{
+ State: gitea.StateOpen,
+ CreatedBy: provider.username,
+ ListOptions: gitea.ListOptions{
+ Page: 100,
+ },
+ },
+ )
+ if err != nil {
+ return fmt.Errorf("failed to list issues: %w", err)
+ }
+
+ for _, issue := range issues {
+ if issue.Title == title {
+ stateClosed := gitea.StateClosed
+ _, _, err = provider.giteaClient.EditIssue(
+ provider.repositoryOwner,
+ provider.repositoryName,
+ issue.ID,
+ gitea.EditIssueOption{
+ State: &stateClosed,
+ },
+ )
+ if err != nil {
+ return fmt.Errorf("failed to close issue: %w", err)
+ }
+ }
+ }
+ return nil
+}
+
+// buildIssueBody builds the body of the issue
+func (provider *AlertProvider) buildIssueBody(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result) string {
+ var formattedConditionResults string
+ if len(result.ConditionResults) > 0 {
+ formattedConditionResults = "\n\n## Condition results\n"
+ for _, conditionResult := range result.ConditionResults {
+ var prefix string
+ if conditionResult.Success {
+ prefix = ":white_check_mark:"
+ } else {
+ prefix = ":x:"
+ }
+ formattedConditionResults += fmt.Sprintf("- %s - `%s`\n", prefix, conditionResult.Condition)
+ }
+ }
+ var description string
+ if alertDescription := alert.GetDescription(); len(alertDescription) > 0 {
+ description = ":\n> " + alertDescription
+ }
+ message := fmt.Sprintf("An alert for **%s** has been triggered due to having failed %d time(s) in a row", ep.DisplayName(), alert.FailureThreshold)
+ return message + description + formattedConditionResults
+}
+
+// GetDefaultAlert returns the provider's default alert configuration
+func (provider *AlertProvider) GetDefaultAlert() *alert.Alert {
+ return provider.DefaultAlert
+}
diff --git a/alerting/provider/gitea/gitea_test.go b/alerting/provider/gitea/gitea_test.go
new file mode 100644
index 00000000..bac9dacd
--- /dev/null
+++ b/alerting/provider/gitea/gitea_test.go
@@ -0,0 +1,169 @@
+package gitea
+
+import (
+ "net/http"
+ "strings"
+ "testing"
+
+ "code.gitea.io/sdk/gitea"
+ "github.com/TwiN/gatus/v5/alerting/alert"
+ "github.com/TwiN/gatus/v5/client"
+ "github.com/TwiN/gatus/v5/config/endpoint"
+ "github.com/TwiN/gatus/v5/test"
+)
+
+func TestAlertDefaultProvider_IsValid(t *testing.T) {
+ scenarios := []struct {
+ Name string
+ Provider AlertProvider
+ Expected bool
+ }{
+ {
+ Name: "invalid",
+ Provider: AlertProvider{RepositoryURL: "", Token: ""},
+ Expected: false,
+ },
+ {
+ Name: "invalid-token",
+ Provider: AlertProvider{RepositoryURL: "https://gitea.com/TwiN/test", Token: "12345"},
+ Expected: false,
+ },
+ {
+ Name: "missing-repository-name",
+ Provider: AlertProvider{RepositoryURL: "https://gitea.com/TwiN", Token: "12345"},
+ Expected: false,
+ },
+ {
+ Name: "enterprise-client",
+ Provider: AlertProvider{RepositoryURL: "https://gitea.example.com/TwiN/test", Token: "12345"},
+ Expected: false,
+ },
+ {
+ Name: "invalid-url",
+ Provider: AlertProvider{RepositoryURL: "gitea.com/TwiN/test", Token: "12345"},
+ Expected: false,
+ },
+ }
+ for _, scenario := range scenarios {
+ t.Run(scenario.Name, func(t *testing.T) {
+ if scenario.Provider.IsValid() != scenario.Expected {
+ t.Errorf("expected %t, got %t", scenario.Expected, scenario.Provider.IsValid())
+ }
+ })
+ }
+}
+
+func TestAlertProvider_Send(t *testing.T) {
+ defer client.InjectHTTPClient(nil)
+ firstDescription := "description-1"
+ secondDescription := "description-2"
+ scenarios := []struct {
+ Name string
+ Provider AlertProvider
+ Alert alert.Alert
+ Resolved bool
+ MockRoundTripper test.MockRoundTripper
+ ExpectedError bool
+ }{
+ {
+ Name: "triggered-error",
+ Provider: AlertProvider{RepositoryURL: "https://gitea.com/TwiN/test", Token: "12345"},
+ Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3},
+ Resolved: false,
+ ExpectedError: true,
+ },
+ {
+ Name: "resolved-error",
+ Provider: AlertProvider{RepositoryURL: "https://gitea.com/TwiN/test", Token: "12345"},
+ Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3},
+ Resolved: true,
+ ExpectedError: true,
+ },
+ }
+ for _, scenario := range scenarios {
+ t.Run(scenario.Name, func(t *testing.T) {
+ scenario.Provider.giteaClient, _ = gitea.NewClient("https://gitea.com")
+ client.InjectHTTPClient(&http.Client{Transport: scenario.MockRoundTripper})
+ err := scenario.Provider.Send(
+ &endpoint.Endpoint{Name: "endpoint-name", Group: "endpoint-group"},
+ &scenario.Alert,
+ &endpoint.Result{
+ ConditionResults: []*endpoint.ConditionResult{
+ {Condition: "[CONNECTED] == true", Success: scenario.Resolved},
+ {Condition: "[STATUS] == 200", Success: scenario.Resolved},
+ },
+ },
+ scenario.Resolved,
+ )
+ if scenario.ExpectedError && err == nil {
+ t.Error("expected error, got none")
+ }
+ if !scenario.ExpectedError && err != nil {
+ t.Error("expected no error, got", err.Error())
+ }
+ })
+ }
+}
+
+func TestAlertProvider_buildRequestBody(t *testing.T) {
+ firstDescription := "description-1"
+ scenarios := []struct {
+ Name string
+ Endpoint endpoint.Endpoint
+ Provider AlertProvider
+ Alert alert.Alert
+ NoConditions bool
+ ExpectedBody string
+ }{
+ {
+ Name: "triggered",
+ Endpoint: endpoint.Endpoint{Name: "endpoint-name", URL: "https://example.org"},
+ Provider: AlertProvider{},
+ Alert: alert.Alert{Description: &firstDescription, FailureThreshold: 3},
+ ExpectedBody: "An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row:\n> description-1\n\n## Condition results\n- :white_check_mark: - `[CONNECTED] == true`\n- :x: - `[STATUS] == 200`",
+ },
+ {
+ Name: "triggered-with-no-description",
+ Endpoint: endpoint.Endpoint{Name: "endpoint-name", URL: "https://example.org"},
+ Provider: AlertProvider{},
+ Alert: alert.Alert{FailureThreshold: 10},
+ ExpectedBody: "An alert for **endpoint-name** has been triggered due to having failed 10 time(s) in a row\n\n## Condition results\n- :white_check_mark: - `[CONNECTED] == true`\n- :x: - `[STATUS] == 200`",
+ },
+ {
+ Name: "triggered-with-no-conditions",
+ NoConditions: true,
+ Endpoint: endpoint.Endpoint{Name: "endpoint-name", URL: "https://example.org"},
+ Provider: AlertProvider{},
+ Alert: alert.Alert{Description: &firstDescription, FailureThreshold: 10},
+ ExpectedBody: "An alert for **endpoint-name** has been triggered due to having failed 10 time(s) in a row:\n> description-1",
+ },
+ }
+ for _, scenario := range scenarios {
+ t.Run(scenario.Name, func(t *testing.T) {
+ var conditionResults []*endpoint.ConditionResult
+ if !scenario.NoConditions {
+ conditionResults = []*endpoint.ConditionResult{
+ {Condition: "[CONNECTED] == true", Success: true},
+ {Condition: "[STATUS] == 200", Success: false},
+ }
+ }
+ body := scenario.Provider.buildIssueBody(
+ &scenario.Endpoint,
+ &scenario.Alert,
+ &endpoint.Result{ConditionResults: conditionResults},
+ )
+ if strings.TrimSpace(body) != strings.TrimSpace(scenario.ExpectedBody) {
+ t.Errorf("expected:\n%s\ngot:\n%s", scenario.ExpectedBody, body)
+ }
+ })
+ }
+}
+
+func TestAlertProvider_GetDefaultAlert(t *testing.T) {
+ if (&AlertProvider{DefaultAlert: &alert.Alert{}}).GetDefaultAlert() == nil {
+ t.Error("expected default alert to be not nil")
+ }
+ if (&AlertProvider{DefaultAlert: nil}).GetDefaultAlert() != nil {
+ t.Error("expected default alert to be nil")
+ }
+}
diff --git a/alerting/provider/provider.go b/alerting/provider/provider.go
index a294ad9b..30e805e4 100644
--- a/alerting/provider/provider.go
+++ b/alerting/provider/provider.go
@@ -6,6 +6,7 @@ import (
"github.com/TwiN/gatus/v5/alerting/provider/custom"
"github.com/TwiN/gatus/v5/alerting/provider/discord"
"github.com/TwiN/gatus/v5/alerting/provider/email"
+ "github.com/TwiN/gatus/v5/alerting/provider/gitea"
"github.com/TwiN/gatus/v5/alerting/provider/github"
"github.com/TwiN/gatus/v5/alerting/provider/gitlab"
"github.com/TwiN/gatus/v5/alerting/provider/googlechat"
@@ -66,6 +67,7 @@ var (
_ AlertProvider = (*email.AlertProvider)(nil)
_ AlertProvider = (*github.AlertProvider)(nil)
_ AlertProvider = (*gitlab.AlertProvider)(nil)
+ _ AlertProvider = (*gitea.AlertProvider)(nil)
_ AlertProvider = (*googlechat.AlertProvider)(nil)
_ AlertProvider = (*jetbrainsspace.AlertProvider)(nil)
_ AlertProvider = (*matrix.AlertProvider)(nil)
diff --git a/config/config.go b/config/config.go
index a4a1d5df..aac864ed 100644
--- a/config/config.go
+++ b/config/config.go
@@ -400,6 +400,7 @@ func validateAlertingConfig(alertingConfig *alerting.Config, endpoints []*endpoi
alert.TypeEmail,
alert.TypeGitHub,
alert.TypeGitLab,
+ alert.TypeGitea,
alert.TypeGoogleChat,
alert.TypeGotify,
alert.TypeJetBrainsSpace,
diff --git a/go.mod b/go.mod
index b92c0763..bed857d3 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/TwiN/gatus/v5
go 1.22.2
require (
+ code.gitea.io/sdk/gitea v0.19.0
github.com/TwiN/deepmerge v0.2.1
github.com/TwiN/g8/v2 v2.0.0
github.com/TwiN/gocache/v2 v2.2.2
@@ -38,8 +39,10 @@ require (
github.com/blend/go-sdk v1.20220411.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
@@ -49,6 +52,7 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
+ github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.17.8 // indirect
diff --git a/go.sum b/go.sum
index 027e9464..16af4108 100644
--- a/go.sum
+++ b/go.sum
@@ -5,6 +5,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKF
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+code.gitea.io/sdk/gitea v0.19.0 h1:8I6s1s4RHgzxiPHhOQdgim1RWIRcr0LVMbHBjBFXq4Y=
+code.gitea.io/sdk/gitea v0.19.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/TwiN/deepmerge v0.2.1 h1:GowJr9O4THTVW4awX63x1BVg1hgr4q+35XKKCYbwsSs=
github.com/TwiN/deepmerge v0.2.1/go.mod h1:LVBmCEBQvibYSF8Gyl/NqhHXH7yIiT7Ozqf9dHxGPW0=
@@ -35,6 +37,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
+github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -43,6 +47,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
+github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -94,6 +100,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
+github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
+github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/ishidawataru/sctp v0.0.0-20230406120618-7ff4192f6ff2 h1:i2fYnDurfLlJH8AyyMOnkLHnHeP8Ff/DDpuZA/D3bPo=
@@ -172,6 +180,7 @@ go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=