From b3d19ed70e8f2d734db59eb3b2adcfbb95fb5afc Mon Sep 17 00:00:00 2001 From: Elliot Waddington Date: Mon, 9 Mar 2026 15:35:13 +0100 Subject: [PATCH 01/18] ENG-2804 add webflow changelog webhook handler to api server (#4189) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2026-03-09 at 12 56 47 image Verified the full flow end-to-end via cURL — sending a signed Webflow webhook payload to a local api-server successfully enqueues the River job and sends a broadcast email via Resend as expected. The feature is gated by config: if `WEBFLOW_WEBHOOK_SECRET` and `RESEND_API_KEY` are not set, the handler and worker simply don't register. This means the code can ship safely now. To go live we need: - Add Webflow + Resend credentials to 1Password ([ENG-3043](https://linear.app/overmind/issue/ENG-3043/add-webflow-webhook-credentials-to-1password-global-vault), [ENG-3044](https://linear.app/overmind/issue/ENG-3043/add-webflow-webhook-credentials-to-1password-global-vault)) - Configure the Webflow webhook URL to point at the production api-server - Import verified user emails into the Resend [segment](https://resend.com/audience?segmentId=e562dcde-600f-4535-bdfc-5e72c5a16c3d) ([ENG-2957](https://linear.app/overmind/issue/ENG-2957/manual-csv-sync-of-verified-user-emails-to-resend)) - Automate adding new users to changelog notify [segment in resend](https://resend.com/audience?segmentId=e562dcde-600f-4535-bdfc-5e72c5a16c3d) [ENG-2958](https://linear.app/overmind/issue/ENG-2958/add-resend-contact-creation-to-user-signup-flow) - Once those are done, changelog publishes in Webflow will automatically trigger broadcast emails. --- > [!NOTE] > **Medium Risk** > Introduces a new externally reachable webhook endpoint and outbound email-sending worker; while gated by config and protected with HMAC + timestamp checks, mistakes could lead to unwanted job enqueues or email broadcasts. > > **Overview** > Adds a Webflow webhook integration that, when enabled via config, verifies `X-Webflow-Signature` (HMAC-SHA256) and timestamp tolerance, filters events by CMS collection ID, and enqueues a River `ChangelogEmail` job. > > Adds a River worker that renders a new embedded HTML template and uses the `resend-go` client to send a broadcast email to a configured Resend segment; wiring includes new CLI/env config fields with secret redaction and new ExternalSecret entries for Webflow/Resend credentials. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b1ac7f7b0e9605a99f8828d52942cd127515a8f2. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 782a27f26097b36ae2b053b9949ef49a962df666 --- go.mod | 200 +++++++++++++++- go.sum | 737 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 931 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 51b9b4a6..243def89 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( cloud.google.com/go/bigtable v1.42.0 cloud.google.com/go/certificatemanager v1.9.6 cloud.google.com/go/compute v1.56.0 - cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 cloud.google.com/go/container v1.46.0 cloud.google.com/go/dataplex v1.28.0 cloud.google.com/go/dataproc/v2 v2.16.0 @@ -40,6 +40,8 @@ require ( cloud.google.com/go/storage v1.60.0 cloud.google.com/go/storagetransfer v1.13.1 connectrpc.com/connect v1.18.1 // v1.19.0 was faulty, wait until it is above this version + connectrpc.com/otelconnect v0.9.0 + github.com/1password/onepassword-sdk-go v0.4.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3 v3.0.0-beta.2 @@ -58,6 +60,12 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v3 v3.0.0 github.com/Masterminds/semver/v3 v3.4.0 github.com/MrAlias/otel-schema-utils v0.4.0-alpha + github.com/a-h/templ v0.3.1001 + github.com/adrg/strutil v0.3.1 + github.com/akedrou/textdiff v0.1.0 + github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 + github.com/antihax/optional v1.0.0 + github.com/auth0/go-auth0/v2 v2.6.0 github.com/auth0/go-jwt-middleware/v2 v2.3.1 github.com/aws/aws-sdk-go-v2 v1.41.3 github.com/aws/aws-sdk-go-v2/config v1.32.11 @@ -83,49 +91,84 @@ require ( github.com/aws/aws-sdk-go-v2/service/rds v1.116.2 github.com/aws/aws-sdk-go-v2/service/route53 v1.62.3 github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 + github.com/aws/aws-sdk-go-v2/service/sesv2 v1.59.4 github.com/aws/aws-sdk-go-v2/service/sns v1.39.13 github.com/aws/aws-sdk-go-v2/service/sqs v1.42.23 github.com/aws/aws-sdk-go-v2/service/ssm v1.68.2 github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 github.com/aws/smithy-go v1.24.2 + github.com/bombsimon/logrusr/v4 v4.1.0 + github.com/bradleyfalzon/ghinstallation/v2 v2.17.0 + github.com/brianvoe/gofakeit/v7 v7.14.1 github.com/cenkalti/backoff/v5 v5.0.3 github.com/charmbracelet/glamour v0.10.0 github.com/coder/websocket v1.8.14 - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/getsentry/sentry-go v0.43.0 github.com/go-jose/go-jose/v4 v4.1.3 + github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/google/btree v1.1.3 + github.com/google/go-github/v80 v80.0.0 github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.17.0 github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e + github.com/gorilla/mux v1.8.1 + github.com/harness/harness-go-sdk v0.7.13 github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/hcl/v2 v2.24.0 github.com/hashicorp/terraform-config-inspect v0.0.0-20260224005459-813a97530220 github.com/hashicorp/terraform-plugin-framework v1.18.0 github.com/hashicorp/terraform-plugin-go v0.30.0 github.com/hashicorp/terraform-plugin-testing v1.14.0 + github.com/invopop/jsonschema v0.13.0 + github.com/jackc/pgx/v5 v5.8.0 github.com/jedib0t/go-pretty/v6 v6.7.8 + github.com/jxskiss/base62 v1.1.0 + github.com/kaptinlin/jsonrepair v0.2.17 + github.com/manifoldco/promptui v0.9.0 + github.com/mavolin/go-htmx v1.0.0 + github.com/mergestat/timediff v0.0.4 github.com/micahhausler/aws-iam-policy v0.4.4 github.com/miekg/dns v1.1.72 github.com/mitchellh/go-homedir v1.1.0 + github.com/mitchellh/go-ps v1.0.0 + github.com/modelcontextprotocol/go-sdk v1.4.0 github.com/muesli/reflow v0.3.0 github.com/nats-io/jwt/v2 v2.8.0 github.com/nats-io/nats-server/v2 v2.12.4 github.com/nats-io/nats.go v1.49.0 github.com/nats-io/nkeys v0.4.15 - github.com/onsi/ginkgo/v2 v2.28.1 // indirect - github.com/onsi/gomega v1.39.1 // indirect + github.com/neo4j/neo4j-go-driver/v6 v6.0.0 + github.com/onsi/ginkgo/v2 v2.28.1 + github.com/onsi/gomega v1.39.1 + github.com/openai/openai-go/v3 v3.26.0 github.com/openrdap/rdap v0.9.2-0.20240517203139-eb57b3a8dedd + github.com/overmindtech/otelpgx v0.10.1-0.20260303210427-65bf1016045e github.com/overmindtech/pterm v0.0.0-20240919144758-04d94ccb2297 + github.com/pborman/ansi v1.0.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c + github.com/posthog/posthog-go v1.10.0 + github.com/projectdiscovery/subfinder/v2 v2.12.0 + github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf + github.com/riverqueue/river v0.31.0 + github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0 + github.com/riverqueue/river/rivertype v0.31.0 + github.com/riverqueue/rivercontrib/otelriver v0.7.0 + github.com/rs/cors v1.11.1 + github.com/samber/slog-logrus/v2 v2.5.3 + github.com/sashabaranov/go-openai v1.41.2 + github.com/serpapi/serpapi-golang v0.0.0-20260126142127-0e41c7993cda github.com/sirupsen/logrus v1.9.4 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 + github.com/stripe/stripe-go/v84 v84.4.0 + github.com/tiktoken-go/tokenizer v0.7.0 github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2 + github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/xiam/dig v0.0.0-20191116195832-893b5fb5093b github.com/zclconf/go-cty v1.18.0 go.etcd.io/bbolt v1.4.3 @@ -155,10 +198,15 @@ require ( k8s.io/api v0.35.2 k8s.io/apimachinery v0.35.2 k8s.io/client-go v0.35.2 + k8s.io/component-base v0.35.2 + modernc.org/sqlite v1.46.1 + riverqueue.com/riverui v0.15.0 + sigs.k8s.io/controller-runtime v0.23.3 sigs.k8s.io/kind v0.31.0 ) require ( + aead.dev/minisign v0.2.0 // indirect al.essio.dev/pkg/shellescape v1.5.1 // indirect atomicgo.dev/cursor v0.2.0 // indirect atomicgo.dev/schedule v0.1.0 // indirect @@ -173,15 +221,23 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect + github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect + github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/PuerkitoBio/rehttp v1.4.0 // indirect + github.com/STARRY-S/zip v0.2.1 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect + github.com/akrylysov/pogreb v0.10.1 // indirect github.com/alecthomas/chroma/v2 v2.16.0 // indirect github.com/alecthomas/kingpin/v2 v2.4.0 // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect + github.com/andybalholm/brotli v1.1.1 // indirect github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/apache/arrow/go/v15 v15.0.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect @@ -197,6 +253,14 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/bodgit/plumbing v1.3.0 // indirect + github.com/bodgit/sevenzip v1.6.0 // indirect + github.com/bodgit/windows v1.0.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.4.2 // indirect github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect; being pulled by glamour, this will be resolved in https://github.com/charmbracelet/glamour/pull/408 @@ -207,39 +271,69 @@ require ( github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect + github.com/cheggaaa/pb/v3 v3.1.4 // indirect + github.com/chzyer/readline v1.5.1 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/cloudflare/circl v1.6.3 // indirect github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect + github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect github.com/containerd/console v1.0.4 // indirect + github.com/corpix/uarand v0.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/extism/go-sdk v1.7.1 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/gaissmai/bart v0.20.4 // indirect + github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/cel-go v0.27.0 // indirect github.com/google/flatbuffers v23.5.26+incompatible // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-github/v30 v30.1.0 // indirect + github.com/google/go-github/v75 v75.0.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.8 // indirect + github.com/google/jsonschema-go v0.4.2 // indirect + github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/google/s2a-go v0.1.9 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.12 // indirect github.com/gookit/color v1.5.4 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/hako/durafmt v0.0.0-20210316092057-3a2c319c1acd // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -249,6 +343,7 @@ require ( github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hc-install v0.9.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect @@ -259,20 +354,38 @@ require ( github.com/hashicorp/terraform-registry-address v0.4.0 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.2 // indirect + github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.3 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lestrrat-go/blackmagic v1.0.3 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc v1.0.6 // indirect + github.com/lestrrat-go/iter v1.0.2 // indirect + github.com/lestrrat-go/jwx/v2 v2.1.6 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lithammer/fuzzysearch v1.1.8 + github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/mholt/archives v0.1.0 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect + github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -284,41 +397,106 @@ require ( github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nuid v1.0.1 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect + github.com/nwaples/rardecode/v2 v2.2.0 // indirect github.com/oklog/run v1.1.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pkoukk/tiktoken-go v0.1.7 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/projectdiscovery/blackrock v0.0.1 // indirect + github.com/projectdiscovery/cdncheck v1.1.24 // indirect + github.com/projectdiscovery/chaos-client v0.5.2 // indirect + github.com/projectdiscovery/dnsx v1.2.2 // indirect + github.com/projectdiscovery/fastdialer v0.4.1 // indirect + github.com/projectdiscovery/goflags v0.1.74 // indirect + github.com/projectdiscovery/gologger v1.1.54 // indirect + github.com/projectdiscovery/hmap v0.0.90 // indirect + github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect + github.com/projectdiscovery/networkpolicy v0.1.16 // indirect + github.com/projectdiscovery/ratelimit v0.0.81 // indirect + github.com/projectdiscovery/retryabledns v1.0.102 // indirect + github.com/projectdiscovery/retryablehttp-go v1.0.115 // indirect + github.com/projectdiscovery/utils v0.4.21 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/refraction-networking/utls v1.8.2 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/riverqueue/apiframe v0.0.0-20251229202423-2b52ce1c482e // indirect + github.com/riverqueue/river/riverdriver v0.31.0 // indirect + github.com/riverqueue/river/rivershared v0.31.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/rs/xid v1.5.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect + github.com/samber/lo v1.52.0 // indirect + github.com/samber/slog-common v0.20.0 // indirect + github.com/segmentio/asm v1.2.0 // indirect + github.com/segmentio/encoding v0.5.3 // indirect + github.com/shirou/gopsutil/v3 v3.23.7 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sorairolake/lzip-go v0.3.5 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect + github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 // indirect + github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 // indirect + github.com/tetratelabs/wazero v1.11.0 // indirect + github.com/therootcompany/xz v1.0.1 // indirect + github.com/tidwall/btree v1.6.0 // indirect + github.com/tidwall/buntdb v1.3.0 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/grect v0.1.4 // indirect + github.com/tidwall/match v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/rtred v0.1.2 // indirect + github.com/tidwall/sjson v1.2.5 // indirect + github.com/tidwall/tinyqueue v0.1.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + github.com/ulikunitz/xz v0.5.15 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/weppos/publicsuffix-go v0.30.1 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/xiam/to v0.0.0-20191116183551-8328998fc0ed // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yuin/goldmark v1.7.10 // indirect github.com/yuin/goldmark-emoji v1.0.5 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + github.com/zcalusic/sysinfo v1.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect + github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect + github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect + go.devnw.com/structs v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect go.opentelemetry.io/otel/log v0.11.0 // indirect go.opentelemetry.io/otel/metric v1.41.0 // indirect go.opentelemetry.io/otel/schema v0.0.12 // indirect go.opentelemetry.io/otel/sdk/metric v1.41.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect + go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/mod v0.33.0 // indirect @@ -328,16 +506,26 @@ require ( golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.41.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect + gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/apiextensions-apiserver v0.35.0 // indirect + k8s.io/apiserver v0.35.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect + modernc.org/libc v1.67.6 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 sigs.k8s.io/yaml v1.6.0 // indirect ) + +require github.com/resend/resend-go/v3 v3.1.1 \ No newline at end of file diff --git a/go.sum b/go.sum index ebb34705..2183d5c8 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk= +aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho= al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= @@ -16,6 +18,15 @@ cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo= charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/aiplatform v1.119.0 h1:Fum1ighlxsmwbmaf0nhuMDebcKJkpx2mgmd1YcyXaYY= @@ -24,6 +35,8 @@ cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.74.0 h1:Q6bAMv+eyvufOpIrfrYxhM46qq1D3ZQTdgUDQqKS+n8= cloud.google.com/go/bigquery v1.74.0/go.mod h1:iViO7Cx3A/cRKcHNRsHB3yqGAMInFBswrE9Pxazsc90= cloud.google.com/go/bigtable v1.42.0 h1:SREvT4jLhJQZXUjsLmFs/1SMQJ+rKEj1cJuPE9liQs8= @@ -32,6 +45,7 @@ cloud.google.com/go/certificatemanager v1.9.6 h1:v5X8X+THKrS9OFZb6k0GRDP1WQxLXTd cloud.google.com/go/certificatemanager v1.9.6/go.mod h1:vWogV874jKZkSRDFCMM3r7wqybv8WXs3XhyNff6o/Zo= cloud.google.com/go/compute v1.56.0 h1:e8xch/mR0tJoUBj3nhNb96+MOQ1JGVGB+rBfVzWEU5I= cloud.google.com/go/compute v1.56.0/go.mod h1:fMFC0mRv+fW2ISg7M3tpDfpZ+kkrHpC/ImNFRCYiNK0= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/container v1.46.0 h1:xX94Lo3xrS5OkdMWKvpEVAbBwjN9uleVv6vOi02fL4s= @@ -42,6 +56,7 @@ cloud.google.com/go/dataplex v1.28.0 h1:rROI3iqMVI9nXT701ULoFRETQVAOAPC3mPSWFDxX cloud.google.com/go/dataplex v1.28.0/go.mod h1:VB+xlYJiJ5kreonXsa2cHPj0A3CfPh/mgiHG4JFhbUA= cloud.google.com/go/dataproc/v2 v2.16.0 h1:0g2hnjlQ8SQTnNeu+Bqqa61QPssfSZF3t+9ldRmx+VQ= cloud.google.com/go/dataproc/v2 v2.16.0/go.mod h1:HlzFg8k1SK+bJN3Zsy2z5g6OZS1D4DYiDUgJtF0gJnE= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/filestore v1.10.3 h1:3KZifUVTqGhNNv6MLeONYth1HjlVM4vDhaH+xrdPljU= cloud.google.com/go/filestore v1.10.3/go.mod h1:94ZGyLTx9j+aWKozPQ6Wbq1DuImie/L/HIdGMshtwac= cloud.google.com/go/functions v1.19.7 h1:7LcOD18euIVGRUPaeCmgO6vfWSLNIsi6STWRQcdANG8= @@ -60,6 +75,8 @@ cloud.google.com/go/networksecurity v0.11.0 h1:+ahtCqEqwHw3a3UIeG21vT817xt9kkDDA cloud.google.com/go/networksecurity v0.11.0/go.mod h1:JLgDsg4tOyJ3eMO8lypjqMftbfd60SJ+P7T+DUmWBsM= cloud.google.com/go/orgpolicy v1.15.1 h1:0hq12wxNwcfUMojr5j3EjWECSInIuyYDhkAWXTomRhc= cloud.google.com/go/orgpolicy v1.15.1/go.mod h1:bpvi9YIyU7wCW9WiXL/ZKT7pd2Ovegyr2xENIeRX5q0= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/redis v1.18.3 h1:6LI8zSt+vmE3WQ7hE5GsJ13CbJBLV1qUw6B7CY31Wcw= cloud.google.com/go/redis v1.18.3/go.mod h1:x8HtXZbvMBDNT6hMHaQ022Pos5d7SP7YsUH8fCJ2Wm4= cloud.google.com/go/resourcemanager v1.10.7 h1:oPZKIdjyVTuag+D4HF7HO0mnSqcqgjcuA18xblwA0V0= @@ -72,6 +89,8 @@ cloud.google.com/go/securitycentermanagement v1.1.6 h1:XFqjKq4ZpKTj8xCXWs/mTmh/U cloud.google.com/go/securitycentermanagement v1.1.6/go.mod h1:nt5Z6rU4s2/j8R/EQxG5K7OfVAfAfwo89j0Nx2Srzaw= cloud.google.com/go/spanner v1.88.0 h1:HS+5TuEYZOVOXj9K+0EtrbTw7bKBLrMe3vgGsbnehmU= cloud.google.com/go/spanner v1.88.0/go.mod h1:MzulBwuuYwQUVdkZXBBFapmXee3N+sQrj2T/yup6uEE= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.60.0 h1:oBfZrSOCimggVNz9Y/bXY35uUcts7OViubeddTTVzQ8= cloud.google.com/go/storage v1.60.0/go.mod h1:q+5196hXfejkctrnx+VYU8RKQr/L3c0cBIlrjmiAKE0= cloud.google.com/go/storagetransfer v1.13.1 h1:Sjukr1LtUt7vLTHNvGc2gaAqlXNFeDFRIRmWGrFaJlY= @@ -80,8 +99,13 @@ cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/otelconnect v0.9.0 h1:NggB3pzRC3pukQWaYbRHJulxuXvmCKCKkQ9hbrHAWoA= +connectrpc.com/otelconnect v0.9.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/1password/onepassword-sdk-go v0.4.0 h1:Nou39yuC6Q0om03irkh5UurfPdX3wx26qZZhQeC9TBU= +github.com/1password/onepassword-sdk-go v0.4.0/go.mod h1:j/CbzhucTywjlYrd6SE6k0LcQaFZ2l8OLBsAsOYtvD0= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= @@ -130,8 +154,10 @@ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= @@ -155,10 +181,29 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/MrAlias/otel-schema-utils v0.4.0-alpha h1:6ZG9rw4NvxKwRp2Bmnfr8WJZVWLhK4e5n3+ezXE6Z2g= github.com/MrAlias/otel-schema-utils v0.4.0-alpha/go.mod h1:baehOhES9qiLv9xMcsY6ZQlKLBRR89XVJEvU7Yz3qJk= +github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub47e7kd2PLZeACxc1LkiiNoDOFRClE= +github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4= +github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8= +github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4= +github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/PuerkitoBio/rehttp v1.4.0 h1:rIN7A2s+O9fmHUM1vUcInvlHj9Ysql4hE+Y0wcl/xk8= +github.com/PuerkitoBio/rehttp v1.4.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= +github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg= +github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/a-h/templ v0.3.1001 h1:yHDTgexACdJttyiyamcTHXr2QkIeVF1MukLy44EAhMY= +github.com/a-h/templ v0.3.1001/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo= +github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4= +github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/akedrou/textdiff v0.1.0 h1:K7nbOVQju7/coCXnJRJ2fsltTwbSvC+M4hKBUJRBRGY= +github.com/akedrou/textdiff v0.1.0/go.mod h1:a9CCC49AKtFTmVDNFHDlCg7V/M7C7QExDAhb2SkL6DQ= +github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w= +github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.16.0 h1:QC5ZMizk67+HzxFDjQ4ASjni5kWBTGiigRG1u23IGvA= @@ -169,6 +214,12 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 h1:TdGQS+RoR4AUO6gqUL74yK1dz/Arrt/WG+dxOj6Yo6A= +github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4/go.mod h1:GJxtdOs9K4neo8Gg65CjJ7jNautmldGli5/OFNabOoo= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= @@ -178,7 +229,11 @@ github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+ye github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/auth0/go-auth0/v2 v2.6.0 h1:KCoLxTcH8qXPYbwKZxxFrL/6P+P+Zc58BQPL6w0Kt30= +github.com/auth0/go-auth0/v2 v2.6.0/go.mod h1:XVRck9fw1EIw1z4guYcbKFGmElnexb+xOvQ/0U1hHd0= github.com/auth0/go-jwt-middleware/v2 v2.3.1 h1:lbDyWE9aLydb3zrank+Gufb9qGJN9u//7EbJK07pRrw= github.com/auth0/go-jwt-middleware/v2 v2.3.1/go.mod h1:mqVr0gdB5zuaFyQFWMJH/c/2hehNjbYUD4i8Dpyf+Hc= github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA= @@ -249,6 +304,8 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.62.3 h1:JRPXnIr0WwFsSHBmuCvT/uh0 github.com/aws/aws-sdk-go-v2/service/route53 v1.62.3/go.mod h1:DHddp7OO4bY467WVCqWBzk5+aEWn7vqYkap7UigJzGk= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA= +github.com/aws/aws-sdk-go-v2/service/sesv2 v1.59.4 h1:PEz6RPI6hG3GHiaMPmrh4iM684GOdIrEc9L30FaSC2k= +github.com/aws/aws-sdk-go-v2/service/sesv2 v1.59.4/go.mod h1:4dOflh7HfqHcjF1OIlt9Tr1T0rDsh906Yc75lAa2CJI= github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row= github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU= github.com/aws/aws-sdk-go-v2/service/sns v1.39.13 h1:8xP94tDzFpgwIOsusGiEFHPaqrpckDojoErk/ZFZTio= @@ -265,18 +322,50 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 h1:XQTQTF75vnug2TXS8m7CVJfC2nni github.com/aws/aws-sdk-go-v2/service/sts v1.41.8/go.mod h1:Xgx+PR1NUOjNmQY+tRMnouRp83JRM8pRMw/vCaVhPkI= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= +github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM= github.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoGXLwLQOZE= +github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY= +github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= +github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= +github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A= +github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= +github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= +github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= +github.com/bombsimon/logrusr/v4 v4.1.0 h1:uZNPbwusB0eUXlO8hIUwStE6Lr5bLN6IgYgG+75kuh4= +github.com/bombsimon/logrusr/v4 v4.1.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhOR03TRc6im0l8= +github.com/bradleyfalzon/ghinstallation/v2 v2.17.0 h1:SmbUK/GxpAspRjSQbB6ARvH+ArzlNzTtHydNyXUQ6zg= +github.com/bradleyfalzon/ghinstallation/v2 v2.17.0/go.mod h1:vuD/xvJT9Y+ZVZRv4HQ42cMyPFIYqpc7AbB4Gvt/DlY= github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= +github.com/brianvoe/gofakeit/v7 v7.14.1 h1:a7fe3fonbj0cW3wgl5VwIKfZtiH9C3cLnwcIXWT7sow= +github.com/brianvoe/gofakeit/v7 v7.14.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY= @@ -301,19 +390,36 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8 github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= +github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo= +github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/corpix/uarand v0.2.0 h1:U98xXwud/AVuCpkpgfPF7J5TQgr7R5tqT8VZP5KWbzE= +github.com/corpix/uarand v0.2.0/go.mod h1:/3Z1QIqWkDIhf6XWn/08/uMHoQ8JUoTIKc2iPchBOmM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= @@ -321,22 +427,42 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= +github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +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/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 h1:idfl8M8rPW93NehFw5H1qqH8yG158t5POr+LX9avbJY= +github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1/go.mod h1:C8DzXehI4zAbrdlbtOByKX6pfivJTBiV9Jjqv56Yd9Q= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw= +github.com/extism/go-sdk v1.7.1/go.mod h1:IT+Xdg5AZM9hVtpFUA+uZCJMge/hbvshl8bwzLtFyKA= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -344,12 +470,23 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= +github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gaissmai/bart v0.20.4 h1:Ik47r1fy3jRVU+1eYzKSW3ho2UgBVTVnUS8O993584U= +github.com/gaissmai/bart v0.20.4/go.mod h1:cEed+ge8dalcbpi8wtS9x9m2hn/fNJH5suhdGQOHnYk= github.com/getsentry/sentry-go v0.43.0 h1:XbXLpFicpo8HmBDaInk7dum18G9KSLcjZiyUKS+hLW4= github.com/getsentry/sentry-go v0.43.0/go.mod h1:XDotiNZbgf5U8bPDUAfvcFmOnMQQceESxyKaObSssW0= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -358,36 +495,77 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e h1:Lf/gRkoycfOBPa42vU2bbgPurFong6zXeFtPoxholzU= +github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= +github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= +github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= @@ -396,17 +574,45 @@ github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8i github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= +github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= +github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= +github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= +github.com/google/go-github/v75 v75.0.0 h1:k7q8Bvg+W5KxRl9Tjq16a9XEgVY1pwuiG5sIL7435Ic= +github.com/google/go-github/v75 v75.0.0/go.mod h1:H3LUJEA1TCrzuUqtdAQniBNwuKiQIqdGKgBo1/M/uqI= +github.com/google/go-github/v80 v80.0.0 h1:BTyk3QOHekrk5VF+jIGz1TNEsmeoQG9K/UWaaP+EWQs= +github.com/google/go-github/v80 v80.0.0/go.mod h1:pRo4AIMdHW83HNMGfNysgSAv0vmu+/pkY8nZO9FT9Yo= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= +github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -415,6 +621,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.12 h1:Fg+zsqzYEs1ZnvmcztTYxhgCBsx3eEhEwQ1W/lHq/sQ= github.com/googleapis/enterprise-certificate-proxy v0.3.12/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= @@ -425,8 +633,14 @@ github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IP github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/hako/durafmt v0.0.0-20210316092057-3a2c319c1acd h1:FsX+T6wA8spPe4c1K9vi7T0LvNCO1TTqiL8u7Wok2hw= +github.com/hako/durafmt v0.0.0-20210316092057-3a2c319c1acd/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= +github.com/harness/harness-go-sdk v0.7.13 h1:lLiliIivyXW/8L7n244q45hdVKNCYprnfztyes4ew7k= +github.com/harness/harness-go-sdk v0.7.13/go.mod h1:iEAGFfIm0MOFJxN6tqMQSPZiEO/Dz1joLDHrkEU3lps= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -450,6 +664,10 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +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/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -482,8 +700,24 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8 github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f h1:Fnl4pzx8SR7k7JuzyW8lEtSFH6EQ8xgcypgIn8pcGIE= +github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= +github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 h1:D/V0gu4zQ3cL2WKeVNVM4r2gLxGGf6McLwgXzRTo2RQ= +github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -492,21 +726,39 @@ github.com/jedib0t/go-pretty/v6 v6.7.8 h1:BVYrDy5DPBA3Qn9ICT+PokP9cvCv1KaHv2i+Hc github.com/jedib0t/go-pretty/v6 v6.7.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= +github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= +github.com/kaptinlin/jsonrepair v0.2.17 h1:fkEom1MBG98QeN7uaJpKBRA9st3bPdS32RK+im/IjCU= +github.com/kaptinlin/jsonrepair v0.2.17/go.mod h1:Hbq/F0frQBVClHW/oQXixaCPysZ6gdzpeUBZPpWQtAQ= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -516,12 +768,36 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs= +github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k= +github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= +github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= +github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx/v2 v2.1.6 h1:hxM1gfDILk/l5ylers6BX/Eq1m/pnxe9NBwW6lVfecA= +github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= @@ -534,6 +810,14 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mavolin/go-htmx v1.0.0 h1:43rZuemWd23zrMcTU939EsflXjOPxtHy9VraT1CZ6qQ= +github.com/mavolin/go-htmx v1.0.0/go.mod h1:r6O09gzKou9kutq3UiDPZ//Q7IeBCMcs8US5/sHFbvg= +github.com/mergestat/timediff v0.0.4 h1:NZ3sqG/6K9flhTubdltmRx3RBfIiYv6LsGP+4FlXMM8= +github.com/mergestat/timediff v0.0.4/go.mod h1:yvMUaRu2oetc+9IbPLYBJviz6sA7xz8OXMDfhBl7YSI= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= +github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q= +github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I= github.com/micahhausler/aws-iam-policy v0.4.4 h1:1aMhJ+0CkvUJ8HGN1chX+noXHs8uvGLkD7xIBeYd31c= github.com/micahhausler/aws-iam-policy v0.4.4/go.mod h1:H+yWljTu4XWJjNJJYgrPUai0AUTGNHc8pumkN57/foI= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= @@ -542,10 +826,14 @@ github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc= +github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -554,12 +842,16 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modelcontextprotocol/go-sdk v1.4.0 h1:u0kr8lbJc1oBcawK7Df+/ajNMpIDFE41OEPxdeTLOn8= +github.com/modelcontextprotocol/go-sdk v1.4.0/go.mod h1:Nxc2n+n/GdCebUaqCOhTetptS17SXXNu9IfNTaLDi1E= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= +github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= @@ -578,16 +870,36 @@ github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/neo4j/neo4j-go-driver/v6 v6.0.0 h1:xVAi6YLOfzXUx+1Lc/F2dUhpbN76BfKleZbAlnDFRiA= +github.com/neo4j/neo4j-go-driver/v6 v6.0.0/go.mod h1:hzSTfNfM31p1uRSzL1F/BAYOgaiTarE6OAQBajfsm+I= +github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= +github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= 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.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE= +github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= github.com/openrdap/rdap v0.9.2-0.20240517203139-eb57b3a8dedd h1:UuQycBx6K0lB0/IfHePshOYjlrptkF4FoApFP2Y4s3k= github.com/openrdap/rdap v0.9.2-0.20240517203139-eb57b3a8dedd/go.mod h1:391Ww1JbjG4FHOlvQqCd6n25CCCPE64JzC5cCYPxhyM= +github.com/overmindtech/otelpgx v0.10.1-0.20260303210427-65bf1016045e h1:vP/Zs8Nbd902stVf7hBOd3VP/lIECgAjWR8pNBwcOu4= +github.com/overmindtech/otelpgx v0.10.1-0.20260303210427-65bf1016045e/go.mod h1:GtSjAg9Irz03mc8tPIh9/bKOx63sqyO752SABZhBdj0= github.com/overmindtech/pterm v0.0.0-20240919144758-04d94ccb2297 h1:ih4bqBMHTCtg3lMwJszNkMGO9n7Uoe0WX5be1/x+s+g= github.com/overmindtech/pterm v0.0.0-20240919144758-04d94ccb2297/go.mod h1:bRQZYnvLrW1S5wYT6tbQnun8NpO5X6zP5cY3VKuDc4U= +github.com/pborman/ansi v1.0.0 h1:OqjHMhvlSuCCV5JT07yqPuJPQzQl+WXsiZ14gZsqOrQ= +github.com/pborman/ansi v1.0.0/go.mod h1:SgWzwMAx1X/Ez7i90VqF8LRiQtx52pWDiQP+x3iGnzw= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -602,13 +914,58 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmd github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkoukk/tiktoken-go v0.1.7 h1:qOBHXX4PHtvIvmOtyg1EeKlwFRiMKAcoMp4Q+bLQDmw= +github.com/pkoukk/tiktoken-go v0.1.7/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posthog/posthog-go v1.10.0 h1:wfoy7Jfb4LigCoHYyMZoiJmmEoCLOkSaYfDxM/NtCqY= +github.com/posthog/posthog-go v1.10.0/go.mod h1:wB3/9Q7d9gGb1P/yf/Wri9VBlbP8oA8z++prRzL5OcY= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= +github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= +github.com/projectdiscovery/cdncheck v1.1.24 h1:6pJ4XnovIrTWzlCJs5/QD1tv6wvK0wiICmmdY0/8WAs= +github.com/projectdiscovery/cdncheck v1.1.24/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U= +github.com/projectdiscovery/chaos-client v0.5.2 h1:dN+7GXEypsJAbCD//dBcUxzAEAEH1fjc/7Rf4F/RiNU= +github.com/projectdiscovery/chaos-client v0.5.2/go.mod h1:KnoJ/NJPhll42uaqlDga6oafFfNw5l2XI2ajRijtDuU= +github.com/projectdiscovery/dnsx v1.2.2 h1:ZjUov0GOyrS8ERlKAAhk+AOkqzaYHBzCP0qZfO+6Ihg= +github.com/projectdiscovery/dnsx v1.2.2/go.mod h1:3iYm86OEqo0WxeGDkVl5WZNmG0qYE5TYNx8fBg6wX1I= +github.com/projectdiscovery/fastdialer v0.4.1 h1:kp6Q0odo0VZ0vZIGOn+q9aLgBSk6uYoD1MsjCAH8+h4= +github.com/projectdiscovery/fastdialer v0.4.1/go.mod h1:875Wlggf0JAz+fDIPwUQeeBqEF6nJA71XVrjuTZCV7I= +github.com/projectdiscovery/goflags v0.1.74 h1:n85uTRj5qMosm0PFBfsvOL24I7TdWRcWq/1GynhXS7c= +github.com/projectdiscovery/goflags v0.1.74/go.mod h1:UMc9/7dFz2oln+10tv6cy+7WZKTHf9UGhaNkF95emh4= +github.com/projectdiscovery/gologger v1.1.54 h1:WMzvJ8j/4gGfPKpCttSTaYCVDU1MWQSJnk3wU8/U6Ws= +github.com/projectdiscovery/gologger v1.1.54/go.mod h1:vza/8pe2OKOt+ujFWncngknad1XWr8EnLKlbcejOyUE= +github.com/projectdiscovery/hmap v0.0.90 h1:p8HWGvPI88hgJoAb4ayR1Oo5VzqPrOCdFG7mASUhQI4= +github.com/projectdiscovery/hmap v0.0.90/go.mod h1:dcjd9P82mkBpFGEy0wBU/3qql5Bx14kmJZvVg7o7vXY= +github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE= +github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI= +github.com/projectdiscovery/networkpolicy v0.1.16 h1:H2VnLmMD7SvxF+rao+639nn8KX/kbPFY+mc8FxeltsI= +github.com/projectdiscovery/networkpolicy v0.1.16/go.mod h1:Vs/IRcJq4QUicjd/tl9gkhQWy7d/LssOwWbaz4buJ0U= +github.com/projectdiscovery/ratelimit v0.0.81 h1:u6lW+rAhS/UO0amHTYmYLipPK8NEotA9521hdojBtgI= +github.com/projectdiscovery/ratelimit v0.0.81/go.mod h1:tK04WXHuC4i6AsFkByInODSNf45gd9sfaMHzmy2bAsA= +github.com/projectdiscovery/retryabledns v1.0.102 h1:R8PzFCVofqLX3Bn4kdjOsE9wZ83FQjXZMDNs4/bHxzI= +github.com/projectdiscovery/retryabledns v1.0.102/go.mod h1:3+GL+YuHpV0Fp6UG7MbIG8mVxXHjfPO5ioQdwlnV08E= +github.com/projectdiscovery/retryablehttp-go v1.0.115 h1:ubIaVyHNj0/qxNv4gar+8/+L3G2Fhpfk54iMDctC7+E= +github.com/projectdiscovery/retryablehttp-go v1.0.115/go.mod h1:XlxLSMBVM7fTXeLVOLjVn1FLuRgQtD49NMFs9sQygfA= +github.com/projectdiscovery/subfinder/v2 v2.12.0 h1:MgEYn0F2qLvr63BWpV9jNjFiD8i9oXI3dp02tAGRft0= +github.com/projectdiscovery/subfinder/v2 v2.12.0/go.mod h1:FNy+bkJwZjUUWLte6T91IRBISqWDZ/q+ygUmoe8eb/w= +github.com/projectdiscovery/utils v0.4.21 h1:yAothTUSF6NwZ9yoC4iGe5gSBrovqKR9JwwW3msxk3Q= +github.com/projectdiscovery/utils v0.4.21/go.mod h1:HJuJFqjB6EmVaDl0ilFPKvLoMaX2GyE6Il2TqKXNs8I= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= @@ -618,24 +975,82 @@ github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5b github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/pterm/pterm v0.12.53 h1:8ERV5eXyvXlAIY8LRrhapPS34j7IKKDAnb7o1Ih3T0w= github.com/pterm/pterm v0.12.53/go.mod h1:BY2H3GtX2BX0ULqLY11C2CusIqnxsYerbkil3XvXIBg= +github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf h1:NxGxgo0KmC8w9fdn8jLCyG1SDrR/Vxbfa1nWErS3pmw= +github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf/go.mod h1:q6RK8Iv6obzk6i0rnLyYPtppwZ5uXJLloL3oxmfrwm8= +github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo= +github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/resend/resend-go/v3 v3.1.1 h1:Uwpf/tZU+O/r/3nMWE6zUAMIG9dX/vTBS3wlQzYJKSw= +github.com/resend/resend-go/v3 v3.1.1/go.mod h1:iI7VA0NoGjWvsNii5iNC5Dy0llsI3HncXPejhniYzwE= +github.com/riverqueue/apiframe v0.0.0-20251229202423-2b52ce1c482e h1:OwOgxT3MRpOj5Mp6DhFdZP43FOQOf2hhywAuT5XZCR4= +github.com/riverqueue/apiframe v0.0.0-20251229202423-2b52ce1c482e/go.mod h1:O7UmsAMjpMYuToN4au5GNXdmN1gli+5FTldgXqAfaD0= +github.com/riverqueue/river v0.31.0 h1:BERwce/WS4Guter0/A3GyTDP+1rxl6vFHyBQv+U/5tM= +github.com/riverqueue/river v0.31.0/go.mod h1:Aqbb/jBrFMvh6rbe6SDC6XVZnS0v1W+QQPjejRvyHzk= +github.com/riverqueue/river/riverdriver v0.31.0 h1:XwDa8DqkRxkqMqfdLOYTgSykiTHNSRcWG1LcCg/g0ys= +github.com/riverqueue/river/riverdriver v0.31.0/go.mod h1:Vl6XPbWtjqP+rqEa/HxcEeXeZL/KPCwqjRlqj+wWsq8= +github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0 h1:Zii6/VNqasBuPvFIA98xgjz3MRy2EvMm6lMyh1RtWBw= +github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0/go.mod h1:z859lpsOraO3IYWjY9w8RZec5I0BAcas9rjZkwxAijU= +github.com/riverqueue/river/rivershared v0.31.0 h1:KVEp+13jnK9YOlMUKnR0eUyJaK+P/APcheoSGMfZArA= +github.com/riverqueue/river/rivershared v0.31.0/go.mod h1:Wvf489bvAiZsJm7mln8YAPZbK7pVfuK7bYfsBt5Nzbw= +github.com/riverqueue/river/rivertype v0.31.0 h1:O6vaJ72SffgF1nxzCrDKd4M+eMZFRlJpycnOcUIGLD8= +github.com/riverqueue/river/rivertype v0.31.0/go.mod h1:D1Ad+EaZiaXbQbJcJcfeicXJMBKno0n6UcfKI5Q7DIQ= +github.com/riverqueue/rivercontrib/otelriver v0.7.0 h1:zLjPf674dcGrz7OPG2JF5xea0fyitFax6Cc6q370Xzo= +github.com/riverqueue/rivercontrib/otelriver v0.7.0/go.mod h1:MuyMZmYBz3JXC8ZLP0dH9IqXK95qRY6gCQSoJGh9h7E= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= +github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/samber/slog-common v0.20.0 h1:WaLnm/aCvBJSk5nR5aXZTFBaV0B47A+AEaEOiZDeUnc= +github.com/samber/slog-common v0.20.0/go.mod h1:+Ozat1jgnnE59UAlmNX1IF3IByHsODnnwf9jUcBZ+m8= +github.com/samber/slog-logrus/v2 v2.5.3 h1:N6YGgQ9CQjUQXe75/iWKtE55EENjG67HYUsJQbPn/dE= +github.com/samber/slog-logrus/v2 v2.5.3/go.mod h1:W3njRsspuMRCd33S0ibPyK1ohRaMhuXKZ1BK8pNiM+c= +github.com/sashabaranov/go-openai v1.41.2 h1:vfPRBZNMpnqu8ELsclWcAvF19lDNgh1t6TVfFFOPiSM= +github.com/sashabaranov/go-openai v1.41.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= +github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/serpapi/serpapi-golang v0.0.0-20260126142127-0e41c7993cda h1:w3JksZEWJDI7x+No5yh2/8S86hq1dmJy7n5btakG30U= +github.com/serpapi/serpapi-golang v0.0.0-20260126142127-0e41c7993cda/go.mod h1:xVL4PnCuCPwkXhVVQysVrX3hEv7nWnIbfnDj2B+hsPw= +github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= +github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg= +github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -654,10 +1069,12 @@ github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xI github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -670,10 +1087,61 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stripe/stripe-go/v84 v84.4.0 h1:JMQMqb+mhW6tns+eYA3G5SZiaoD2ULwN0lZ+kNjWAsY= +github.com/stripe/stripe-go/v84 v84.4.0/go.mod h1:Z4gcKw1zl4geDG2+cjpSaJES9jaohGX6n7FP8/kHIqw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk= +github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA= +github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 h1:ZF+QBjOI+tILZjBaFj3HgFonKXUcwgJ4djLb6i42S3Q= +github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834/go.mod h1:m9ymHTgNSEjuxvw8E7WWe4Pl4hZQHXONY8wE6dMLaRk= +github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA= +github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU= +github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= +github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= +github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI= +github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8= +github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= +github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA= +github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg= +github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q= +github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= +github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8= +github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE= +github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw= +github.com/tiktoken-go/tokenizer v0.7.0 h1:VMu6MPT0bXFDHr7UPh9uii7CNItVt3X9K90omxL54vw= +github.com/tiktoken-go/tokenizer v0.7.0/go.mod h1:6UCYI/DtOallbmL7sSy30p6YQv60qNyU/4aVigPOx6w= +github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2 h1:H8wwQwTe5sL6x30z71lUgNiwBdeCHQjrphCfLwqIHGo= github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2/go.mod h1:/kR4beFhlz2g+V5ik8jW+3PMiMQAPt29y6K64NNY53c= github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 h1:3/aHKUq7qaFMWxyQV0W2ryNgg8x8rVeKVA20KJUkfS0= @@ -685,6 +1153,12 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= +github.com/weppos/publicsuffix-go v0.30.1 h1:8q+QwBS1MY56Zjfk/50ycu33NN8aa1iCCEQwo/71Oos= +github.com/weppos/publicsuffix-go v0.30.1/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -698,12 +1172,23 @@ github.com/xiam/to v0.0.0-20191116183551-8328998fc0ed/go.mod h1:cqbG7phSzrbdg3aj github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= +github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= +github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= +github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI= github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yuin/goldmark-emoji v1.0.5 h1:EMVWyCGPlXJfUXBXpuMu+ii3TIaxbVBnEX9uaDC4cIk= github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc= +github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30= github.com/zclconf/go-cty v1.18.0 h1:pJ8+HNI4gFoyRNqVE37wWbJWVw43BZczFo7KUoRczaA= github.com/zclconf/go-cty v1.18.0/go.mod h1:qpnV6EDNgC1sns/AleL1fvatHw72j+S+nS+MJ+T2CSg= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= @@ -712,8 +1197,24 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30= +github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk= +github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= +github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= +github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 h1:YOQ1vXEwE4Rnj+uQ/3oCuJk5wgVsvUyW+glsndwYuyA= +github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21S5Z9bK1BMrertTGX/F8hgAPw7ERJRNS0= +github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= +go.devnw.com/structs v1.0.0 h1:FFkBoBOkapCdxFEIkpOZRmMOMr9b9hxjKTD3bJYl9lk= +go.devnw.com/structs v1.0.0/go.mod h1:wHBkdQpNeazdQHszJ2sxwVEpd8zGTEsKkeywDLGbrmg= go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/detectors/aws/ec2/v2 v2.0.0-20250901115419-474a7992e57c h1:YSqSR1Fil5Ip0N6AlNBFbNv7cvIHZ2j4+wqbVafAGmQ= @@ -728,6 +1229,8 @@ go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8= @@ -754,101 +1257,278 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= +go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo= golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= +gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.269.0 h1:qDrTOxKUQ/P0MveH6a7vZ+DNHxJQjtGm/uvdbdGXCQg= google.golang.org/api v0.269.0/go.mod h1:N8Wpcu23Tlccl0zSHEkcAZQKDLdquxK+l9r2LkwAauE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -856,34 +1536,91 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= +gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= +gopkg.in/dnaeon/go-vcr.v3 v3.2.0 h1:Rltp0Vf+Aq0u4rQXgmXgtgoRDStTnFN83cWgSGSoRzM= +gopkg.in/dnaeon/go-vcr.v3 v3.2.0/go.mod h1:2IMOnnlx9I6u9x+YBsM3tAMx6AlOxnJ0pWxQAzZ79Ag= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw= k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60= +k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4= +k8s.io/apiextensions-apiserver v0.35.0/go.mod h1:E1Ahk9SADaLQ4qtzYFkwUqusXTcaV2uw3l14aqpL2LU= k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8= k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/apiserver v0.35.0 h1:CUGo5o+7hW9GcAEF3x3usT3fX4f9r8xmgQeCBDaOgX4= +k8s.io/apiserver v0.35.0/go.mod h1:QUy1U4+PrzbJaM3XGu2tQ7U9A4udRRo5cyxkFX0GEds= k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o= k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g= +k8s.io/component-base v0.35.2 h1:btgR+qNrpWuRSuvWSnQYsZy88yf5gVwemvz0yw79pGc= +k8s.io/component-base v0.35.2/go.mod h1:B1iBJjooe6xIJYUucAxb26RwhAjzx0gHnqO9htWIX+0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= +modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= +modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= +modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= +modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= +modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU= +modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +riverqueue.com/riverui v0.15.0 h1:7Xm/tqv63jZrGSv4X2u4zpAvbtXSs835Qk4RFonBDdk= +riverqueue.com/riverui v0.15.0/go.mod h1:J4fH8+zPe1cqmYWuMWVJdDdMmq1U2UPVofyOczGZNnw= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0 h1:XotDXzqvJ8Nx5eiZZueLpTuafJz8SiodgOemI+w87QU= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80= +sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/kind v0.31.0 h1:UcT4nzm+YM7YEbqiAKECk+b6dsvc/HRZZu9U0FolL1g= From 096a0a5d6cef0e38029d0756d0e18fd69a351e36 Mon Sep 17 00:00:00 2001 From: carabasdaniel Date: Mon, 9 Mar 2026 18:11:38 +0200 Subject: [PATCH 02/18] fix: pin Alpine to 3.23.3 and upgrade zlib to remediate CVE-2026-22184 (#4193) Pin all runtime Alpine base images from 3.23 to 3.23.3 (ships zlib 1.3.2-r0) and add apk upgrade --no-cache to builder stages using golang:1.26-alpine, node:24-alpine, and nats:alpine where the base Alpine version cannot be pinned directly. --- > [!NOTE] > **Low Risk** > Low risk: changes are limited to Docker base image patch pinning and package upgrades, but they can affect container build reproducibility and potentially introduce subtle runtime/library differences. > > **Overview** > Pins all Alpine runtime stages from `alpine:3.23` to `alpine:3.23.3` across Go-based services/sources (and multi-stage images like `api-server`, `gateway`, `revlink`, `srcman`, etc.). > > Adds `apk upgrade --no-cache` to builder/base stages that inherit Alpine indirectly (`golang:1.26-alpine`, `node:24-alpine`, and `nats:alpine`) before installing required packages, ensuring patched system libraries (e.g., zlib) are picked up during image builds. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit a8089e8113c4afcbc923f40d9de442f4227fac31. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 77fdaa992e127a8accaaa2328be36977e9c616fe --- aws-source/build/package/Dockerfile | 4 ++-- k8s-source/build/package/Dockerfile | 4 ++-- sources/azure/build/package/Dockerfile | 4 ++-- sources/gcp/build/package/Dockerfile | 4 ++-- stdlib-source/build/package/Dockerfile | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aws-source/build/package/Dockerfile b/aws-source/build/package/Dockerfile index e6cd5153..6f9aba9d 100644 --- a/aws-source/build/package/Dockerfile +++ b/aws-source/build/package/Dockerfile @@ -6,7 +6,7 @@ ARG BUILD_VERSION ARG BUILD_COMMIT # required for generating the version descriptor -RUN apk add --no-cache git +RUN apk upgrade --no-cache && apk add --no-cache git WORKDIR /workspace @@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/go/pkg \ --mount=type=cache,target=/root/.cache/go-build \ GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/go/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/go/tracing.commit=${BUILD_COMMIT}" -o source aws-source/main.go -FROM alpine:3.23 +FROM alpine:3.23.3 WORKDIR / COPY --from=builder /workspace/source . USER 65534:65534 diff --git a/k8s-source/build/package/Dockerfile b/k8s-source/build/package/Dockerfile index f579cf84..566ca10e 100644 --- a/k8s-source/build/package/Dockerfile +++ b/k8s-source/build/package/Dockerfile @@ -6,7 +6,7 @@ ARG BUILD_VERSION ARG BUILD_COMMIT # required for accessing the private dependencies and generating version descriptor -RUN apk add --no-cache git curl +RUN apk upgrade --no-cache && apk add --no-cache git curl WORKDIR /workspace @@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/go/pkg \ --mount=type=cache,target=/root/.cache/go-build \ GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/go/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/go/tracing.commit=${BUILD_COMMIT}" -o source k8s-source/main.go -FROM alpine:3.23 +FROM alpine:3.23.3 WORKDIR / COPY --from=builder /workspace/source . USER 65534:65534 diff --git a/sources/azure/build/package/Dockerfile b/sources/azure/build/package/Dockerfile index 1fc2d532..a31baa68 100644 --- a/sources/azure/build/package/Dockerfile +++ b/sources/azure/build/package/Dockerfile @@ -6,7 +6,7 @@ ARG BUILD_VERSION ARG BUILD_COMMIT # required for generating the version descriptor -RUN apk add --no-cache git +RUN apk upgrade --no-cache && apk add --no-cache git WORKDIR /workspace @@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/go/pkg \ --mount=type=cache,target=/root/.cache/go-build \ GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/go/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/go/tracing.commit=${BUILD_COMMIT}" -o source sources/azure/main.go -FROM alpine:3.23 +FROM alpine:3.23.3 WORKDIR / COPY --from=builder /workspace/source . USER 65534:65534 diff --git a/sources/gcp/build/package/Dockerfile b/sources/gcp/build/package/Dockerfile index bfd42f67..f90fad0a 100644 --- a/sources/gcp/build/package/Dockerfile +++ b/sources/gcp/build/package/Dockerfile @@ -6,7 +6,7 @@ ARG BUILD_VERSION ARG BUILD_COMMIT # required for generating the version descriptor -RUN apk add --no-cache git +RUN apk upgrade --no-cache && apk add --no-cache git WORKDIR /workspace @@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/go/pkg \ --mount=type=cache,target=/root/.cache/go-build \ GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/go/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/go/tracing.commit=${BUILD_COMMIT}" -o source sources/gcp/main.go -FROM alpine:3.23 +FROM alpine:3.23.3 WORKDIR / COPY --from=builder /workspace/source . USER 65534:65534 diff --git a/stdlib-source/build/package/Dockerfile b/stdlib-source/build/package/Dockerfile index 4c8d1112..0ea8527d 100644 --- a/stdlib-source/build/package/Dockerfile +++ b/stdlib-source/build/package/Dockerfile @@ -6,7 +6,7 @@ ARG BUILD_VERSION ARG BUILD_COMMIT # required for accessing the private dependencies and generating version descriptor -RUN apk add --no-cache git curl +RUN apk upgrade --no-cache && apk add --no-cache git curl WORKDIR /workspace @@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/go/pkg \ --mount=type=cache,target=/root/.cache/go-build \ GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/go/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/go/tracing.commit=${BUILD_COMMIT}" -o source stdlib-source/main.go -FROM alpine:3.23 +FROM alpine:3.23.3 WORKDIR / COPY --from=builder /workspace/source . USER 65534:65534 From 76874cd74968568c5c3f8dfc264b440616e55d45 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Mon, 9 Mar 2026 17:16:43 +0100 Subject: [PATCH 03/18] fix(deps): update module github.com/auth0/go-jwt-middleware/v2 to v3 (#4145) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :video_camera: https://www.loom.com/share/4049912c73734143a8dde39ebf3f4fe6 :video_camera: This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [github.com/auth0/go-jwt-middleware/v2](https://redirect.github.com/auth0/go-jwt-middleware) | `v2.3.1` → `v3.0.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fauth0%2fgo-jwt-middleware%2fv2/v3.0.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fauth0%2fgo-jwt-middleware%2fv2/v2.3.1/v3.0.0?slim=true) | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/370) for more information. --- ### Release Notes
auth0/go-jwt-middleware (github.com/auth0/go-jwt-middleware/v2) ### [`v3.0.0`](https://redirect.github.com/auth0/go-jwt-middleware/blob/HEAD/CHANGELOG.md#v300-2026-01-19) [Compare Source](https://redirect.github.com/auth0/go-jwt-middleware/compare/v2.3.1...v3.0.0) [Full Changelog](https://redirect.github.com/auth0/go-jwt-middleware/compare/v2.3.1...v3.0.0) **BEFORE YOU UPGRADE** - This is a major release that includes breaking changes. Please see [MIGRATION\_GUIDE.md](MIGRATION_GUIDE.md) before upgrading. This release will require changes to your application. ##### Added - Pure options pattern for validator, middleware, and JWKS provider ([#​357](https://redirect.github.com/auth0/go-jwt-middleware/pull/357), [#​358](https://redirect.github.com/auth0/go-jwt-middleware/pull/358), [#​360](https://redirect.github.com/auth0/go-jwt-middleware/pull/360)) - DPoP (Demonstrating Proof-of-Possession) support per RFC 9449 ([#​363](https://redirect.github.com/auth0/go-jwt-middleware/pull/363)) - Framework-agnostic core package for reusable validation logic ([#​356](https://redirect.github.com/auth0/go-jwt-middleware/pull/356)) - Type-safe claims retrieval with generics (`GetClaims[T]()`, `MustGetClaims[T]()`, `HasClaims()`) - Structured logging support compatible with `log/slog` - Support for 14 signature algorithms (HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, ES256K, EdDSA) - Enhanced error responses with RFC 6750 compliance - Trusted proxy configuration for DPoP behind reverse proxies - Multiple issuer and audience support with new APIs - Documentation and linting configuration ([#​361](https://redirect.github.com/auth0/go-jwt-middleware/pull/361)) ##### Changed - Migrated from square/go-jose to lestrrat-go/jwx v3 ([#​358](https://redirect.github.com/auth0/go-jwt-middleware/pull/358)) - Module path updated to `github.com/auth0/go-jwt-middleware/v3` ([#​355](https://redirect.github.com/auth0/go-jwt-middleware/pull/355)) - Minimum Go version updated to 1.24 ([#​355](https://redirect.github.com/auth0/go-jwt-middleware/pull/355)) - Update examples for v3 module path and new APIs ##### Breaking - Pure options pattern: All constructors (`New()`) now require functional options instead of positional parameters - Context key: `ContextKey{}` is no longer exported - use `GetClaims[T]()` helper function - Custom claims now use generics for type safety - `TokenExtractor` returns `ExtractedToken` (with scheme) instead of `string` - Type naming: `ExclusionUrlHandler` renamed to `ExclusionURLHandler` ##### Migration Example **v2:** ```go // Validator with positional parameters jwtValidator, err := validator.New( keyFunc, validator.RS256, "https://issuer.example.com/", []string{"my-api"}, ) // Middleware middleware := jwtmiddleware.New(jwtValidator.ValidateToken) // Claims access via context key claims := r.Context().Value(jwtmiddleware.ContextKey{}).(*validator.ValidatedClaims) ``` **v3:** ```go // Validator with pure options jwtValidator, err := validator.New( validator.WithKeyFunc(keyFunc), validator.WithAlgorithm(validator.RS256), validator.WithIssuer("https://issuer.example.com/"), validator.WithAudience("my-api"), ) // Middleware with options middleware, err := jwtmiddleware.New( jwtmiddleware.WithValidator(jwtValidator), ) // Type-safe claims with generics claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context()) ``` See [MIGRATION\_GUIDE.md](MIGRATION_GUIDE.md) for complete migration instructions. ***
--- ### Configuration 📅 **Schedule**: Branch creation - "before 10am on friday" in timezone Europe/London, Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/overmindtech/workspace). --- > [!NOTE] > **High Risk** > Upgrades a major authentication dependency and rewrites JWT validation/claim extraction paths, so mistakes could break auth enforcement or token parsing across the API server. > > **Overview** > Migrates the codebase from `github.com/auth0/go-jwt-middleware/v2` to `v3`, updating JWKS provider/validator/middleware construction to the new options-based APIs and adjusting token extraction/claims retrieval. > > Because `v3` no longer exposes `ContextKey{}`, the auth middleware now stores `*validator.ValidatedClaims` under a new `auth.ValidatedClaimsContextKey{}` and updates downstream callers (e.g. token expiry in `ManagementServiceHandler.CreateToken`) accordingly. The API server init path now skips validator setup when `AllowUnauthenticated` is enabled and tightens startup validation/error logging for missing Auth0 config; related tests set `AllowUnauthenticated: true` to accommodate `v3` rejecting empty audience/domain values. > > Also updates `go.mod`/`go.sum` for new transitive deps pulled in by `v3` (e.g. `lestrrat-go/jwx/v3`) and adds `github.com/resend/resend-go/v3` to the main require block. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e8a54151abc72beb9973302047684ad983aa5b8e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: f8185846b5c05bebfd88c56b76c4d1bb95a592db --- go.mod | 16 ++++--- go.sum | 26 ++++++++---- go/auth/middleware.go | 87 ++++++++++++++++++++++++-------------- go/auth/middleware_test.go | 2 +- 4 files changed, 85 insertions(+), 46 deletions(-) diff --git a/go.mod b/go.mod index 243def89..1be6565a 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,7 @@ require ( github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 github.com/antihax/optional v1.0.0 github.com/auth0/go-auth0/v2 v2.6.0 - github.com/auth0/go-jwt-middleware/v2 v2.3.1 + github.com/auth0/go-jwt-middleware/v3 v3.0.0 github.com/aws/aws-sdk-go-v2 v1.41.3 github.com/aws/aws-sdk-go-v2/config v1.32.11 github.com/aws/aws-sdk-go-v2/credentials v1.19.11 @@ -150,6 +150,7 @@ require ( github.com/posthog/posthog-go v1.10.0 github.com/projectdiscovery/subfinder/v2 v2.12.0 github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf + github.com/resend/resend-go/v3 v3.1.1 github.com/riverqueue/river v0.31.0 github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0 github.com/riverqueue/river/rivertype v0.31.0 @@ -367,12 +368,17 @@ require ( github.com/klauspost/pgzip v1.2.6 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lestrrat-go/blackmagic v1.0.3 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect + github.com/lestrrat-go/dsig v1.0.0 // indirect + github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect + github.com/lestrrat-go/httprc/v3 v3.0.3 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/jwx/v2 v2.1.6 // indirect + github.com/lestrrat-go/jwx/v3 v3.0.12 // indirect github.com/lestrrat-go/option v1.0.1 // indirect + github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/lithammer/fuzzysearch v1.1.8 github.com/logrusorgru/aurora v2.0.3+incompatible // indirect @@ -437,7 +443,7 @@ require ( github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect github.com/samber/lo v1.52.0 // indirect github.com/samber/slog-common v0.20.0 // indirect - github.com/segmentio/asm v1.2.0 // indirect + github.com/segmentio/asm v1.2.1 // indirect github.com/segmentio/encoding v0.5.3 // indirect github.com/shirou/gopsutil/v3 v3.23.7 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect @@ -466,6 +472,7 @@ require ( github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect github.com/ulikunitz/xz v0.5.15 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect + github.com/valyala/fastjson v1.6.7 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -511,7 +518,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/apiextensions-apiserver v0.35.0 // indirect k8s.io/apiserver v0.35.0 // indirect @@ -527,5 +533,3 @@ require ( sigs.k8s.io/structured-merge-diff/v6 v6.3.2 sigs.k8s.io/yaml v1.6.0 // indirect ) - -require github.com/resend/resend-go/v3 v3.1.1 \ No newline at end of file diff --git a/go.sum b/go.sum index 2183d5c8..6116b7d2 100644 --- a/go.sum +++ b/go.sum @@ -234,8 +234,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/auth0/go-auth0/v2 v2.6.0 h1:KCoLxTcH8qXPYbwKZxxFrL/6P+P+Zc58BQPL6w0Kt30= github.com/auth0/go-auth0/v2 v2.6.0/go.mod h1:XVRck9fw1EIw1z4guYcbKFGmElnexb+xOvQ/0U1hHd0= -github.com/auth0/go-jwt-middleware/v2 v2.3.1 h1:lbDyWE9aLydb3zrank+Gufb9qGJN9u//7EbJK07pRrw= -github.com/auth0/go-jwt-middleware/v2 v2.3.1/go.mod h1:mqVr0gdB5zuaFyQFWMJH/c/2hehNjbYUD4i8Dpyf+Hc= +github.com/auth0/go-jwt-middleware/v3 v3.0.0 h1:+rvUPCT+VbAuK4tpS13fWfZrMyqTwLopt3VoY0Y7kvA= +github.com/auth0/go-jwt-middleware/v3 v3.0.0/go.mod h1:iU42jqjRyeKbf9YYSnRnolr836gk6Ty/jnUNuVq2b0o= github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA= github.com/aws/aws-sdk-go-v2 v1.41.3/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 h1:N4lRUXZpZ1KVEUn6hxtco/1d2lgYhNn1fHkkl8WhlyQ= @@ -770,18 +770,28 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs= -github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= +github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= +github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= +github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY= +github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k= github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= +github.com/lestrrat-go/httprc/v3 v3.0.3 h1:WjLHWkDkgWXeIUrKi/7lS/sGq2DjkSAwdTbH5RHXAKs= +github.com/lestrrat-go/httprc/v3 v3.0.3/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= github.com/lestrrat-go/jwx/v2 v2.1.6 h1:hxM1gfDILk/l5ylers6BX/Eq1m/pnxe9NBwW6lVfecA= github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU= +github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg= +github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= +github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= @@ -1026,8 +1036,8 @@ github.com/samber/slog-logrus/v2 v2.5.3 h1:N6YGgQ9CQjUQXe75/iWKtE55EENjG67HYUsJQ github.com/samber/slog-logrus/v2 v2.5.3/go.mod h1:W3njRsspuMRCd33S0ibPyK1ohRaMhuXKZ1BK8pNiM+c= github.com/sashabaranov/go-openai v1.41.2 h1:vfPRBZNMpnqu8ELsclWcAvF19lDNgh1t6TVfFFOPiSM= github.com/sashabaranov/go-openai v1.41.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= -github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= -github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= +github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -1146,6 +1156,8 @@ github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2 h1:H8wwQwTe5sL6x30z7 github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2/go.mod h1:/kR4beFhlz2g+V5ik8jW+3PMiMQAPt29y6K64NNY53c= github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 h1:3/aHKUq7qaFMWxyQV0W2ryNgg8x8rVeKVA20KJUkfS0= github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2/go.mod h1:Zit4b8AQXaXvA68+nzmbyDzqiyFRISyw1JiD5JqUBjw= +github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= +github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -1544,8 +1556,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= -gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= diff --git a/go/auth/middleware.go b/go/auth/middleware.go index 0241af4a..081f283e 100644 --- a/go/auth/middleware.go +++ b/go/auth/middleware.go @@ -11,9 +11,9 @@ import ( "strings" "time" - jwtmiddleware "github.com/auth0/go-jwt-middleware/v2" - "github.com/auth0/go-jwt-middleware/v2/jwks" - "github.com/auth0/go-jwt-middleware/v2/validator" + jwtmiddleware "github.com/auth0/go-jwt-middleware/v3" + "github.com/auth0/go-jwt-middleware/v3/jwks" + "github.com/auth0/go-jwt-middleware/v3/validator" "github.com/getsentry/sentry-go" log "github.com/sirupsen/logrus" "go.opentelemetry.io/otel/attribute" @@ -42,6 +42,11 @@ type UserTokenContextKey struct{} // This will be the auth0 `user_id` from the tokens `sub` claim. type CurrentSubjectContextKey struct{} +// ValidatedClaimsContextKey stores the full *validator.ValidatedClaims in +// context. In v3 the middleware's context key is unexported, so we use our own +// for code that needs the full validated claims (e.g. token expiry lookup). +type ValidatedClaimsContextKey struct{} + // MiddlewareConfig Configuration for the auth middleware type MiddlewareConfig struct { Auth0Domain string @@ -214,7 +219,7 @@ func WithAccount(account string) OverrideAuthOptionFunc { } // Sets the auth info in the context directly from the validated claims produced -// by the `github.com/auth0/go-jwt-middleware/v2/validator` package. This is +// by the `github.com/auth0/go-jwt-middleware/v3/validator` package. This is // essentially what the middleware already does when receiving a request, and // therefore should only be used in exceptional circumstances, like testing, when the // middleware is not being used. @@ -224,7 +229,7 @@ func WithAccount(account string) OverrideAuthOptionFunc { func WithValidatedClaims(claims *validator.ValidatedClaims) OverrideAuthOptionFunc { return func(ctx context.Context) context.Context { customClaims := claims.CustomClaims.(*CustomClaims) - ctx = context.WithValue(ctx, jwtmiddleware.ContextKey{}, claims) + ctx = context.WithValue(ctx, ValidatedClaimsContextKey{}, claims) ctx = context.WithValue(ctx, CustomClaimsContextKey{}, customClaims) ctx = context.WithValue(ctx, CurrentSubjectContextKey{}, claims.RegisteredClaims.Subject) ctx = context.WithValue(ctx, AccountNameContextKey{}, customClaims.AccountName) @@ -282,9 +287,23 @@ func withCustomClaims(modify func(*CustomClaims)) OverrideAuthOptionFunc { // // This middleware also extract custom claims form the token and stores them in // CustomClaimsContextKey +// +// NOTE: This function uses log.Fatalf for startup-time configuration errors +// because its signature returns http.Handler, not (http.Handler, error). +// Propagating errors would require changing every caller of NewAuthMiddleware. func ensureValidTokenHandler(config MiddlewareConfig, next http.Handler) http.Handler { - if config.Auth0Domain == "" && config.IssuerURL == "" && config.Auth0Audience == "" { - log.Fatalf("Auth0 configuration is missing") + if config.BypassAuth { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + span := trace.SpanFromContext(r.Context()) + span.SetAttributes(attribute.Bool("ovm.auth.bypass", true)) + ctx := OverrideAuth(r.Context(), WithBypassScopeCheck()) + next.ServeHTTP(w, r.Clone(ctx)) + }) + } + + if config.Auth0Audience == "" || (config.Auth0Domain == "" && config.IssuerURL == "") { + log.Fatalf("Auth0 configuration is incomplete: audience=%q, domain=%q, issuerURL=%q", + config.Auth0Audience, config.Auth0Domain, config.IssuerURL) } var issuerURL *url.URL @@ -299,22 +318,26 @@ func ensureValidTokenHandler(config MiddlewareConfig, next http.Handler) http.Ha log.Fatalf("Failed to parse the issuer url: %v", err) } - provider := jwks.NewCachingProvider(issuerURL, 5*time.Minute) + provider, err := jwks.NewCachingProvider( + jwks.WithIssuerURL(issuerURL), + jwks.WithCacheTTL(5*time.Minute), + ) + if err != nil { + log.Fatalf("Failed to set up the jwks provider: %v", err) + } jwtValidator, err := validator.New( - provider.KeyFunc, - validator.RS256, - issuerURL.String(), - []string{config.Auth0Audience}, - validator.WithCustomClaims( - func() validator.CustomClaims { - return &CustomClaims{} - }, - ), + validator.WithKeyFunc(provider.KeyFunc), + validator.WithAlgorithm(validator.RS256), + validator.WithIssuer(issuerURL.String()), + validator.WithAudience(config.Auth0Audience), + validator.WithCustomClaims(func() *CustomClaims { + return &CustomClaims{} + }), validator.WithAllowedClockSkew(time.Minute), ) if err != nil { - log.Fatalf("Failed to set up the jwt validator") + log.Fatalf("Failed to set up the jwt validator: %v", err) } errorHandler := func(w http.ResponseWriter, r *http.Request, err error) { @@ -382,17 +405,24 @@ func ensureValidTokenHandler(config MiddlewareConfig, next http.Handler) http.Ha tokenExtractor := jwtmiddleware.MultiTokenExtractor(extractors...) - middleware := jwtmiddleware.New( - jwtValidator.ValidateToken, + middleware, err := jwtmiddleware.New( + jwtmiddleware.WithValidator(jwtValidator), jwtmiddleware.WithErrorHandler(errorHandler), jwtmiddleware.WithTokenExtractor(tokenExtractor), ) + if err != nil { + log.Fatalf("Failed to set up the jwt middleware: %v", err) + } jwtValidationMiddleware := middleware.CheckJWT(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // extract account name and setup otel attributes after the JWT was validated, but before the actual handler runs - claims := r.Context().Value(jwtmiddleware.ContextKey{}).(*validator.ValidatedClaims) + claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context()) + if err != nil { + errorHandler(w, r, fmt.Errorf("error getting validated claims: %w", err)) + return + } - token, err := tokenExtractor(r) + extractedToken, err := tokenExtractor(r) // we should never hit this as the middleware wouldn't call the handler if err != nil { // This is not ErrJWTMissing because an error here means that the @@ -412,7 +442,8 @@ func ensureValidTokenHandler(config MiddlewareConfig, next http.Handler) http.Ha // note that the values are looked up in last-in-first-out order, so // there is an absolutely minor perf optimisation to have the context // values set in ascending order of access frequency. - ctx = context.WithValue(ctx, UserTokenContextKey{}, token) + ctx = context.WithValue(ctx, UserTokenContextKey{}, extractedToken.Token) + ctx = context.WithValue(ctx, ValidatedClaimsContextKey{}, claims) ctx = context.WithValue(ctx, CustomClaimsContextKey{}, customClaims) ctx = context.WithValue(ctx, CurrentSubjectContextKey{}, claims.RegisteredClaims.Subject) ctx = context.WithValue(ctx, AccountNameContextKey{}, customClaims.AccountName) @@ -445,14 +476,8 @@ func ensureValidTokenHandler(config MiddlewareConfig, next http.Handler) http.Ha var shouldBypass bool - // If config.BypassAuth is true then bypass - if config.BypassAuth { - shouldBypass = true - } - - // If we aren't bypassing always and we have a regex then check if we - // should bypass - if !shouldBypass && config.BypassAuthForPaths != nil { + // Check if the request path matches the bypass regex + if config.BypassAuthForPaths != nil { shouldBypass = config.BypassAuthForPaths.MatchString(r.URL.Path) if shouldBypass { span.SetAttributes(attribute.String("ovm.auth.bypassedPath", r.URL.Path)) diff --git a/go/auth/middleware_test.go b/go/auth/middleware_test.go index b0231711..412da45b 100644 --- a/go/auth/middleware_test.go +++ b/go/auth/middleware_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/auth0/go-jwt-middleware/v2/validator" + "github.com/auth0/go-jwt-middleware/v3/validator" "github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4/jwt" log "github.com/sirupsen/logrus" From db313ad742a8e1ac536c929748399afdf3ee3730 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Mon, 9 Mar 2026 18:22:43 +0100 Subject: [PATCH 04/18] maint, add a BUGBOT rule to keep go.mod clean (#4198) > [!NOTE] > **Medium Risk** > Primarily dependency hygiene, but it changes `go.mod` direct/indirect requirements (and adds a few direct deps), which can affect module resolution and builds. > > **Overview** > Adds a new Bugbot rule requiring `go.mod` to contain exactly two `require` blocks, with **all direct deps** in the first and **all `// indirect` deps** in the second. > > Updates `go.mod` accordingly by moving several modules between direct/indirect blocks and adding a few direct requirements (notably `cloud.google.com/go/auth/oauth2adapt`, `github.com/lithammer/fuzzysearch`, and `sigs.k8s.io/structured-merge-diff/v6`). > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f14e91b436c6b898c84f4570d0057733c5d8a304. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 3b467a861bd85514ce230e67ab433ffb49d4d600 --- go.mod | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 1be6565a..c4dcc72a 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( charm.land/lipgloss/v2 v2.0.0 cloud.google.com/go/aiplatform v1.119.0 cloud.google.com/go/auth v0.18.2 + cloud.google.com/go/auth/oauth2adapt v0.2.8 cloud.google.com/go/bigquery v1.74.0 cloud.google.com/go/bigtable v1.42.0 cloud.google.com/go/certificatemanager v1.9.6 @@ -55,7 +56,6 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresql/armpostgresqlflexibleservers/v5 v5.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources/v2 v2.1.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources/v3 v3.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql/v2 v2.0.0-beta.7 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v3 v3.0.0 github.com/Masterminds/semver/v3 v3.4.0 @@ -125,6 +125,7 @@ require ( github.com/jedib0t/go-pretty/v6 v6.7.8 github.com/jxskiss/base62 v1.1.0 github.com/kaptinlin/jsonrepair v0.2.17 + github.com/lithammer/fuzzysearch v1.1.8 github.com/manifoldco/promptui v0.9.0 github.com/mavolin/go-htmx v1.0.0 github.com/mergestat/timediff v0.0.4 @@ -190,7 +191,6 @@ require ( golang.org/x/text v0.34.0 gonum.org/v1/gonum v0.17.0 google.golang.org/api v0.269.0 - google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 google.golang.org/grpc v1.79.2 google.golang.org/protobuf v1.36.11 @@ -204,6 +204,7 @@ require ( riverqueue.com/riverui v0.15.0 sigs.k8s.io/controller-runtime v0.23.3 sigs.k8s.io/kind v0.31.0 + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 ) require ( @@ -213,10 +214,10 @@ require ( atomicgo.dev/schedule v0.1.0 // indirect cel.dev/expr v0.25.1 // indirect cloud.google.com/go v0.123.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.8 cloud.google.com/go/longrunning v0.8.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources/v3 v3.0.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect @@ -380,7 +381,6 @@ require ( github.com/lestrrat-go/option v1.0.1 // indirect github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/lithammer/fuzzysearch v1.1.8 github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect @@ -515,6 +515,7 @@ require ( golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect @@ -530,6 +531,5 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 sigs.k8s.io/yaml v1.6.0 // indirect ) From 0aedf74dd9c3f062c2df852aee1fcb5e490feb1f Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 10 Mar 2026 11:59:00 +0100 Subject: [PATCH 05/18] GitHub library upgrades (#4200) image Upgrade `github.com/google/go-github` from v80 to v84 and `go-querystring` to resolve `ENG-3024`. The upgrade involved updating import paths and `go.mod`/`go.sum`. Although the upstream library had breaking changes between v80 and v84, our specific usage of the GitHub client library was not affected, and all existing tests pass. --- Linear Issue: [ENG-3024](https://linear.app/overmind/issue/ENG-3024/upgrade-github-libraries)

Open in Web Open in Cursor 

GitOrigin-RevId: e4fb546b7842a3fbf86f17a6fbf8a653f1a867b7 --- go.mod | 4 ++-- go.sum | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index c4dcc72a..09728f00 100644 --- a/go.mod +++ b/go.mod @@ -108,7 +108,7 @@ require ( github.com/go-jose/go-jose/v4 v4.1.3 github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/google/btree v1.1.3 - github.com/google/go-github/v80 v80.0.0 + github.com/google/go-github/v84 v84.0.0 github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.17.0 github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e @@ -325,7 +325,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-github/v30 v30.1.0 // indirect github.com/google/go-github/v75 v75.0.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect + github.com/google/go-querystring v1.2.0 // indirect github.com/google/go-tpm v0.9.8 // indirect github.com/google/jsonschema-go v0.4.2 // indirect github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect diff --git a/go.sum b/go.sum index 6116b7d2..83f5476e 100644 --- a/go.sum +++ b/go.sum @@ -583,6 +583,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= @@ -591,11 +592,12 @@ github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= github.com/google/go-github/v75 v75.0.0 h1:k7q8Bvg+W5KxRl9Tjq16a9XEgVY1pwuiG5sIL7435Ic= github.com/google/go-github/v75 v75.0.0/go.mod h1:H3LUJEA1TCrzuUqtdAQniBNwuKiQIqdGKgBo1/M/uqI= -github.com/google/go-github/v80 v80.0.0 h1:BTyk3QOHekrk5VF+jIGz1TNEsmeoQG9K/UWaaP+EWQs= -github.com/google/go-github/v80 v80.0.0/go.mod h1:pRo4AIMdHW83HNMGfNysgSAv0vmu+/pkY8nZO9FT9Yo= +github.com/google/go-github/v84 v84.0.0 h1:I/0Xn5IuChMe8TdmI2bbim5nyhaRFJ7DEdzmD2w+yVA= +github.com/google/go-github/v84 v84.0.0/go.mod h1:WwYL1z1ajRdlaPszjVu/47x1L0PXukJBn73xsiYrRRQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +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/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= From de0987414fe5c39c94d780de8d52545c91df7c97 Mon Sep 17 00:00:00 2001 From: Lionel Wilson <80872669+Lionel-Wilson@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:53:21 +0000 Subject: [PATCH 06/18] feat: create Elastic SAN volume snapshot adapter (#4209) image --- > [!NOTE] > **Medium Risk** > Introduces a new Azure resource adapter and changes GET query parsing for Azure to accept full resource IDs, which could affect query behavior for Azure adapters if path-key mappings are missing or incorrect. > > **Overview** > Adds a new Azure adapter for Elastic SAN volume snapshots, including an Azure SDK client wrapper, lookups/linking to parent Elastic SAN/volume group (and source volume when available), Terraform mappings, and unit tests/mocks. > > Extends the core `standardAdapterCore.Get` path parsing to accept full Azure resource IDs (e.g. from Terraform mappings) by extracting query parts based on per-type path key definitions, returning explicit query errors when unsupported. > > Also updates dependencies (`armelasticsan`), registers the new adapter in `azure/manual/adapters.go`, adds ElasticSAN item types/resources + resourceID path-key mapping, tightens k8s `Endpoints` staticcheck suppressions, and makes multiple tests safer by returning after `t.Fatal`/`t.Fatalf` to avoid nil dereferences. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c7e10ad43d6ec2031feae80015364980a25527af. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 97899d2e8b23eae053e5a6612affd3df5d872e73 --- aws-source/adapters/ecs-task_test.go | 1 + cmd/auth_client_test.go | 1 + cmd/explore_test.go | 5 + go.mod | 1 + go.sum | 2 + go/discovery/adapter_test.go | 1 + k8s-source/adapters/endpoints.go | 11 +- .../elastic-san-volume-snapshot-client.go | 35 +++ sources/azure/manual/adapters.go | 11 + .../manual/elastic-san-volume-snapshot.go | 271 ++++++++++++++++++ .../elastic-san-volume-snapshot_test.go | 223 ++++++++++++++ sources/azure/shared/item-types.go | 3 + ...mock_elastic_san_volume_snapshot_client.go | 72 +++++ sources/azure/shared/models.go | 5 +- sources/azure/shared/utils.go | 1 + sources/gcp/proc/proc_test.go | 1 + sources/snapshot/adapters/adapter_test.go | 1 + sources/snapshot/adapters/index_test.go | 1 + sources/transformer.go | 20 +- 19 files changed, 658 insertions(+), 8 deletions(-) create mode 100644 sources/azure/clients/elastic-san-volume-snapshot-client.go create mode 100644 sources/azure/manual/elastic-san-volume-snapshot.go create mode 100644 sources/azure/manual/elastic-san-volume-snapshot_test.go create mode 100644 sources/azure/shared/mocks/mock_elastic_san_volume_snapshot_client.go diff --git a/aws-source/adapters/ecs-task_test.go b/aws-source/adapters/ecs-task_test.go index 9179758e..d149d316 100644 --- a/aws-source/adapters/ecs-task_test.go +++ b/aws-source/adapters/ecs-task_test.go @@ -124,6 +124,7 @@ func TestTaskGetInputMapper(t *testing.T) { if input == nil { t.Fatal("input is nil") + return } if *input.Cluster != "test-ECSCluster-Bt4SqcM3CURk" { diff --git a/cmd/auth_client_test.go b/cmd/auth_client_test.go index ec4516fc..eaf03177 100644 --- a/cmd/auth_client_test.go +++ b/cmd/auth_client_test.go @@ -208,6 +208,7 @@ func TestNewRetryableHTTPClientRespectsProxy(t *testing.T) { if httpTransport == nil { t.Fatal("Could not get http.Transport") + return } // Verify proxy function is set to ProxyFromEnvironment diff --git a/cmd/explore_test.go b/cmd/explore_test.go index a57ec4ae..561a5631 100644 --- a/cmd/explore_test.go +++ b/cmd/explore_test.go @@ -60,6 +60,7 @@ func TestUnifiedGCPConfigs(t *testing.T) { if foundConfig == nil { t.Fatalf("Could not find config for project %s in result", originalConfig.ProjectID) + return } if !reflect.DeepEqual(foundConfig.Regions, originalConfig.Regions) { @@ -115,9 +116,11 @@ func TestUnifiedGCPConfigs(t *testing.T) { if unifiedConfig == nil { t.Fatal("Could not find unified-project config in result") + return } if differentConfig == nil { t.Fatal("Could not find different-project config in result") + return } // Verify unified config has all regions @@ -315,9 +318,11 @@ func TestUnifiedAzureConfigs(t *testing.T) { if unifiedConfig == nil { t.Fatal("Could not find config for subscription 00000000-0000-0000-0000-000000000001 in result") + return } if differentConfig == nil { t.Fatal("Could not find config for subscription 00000000-0000-0000-0000-000000000002 in result") + return } // Verify the first config was kept (tenant-first, client-first) diff --git a/go.mod b/go.mod index 09728f00..ed4ab614 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v7 v7.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v3 v3.4.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/v2 v2.0.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v9 v9.0.0 diff --git a/go.sum b/go.sum index 83f5476e..073d217e 100644 --- a/go.sum +++ b/go.sum @@ -124,6 +124,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v3 v3.4.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v3 v3.4.0/go.mod h1:Bb7kqorvA2acMCNFac+2ldoQWi7QrcMdH+9Gg9C7fSM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan v1.2.0 h1:8xYBtaMs3Msy1bFYTVrVFBh05JUGNMMP/v3z3x5hoIw= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan v1.2.0/go.mod h1:bXxc3uCnIUCh68pl4njcH45qUgRuR0kZfR6v06k18/A= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.1 h1:1kpY4qe+BGAH2ykv4baVSqyx+AY5VjXeJ15SldlU6hs= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.1/go.mod h1:nT6cWpWdUt+g81yuKmjeYPUtI73Ak3yQIT4PVVsCEEQ= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/v2 v2.0.1 h1:nFZ7AvJqTpWobmnZlprsK6GucrByFsXWB+DwkhRxM9I= diff --git a/go/discovery/adapter_test.go b/go/discovery/adapter_test.go index fcf0ec91..98f5ebf0 100644 --- a/go/discovery/adapter_test.go +++ b/go/discovery/adapter_test.go @@ -708,6 +708,7 @@ func TestNewQueryResultStream(t *testing.T) { // Test Initialization if stream == nil { t.Fatal("Expected stream to be initialized, got nil") + return } if stream.itemHandler == nil || stream.errHandler == nil { t.Fatal("Expected handlers to be set") diff --git a/k8s-source/adapters/endpoints.go b/k8s-source/adapters/endpoints.go index 9fa04764..14045e0e 100644 --- a/k8s-source/adapters/endpoints.go +++ b/k8s-source/adapters/endpoints.go @@ -7,7 +7,6 @@ // and acceptable. When the SDK eventually drops support for v1.Endpoints we // will need to split out version-specific builds of the k8s-source. -//nolint:staticcheck // See note at top of file package adapters import ( @@ -18,7 +17,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func EndpointsExtractor(resource *v1.Endpoints, scope string) ([]*sdp.LinkedItemQuery, error) { +func EndpointsExtractor(resource *v1.Endpoints, scope string) ([]*sdp.LinkedItemQuery, error) { //nolint:staticcheck,nolintlint // SA1019: v1.Endpoints deprecated; see note at top of file queries := make([]*sdp.LinkedItemQuery, 0) sd, err := ParseScope(scope, true) @@ -72,15 +71,15 @@ func EndpointsExtractor(resource *v1.Endpoints, scope string) ([]*sdp.LinkedItem } func newEndpointsAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string, cache sdpcache.Cache) discovery.ListableAdapter { - return &KubeTypeAdapter[*v1.Endpoints, *v1.EndpointsList]{ + return &KubeTypeAdapter[*v1.Endpoints, *v1.EndpointsList]{ //nolint:staticcheck,nolintlint // SA1019: v1.Endpoints deprecated; see note at top of file ClusterName: cluster, Namespaces: namespaces, TypeName: "Endpoints", - NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.Endpoints, *v1.EndpointsList] { + NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.Endpoints, *v1.EndpointsList] { //nolint:staticcheck,nolintlint // SA1019 return cs.CoreV1().Endpoints(namespace) }, - ListExtractor: func(list *v1.EndpointsList) ([]*v1.Endpoints, error) { - extracted := make([]*v1.Endpoints, len(list.Items)) + ListExtractor: func(list *v1.EndpointsList) ([]*v1.Endpoints, error) { //nolint:staticcheck,nolintlint // SA1019 + extracted := make([]*v1.Endpoints, len(list.Items)) //nolint:staticcheck,nolintlint // SA1019 for i := range list.Items { extracted[i] = &list.Items[i] diff --git a/sources/azure/clients/elastic-san-volume-snapshot-client.go b/sources/azure/clients/elastic-san-volume-snapshot-client.go new file mode 100644 index 00000000..b1306edf --- /dev/null +++ b/sources/azure/clients/elastic-san-volume-snapshot-client.go @@ -0,0 +1,35 @@ +package clients + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" +) + +//go:generate mockgen -destination=../shared/mocks/mock_elastic_san_volume_snapshot_client.go -package=mocks -source=elastic-san-volume-snapshot-client.go + +// ElasticSanVolumeSnapshotPager is a type alias for the generic Pager interface with volume snapshot list response type. +type ElasticSanVolumeSnapshotPager = Pager[armelasticsan.VolumeSnapshotsClientListByVolumeGroupResponse] + +// ElasticSanVolumeSnapshotClient is an interface for interacting with Azure Elastic SAN volume snapshots. +type ElasticSanVolumeSnapshotClient interface { + Get(ctx context.Context, resourceGroupName string, elasticSanName string, volumeGroupName string, snapshotName string, options *armelasticsan.VolumeSnapshotsClientGetOptions) (armelasticsan.VolumeSnapshotsClientGetResponse, error) + ListByVolumeGroup(ctx context.Context, resourceGroupName string, elasticSanName string, volumeGroupName string, options *armelasticsan.VolumeSnapshotsClientListByVolumeGroupOptions) ElasticSanVolumeSnapshotPager +} + +type elasticSanVolumeSnapshotClient struct { + client *armelasticsan.VolumeSnapshotsClient +} + +func (c *elasticSanVolumeSnapshotClient) Get(ctx context.Context, resourceGroupName string, elasticSanName string, volumeGroupName string, snapshotName string, options *armelasticsan.VolumeSnapshotsClientGetOptions) (armelasticsan.VolumeSnapshotsClientGetResponse, error) { + return c.client.Get(ctx, resourceGroupName, elasticSanName, volumeGroupName, snapshotName, options) +} + +func (c *elasticSanVolumeSnapshotClient) ListByVolumeGroup(ctx context.Context, resourceGroupName string, elasticSanName string, volumeGroupName string, options *armelasticsan.VolumeSnapshotsClientListByVolumeGroupOptions) ElasticSanVolumeSnapshotPager { + return c.client.NewListByVolumeGroupPager(resourceGroupName, elasticSanName, volumeGroupName, options) +} + +// NewElasticSanVolumeSnapshotClient creates a new ElasticSanVolumeSnapshotClient from the Azure SDK client. +func NewElasticSanVolumeSnapshotClient(client *armelasticsan.VolumeSnapshotsClient) ElasticSanVolumeSnapshotClient { + return &elasticSanVolumeSnapshotClient{client: client} +} diff --git a/sources/azure/manual/adapters.go b/sources/azure/manual/adapters.go index aaeba7cb..de518f3b 100644 --- a/sources/azure/manual/adapters.go +++ b/sources/azure/manual/adapters.go @@ -15,6 +15,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v9" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresql/armpostgresqlflexibleservers/v5" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources/v2" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql/v2" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v3" @@ -412,6 +413,11 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred return nil, fmt.Errorf("failed to create snapshots client: %w", err) } + elasticSanVolumeSnapshotsClient, err := armelasticsan.NewVolumeSnapshotsClient(subscriptionID, cred, nil) + if err != nil { + return nil, fmt.Errorf("failed to create elastic san volume snapshots client: %w", err) + } + sharedGalleryImagesClient, err := armcompute.NewSharedGalleryImagesClient(subscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create shared gallery images client: %w", err) @@ -692,6 +698,10 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred clients.NewSnapshotsClient(snapshotsClient), resourceGroupScopes, ), cache), + sources.WrapperToAdapter(NewElasticSanVolumeSnapshot( + clients.NewElasticSanVolumeSnapshotClient(elasticSanVolumeSnapshotsClient), + resourceGroupScopes, + ), cache), ) } @@ -780,6 +790,7 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred sources.WrapperToAdapter(NewComputeGallery(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeGalleryImage(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeSnapshot(nil, placeholderResourceGroupScopes), noOpCache), + sources.WrapperToAdapter(NewElasticSanVolumeSnapshot(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeSharedGalleryImage(nil, subscriptionID), noOpCache), sources.WrapperToAdapter(NewNetworkPrivateEndpoint(nil, placeholderResourceGroupScopes), noOpCache), ) diff --git a/sources/azure/manual/elastic-san-volume-snapshot.go b/sources/azure/manual/elastic-san-volume-snapshot.go new file mode 100644 index 00000000..0c0bdbad --- /dev/null +++ b/sources/azure/manual/elastic-san-volume-snapshot.go @@ -0,0 +1,271 @@ +package manual + +import ( + "context" + "errors" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/shared" +) + +var ( + ElasticSanLookupByName = shared.NewItemTypeLookup("name", azureshared.ElasticSan) + ElasticSanVolumeGroupLookupByName = shared.NewItemTypeLookup("name", azureshared.ElasticSanVolumeGroup) + ElasticSanVolumeSnapshotLookupByName = shared.NewItemTypeLookup("name", azureshared.ElasticSanVolumeSnapshot) +) + +type elasticSanVolumeSnapshotWrapper struct { + client clients.ElasticSanVolumeSnapshotClient + *azureshared.MultiResourceGroupBase +} + +func NewElasticSanVolumeSnapshot(client clients.ElasticSanVolumeSnapshotClient, resourceGroupScopes []azureshared.ResourceGroupScope) sources.SearchableWrapper { + return &elasticSanVolumeSnapshotWrapper{ + client: client, + MultiResourceGroupBase: azureshared.NewMultiResourceGroupBase( + resourceGroupScopes, + sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + azureshared.ElasticSanVolumeSnapshot, + ), + } +} + +func (s elasticSanVolumeSnapshotWrapper) Get(ctx context.Context, scope string, queryParts ...string) (*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 3 { + return nil, azureshared.QueryError(errors.New("Get requires 3 query parts: elasticSanName, volumeGroupName and snapshotName"), scope, s.Type()) + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + return nil, azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, s.Type()) + } + volumeGroupName := queryParts[1] + if volumeGroupName == "" { + return nil, azureshared.QueryError(errors.New("volumeGroupName cannot be empty"), scope, s.Type()) + } + snapshotName := queryParts[2] + if snapshotName == "" { + return nil, azureshared.QueryError(errors.New("snapshotName cannot be empty"), scope, s.Type()) + } + + rgScope, err := s.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + resp, err := s.client.Get(ctx, rgScope.ResourceGroup, elasticSanName, volumeGroupName, snapshotName, nil) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + + return s.azureSnapshotToSDPItem(&resp.Snapshot, elasticSanName, volumeGroupName, snapshotName, scope) +} + +func (s elasticSanVolumeSnapshotWrapper) GetLookups() sources.ItemTypeLookups { + return sources.ItemTypeLookups{ + ElasticSanLookupByName, + ElasticSanVolumeGroupLookupByName, + ElasticSanVolumeSnapshotLookupByName, + } +} + +func (s elasticSanVolumeSnapshotWrapper) Search(ctx context.Context, scope string, queryParts ...string) ([]*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 2 { + return nil, azureshared.QueryError(errors.New("Search requires 2 query parts: elasticSanName and volumeGroupName"), scope, s.Type()) + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + return nil, azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, s.Type()) + } + volumeGroupName := queryParts[1] + if volumeGroupName == "" { + return nil, azureshared.QueryError(errors.New("volumeGroupName cannot be empty"), scope, s.Type()) + } + + rgScope, err := s.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + pager := s.client.ListByVolumeGroup(ctx, rgScope.ResourceGroup, elasticSanName, volumeGroupName, nil) + + var items []*sdp.Item + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + for _, snapshot := range page.Value { + if snapshot.Name == nil { + continue + } + item, sdpErr := s.azureSnapshotToSDPItem(snapshot, elasticSanName, volumeGroupName, *snapshot.Name, scope) + if sdpErr != nil { + return nil, sdpErr + } + items = append(items, item) + } + } + return items, nil +} + +func (s elasticSanVolumeSnapshotWrapper) SearchStream(ctx context.Context, stream discovery.QueryResultStream, cache sdpcache.Cache, cacheKey sdpcache.CacheKey, scope string, queryParts ...string) { + if len(queryParts) < 2 { + stream.SendError(azureshared.QueryError(errors.New("Search requires 2 query parts: elasticSanName and volumeGroupName"), scope, s.Type())) + return + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + stream.SendError(azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, s.Type())) + return + } + volumeGroupName := queryParts[1] + if volumeGroupName == "" { + stream.SendError(azureshared.QueryError(errors.New("volumeGroupName cannot be empty"), scope, s.Type())) + return + } + + rgScope, err := s.ResourceGroupScopeFromScope(scope) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, s.Type())) + return + } + pager := s.client.ListByVolumeGroup(ctx, rgScope.ResourceGroup, elasticSanName, volumeGroupName, nil) + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, s.Type())) + return + } + for _, snapshot := range page.Value { + if snapshot.Name == nil { + continue + } + item, sdpErr := s.azureSnapshotToSDPItem(snapshot, elasticSanName, volumeGroupName, *snapshot.Name, scope) + if sdpErr != nil { + stream.SendError(sdpErr) + continue + } + cache.StoreItem(ctx, item, shared.DefaultCacheDuration, cacheKey) + stream.SendItem(item) + } + } +} + +func (s elasticSanVolumeSnapshotWrapper) SearchLookups() []sources.ItemTypeLookups { + return []sources.ItemTypeLookups{ + { + ElasticSanLookupByName, + ElasticSanVolumeGroupLookupByName, + }, + } +} + +func (s elasticSanVolumeSnapshotWrapper) azureSnapshotToSDPItem(snapshot *armelasticsan.Snapshot, elasticSanName, volumeGroupName, snapshotName, scope string) (*sdp.Item, *sdp.QueryError) { + if snapshot.Name == nil { + return nil, azureshared.QueryError(errors.New("snapshot name is nil"), scope, s.Type()) + } + attributes, err := shared.ToAttributesWithExclude(snapshot, "tags") + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + err = attributes.Set("uniqueAttr", shared.CompositeLookupKey(elasticSanName, volumeGroupName, snapshotName)) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + + sdpItem := &sdp.Item{ + Type: azureshared.ElasticSanVolumeSnapshot.String(), + UniqueAttribute: "uniqueAttr", + Attributes: attributes, + Scope: scope, + LinkedItemQueries: []*sdp.LinkedItemQuery{}, + } + + // Link to parent Elastic SAN + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSan.String(), + Method: sdp.QueryMethod_GET, + Query: elasticSanName, + Scope: scope, + }, + }) + + // Link to parent Volume Group + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSanVolumeGroup.String(), + Method: sdp.QueryMethod_GET, + Query: shared.CompositeLookupKey(elasticSanName, volumeGroupName), + Scope: scope, + }, + }) + + // Link to source volume from CreationData.SourceID + if snapshot.Properties != nil && snapshot.Properties.CreationData != nil && snapshot.Properties.CreationData.SourceID != nil && *snapshot.Properties.CreationData.SourceID != "" { + sourceID := *snapshot.Properties.CreationData.SourceID + parts := azureshared.ExtractPathParamsFromResourceID(sourceID, []string{"elasticSans", "volumegroups", "volumes"}) + if len(parts) >= 3 { + extractedScope := azureshared.ExtractScopeFromResourceID(sourceID) + if extractedScope == "" { + extractedScope = scope + } + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSanVolume.String(), + Method: sdp.QueryMethod_GET, + Query: shared.CompositeLookupKey(parts[0], parts[1], parts[2]), + Scope: extractedScope, + }, + }) + } + } + + if snapshot.Properties != nil && snapshot.Properties.ProvisioningState != nil { + switch *snapshot.Properties.ProvisioningState { + case armelasticsan.ProvisioningStatesSucceeded: + sdpItem.Health = sdp.Health_HEALTH_OK.Enum() + case armelasticsan.ProvisioningStatesCreating, armelasticsan.ProvisioningStatesUpdating, armelasticsan.ProvisioningStatesDeleting, + armelasticsan.ProvisioningStatesPending, armelasticsan.ProvisioningStatesRestoring: + sdpItem.Health = sdp.Health_HEALTH_PENDING.Enum() + case armelasticsan.ProvisioningStatesFailed, armelasticsan.ProvisioningStatesCanceled, + armelasticsan.ProvisioningStatesDeleted, armelasticsan.ProvisioningStatesInvalid: + sdpItem.Health = sdp.Health_HEALTH_ERROR.Enum() + default: + sdpItem.Health = sdp.Health_HEALTH_UNKNOWN.Enum() + } + } + + return sdpItem, nil +} + +func (s elasticSanVolumeSnapshotWrapper) PotentialLinks() map[shared.ItemType]bool { + return map[shared.ItemType]bool{ + azureshared.ElasticSan: true, + azureshared.ElasticSanVolumeGroup: true, + azureshared.ElasticSanVolume: true, + } +} + +func (s elasticSanVolumeSnapshotWrapper) TerraformMappings() []*sdp.TerraformMapping { + return []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_GET, + TerraformQueryMap: "azurerm_elastic_san_volume_snapshot.id", + }, + } +} + +func (s elasticSanVolumeSnapshotWrapper) IAMPermissions() []string { + return []string{ + "Microsoft.ElasticSan/elasticSans/volumegroups/snapshots/read", + } +} + +func (s elasticSanVolumeSnapshotWrapper) PredefinedRole() string { + return "Reader" +} diff --git a/sources/azure/manual/elastic-san-volume-snapshot_test.go b/sources/azure/manual/elastic-san-volume-snapshot_test.go new file mode 100644 index 00000000..83595296 --- /dev/null +++ b/sources/azure/manual/elastic-san-volume-snapshot_test.go @@ -0,0 +1,223 @@ +package manual_test + +import ( + "context" + "errors" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + "go.uber.org/mock/gomock" + + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/manual" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/azure/shared/mocks" + "github.com/overmindtech/cli/sources/shared" +) + +// mockElasticSanVolumeSnapshotPager is a simple mock implementation of ElasticSanVolumeSnapshotPager +type mockElasticSanVolumeSnapshotPager struct { + pages []armelasticsan.VolumeSnapshotsClientListByVolumeGroupResponse + index int +} + +func (m *mockElasticSanVolumeSnapshotPager) More() bool { + return m.index < len(m.pages) +} + +func (m *mockElasticSanVolumeSnapshotPager) NextPage(ctx context.Context) (armelasticsan.VolumeSnapshotsClientListByVolumeGroupResponse, error) { + if m.index >= len(m.pages) { + return armelasticsan.VolumeSnapshotsClientListByVolumeGroupResponse{}, errors.New("no more pages") + } + page := m.pages[m.index] + m.index++ + return page, nil +} + +func createAzureElasticSanSnapshot(name string) *armelasticsan.Snapshot { + provisioningState := armelasticsan.ProvisioningStatesSucceeded + return &armelasticsan.Snapshot{ + ID: new("/subscriptions/sub/resourceGroups/rg/providers/Microsoft.ElasticSan/elasticSans/es/volumegroups/vg/snapshots/" + name), + Name: new(name), + Type: new("Microsoft.ElasticSan/elasticSans/volumegroups/snapshots"), + Properties: &armelasticsan.SnapshotProperties{ + ProvisioningState: &provisioningState, + CreationData: &armelasticsan.SnapshotCreationData{}, + }, + } +} + +func TestElasticSanVolumeSnapshot(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + subscriptionID := "test-subscription" + resourceGroup := "test-rg" + elasticSanName := "test-elastic-san" + volumeGroupName := "test-volume-group" + snapshotName := "test-snapshot" + + t.Run("Get", func(t *testing.T) { + snapshot := createAzureElasticSanSnapshot(snapshotName) + + mockClient := mocks.NewMockElasticSanVolumeSnapshotClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, elasticSanName, volumeGroupName, snapshotName, nil).Return( + armelasticsan.VolumeSnapshotsClientGetResponse{ + Snapshot: *snapshot, + }, nil) + + wrapper := manual.NewElasticSanVolumeSnapshot(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(elasticSanName, volumeGroupName, snapshotName) + sdpItem, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + if sdpItem.GetType() != azureshared.ElasticSanVolumeSnapshot.String() { + t.Errorf("Expected type %s, got %s", azureshared.ElasticSanVolumeSnapshot.String(), sdpItem.GetType()) + } + + if sdpItem.GetUniqueAttribute() != "uniqueAttr" { + t.Errorf("Expected unique attribute 'uniqueAttr', got %s", sdpItem.GetUniqueAttribute()) + } + + expectedUnique := shared.CompositeLookupKey(elasticSanName, volumeGroupName, snapshotName) + if sdpItem.UniqueAttributeValue() != expectedUnique { + t.Errorf("Expected unique attribute value %s, got %s", expectedUnique, sdpItem.UniqueAttributeValue()) + } + + if sdpItem.GetScope() != subscriptionID+"."+resourceGroup { + t.Errorf("Expected scope %s, got %s", subscriptionID+"."+resourceGroup, sdpItem.GetScope()) + } + + if err := sdpItem.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + + t.Run("StaticTests", func(t *testing.T) { + scope := subscriptionID + "." + resourceGroup + queryTests := shared.QueryTests{ + {ExpectedType: azureshared.ElasticSan.String(), ExpectedMethod: sdp.QueryMethod_GET, ExpectedQuery: elasticSanName, ExpectedScope: scope}, + {ExpectedType: azureshared.ElasticSanVolumeGroup.String(), ExpectedMethod: sdp.QueryMethod_GET, ExpectedQuery: shared.CompositeLookupKey(elasticSanName, volumeGroupName), ExpectedScope: scope}, + } + shared.RunStaticTests(t, adapter, sdpItem, queryTests) + }) + }) + + t.Run("GetWithInsufficientQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanVolumeSnapshotClient(ctrl) + wrapper := manual.NewElasticSanVolumeSnapshot(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], elasticSanName, true) + if qErr == nil { + t.Error("Expected error when providing insufficient query parts, but got nil") + } + }) + + t.Run("GetWithEmptyName", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanVolumeSnapshotClient(ctrl) + wrapper := manual.NewElasticSanVolumeSnapshot(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(elasticSanName, volumeGroupName, "") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when snapshot name is empty, but got nil") + } + }) + + t.Run("ErrorHandling", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanVolumeSnapshotClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, elasticSanName, volumeGroupName, "nonexistent", nil).Return( + armelasticsan.VolumeSnapshotsClientGetResponse{}, errors.New("snapshot not found")) + + wrapper := manual.NewElasticSanVolumeSnapshot(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(elasticSanName, volumeGroupName, "nonexistent") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when resource not found, but got nil") + } + }) + + t.Run("Search", func(t *testing.T) { + snapshot1 := createAzureElasticSanSnapshot("snap-1") + snapshot2 := createAzureElasticSanSnapshot("snap-2") + + mockClient := mocks.NewMockElasticSanVolumeSnapshotClient(ctrl) + mockPager := &mockElasticSanVolumeSnapshotPager{ + pages: []armelasticsan.VolumeSnapshotsClientListByVolumeGroupResponse{ + { + SnapshotList: armelasticsan.SnapshotList{ + Value: []*armelasticsan.Snapshot{snapshot1, snapshot2}, + }, + }, + }, + } + mockClient.EXPECT().ListByVolumeGroup(ctx, resourceGroup, elasticSanName, volumeGroupName, nil).Return(mockPager) + + wrapper := manual.NewElasticSanVolumeSnapshot(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable, ok := adapter.(discovery.SearchableAdapter) + if !ok { + t.Fatalf("Adapter does not support Search operation") + } + + query := shared.CompositeLookupKey(elasticSanName, volumeGroupName) + items, err := searchable.Search(ctx, wrapper.Scopes()[0], query, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + if len(items) != 2 { + t.Fatalf("Expected 2 items, got %d", len(items)) + } + for _, item := range items { + if err := item.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + } + }) + + t.Run("SearchStream", func(t *testing.T) { + snapshot := createAzureElasticSanSnapshot("stream-snap") + mockClient := mocks.NewMockElasticSanVolumeSnapshotClient(ctrl) + mockPager := &mockElasticSanVolumeSnapshotPager{ + pages: []armelasticsan.VolumeSnapshotsClientListByVolumeGroupResponse{ + { + SnapshotList: armelasticsan.SnapshotList{ + Value: []*armelasticsan.Snapshot{snapshot}, + }, + }, + }, + } + mockClient.EXPECT().ListByVolumeGroup(ctx, resourceGroup, elasticSanName, volumeGroupName, nil).Return(mockPager) + + wrapper := manual.NewElasticSanVolumeSnapshot(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + streamable, ok := adapter.(discovery.SearchStreamableAdapter) + if !ok { + t.Fatalf("Adapter does not support SearchStream operation") + } + + query := shared.CompositeLookupKey(elasticSanName, volumeGroupName) + stream := discovery.NewRecordingQueryResultStream() + streamable.SearchStream(ctx, wrapper.Scopes()[0], query, true, stream) + items := stream.GetItems() + if len(items) != 1 { + t.Fatalf("Expected 1 item from stream, got %d", len(items)) + } + if items[0].GetType() != azureshared.ElasticSanVolumeSnapshot.String() { + t.Errorf("Expected type %s, got %s", azureshared.ElasticSanVolumeSnapshot.String(), items[0].GetType()) + } + }) +} diff --git a/sources/azure/shared/item-types.go b/sources/azure/shared/item-types.go index aae8f3f7..6f05bbc0 100644 --- a/sources/azure/shared/item-types.go +++ b/sources/azure/shared/item-types.go @@ -176,6 +176,9 @@ var ( BatchBatchDetector = shared.NewItemType(Azure, Batch, BatchDetector) // ElasticSAN item types + ElasticSan = shared.NewItemType(Azure, ElasticSAN, ElasticSanResource) + ElasticSanVolumeGroup = shared.NewItemType(Azure, ElasticSAN, VolumeGroup) + ElasticSanVolume = shared.NewItemType(Azure, ElasticSAN, Volume) ElasticSanVolumeSnapshot = shared.NewItemType(Azure, ElasticSAN, VolumeSnapshot) // Authorization item types diff --git a/sources/azure/shared/mocks/mock_elastic_san_volume_snapshot_client.go b/sources/azure/shared/mocks/mock_elastic_san_volume_snapshot_client.go new file mode 100644 index 00000000..89dab0b5 --- /dev/null +++ b/sources/azure/shared/mocks/mock_elastic_san_volume_snapshot_client.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: elastic-san-volume-snapshot-client.go +// +// Generated by this command: +// +// mockgen -destination=../shared/mocks/mock_elastic_san_volume_snapshot_client.go -package=mocks -source=elastic-san-volume-snapshot-client.go +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + armelasticsan "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + clients "github.com/overmindtech/cli/sources/azure/clients" + gomock "go.uber.org/mock/gomock" +) + +// MockElasticSanVolumeSnapshotClient is a mock of ElasticSanVolumeSnapshotClient interface. +type MockElasticSanVolumeSnapshotClient struct { + ctrl *gomock.Controller + recorder *MockElasticSanVolumeSnapshotClientMockRecorder + isgomock struct{} +} + +// MockElasticSanVolumeSnapshotClientMockRecorder is the mock recorder for MockElasticSanVolumeSnapshotClient. +type MockElasticSanVolumeSnapshotClientMockRecorder struct { + mock *MockElasticSanVolumeSnapshotClient +} + +// NewMockElasticSanVolumeSnapshotClient creates a new mock instance. +func NewMockElasticSanVolumeSnapshotClient(ctrl *gomock.Controller) *MockElasticSanVolumeSnapshotClient { + mock := &MockElasticSanVolumeSnapshotClient{ctrl: ctrl} + mock.recorder = &MockElasticSanVolumeSnapshotClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockElasticSanVolumeSnapshotClient) EXPECT() *MockElasticSanVolumeSnapshotClientMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockElasticSanVolumeSnapshotClient) Get(ctx context.Context, resourceGroupName, elasticSanName, volumeGroupName, snapshotName string, options *armelasticsan.VolumeSnapshotsClientGetOptions) (armelasticsan.VolumeSnapshotsClientGetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, elasticSanName, volumeGroupName, snapshotName, options) + ret0, _ := ret[0].(armelasticsan.VolumeSnapshotsClientGetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockElasticSanVolumeSnapshotClientMockRecorder) Get(ctx, resourceGroupName, elasticSanName, volumeGroupName, snapshotName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockElasticSanVolumeSnapshotClient)(nil).Get), ctx, resourceGroupName, elasticSanName, volumeGroupName, snapshotName, options) +} + +// ListByVolumeGroup mocks base method. +func (m *MockElasticSanVolumeSnapshotClient) ListByVolumeGroup(ctx context.Context, resourceGroupName, elasticSanName, volumeGroupName string, options *armelasticsan.VolumeSnapshotsClientListByVolumeGroupOptions) clients.ElasticSanVolumeSnapshotPager { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListByVolumeGroup", ctx, resourceGroupName, elasticSanName, volumeGroupName, options) + ret0, _ := ret[0].(clients.ElasticSanVolumeSnapshotPager) + return ret0 +} + +// ListByVolumeGroup indicates an expected call of ListByVolumeGroup. +func (mr *MockElasticSanVolumeSnapshotClientMockRecorder) ListByVolumeGroup(ctx, resourceGroupName, elasticSanName, volumeGroupName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByVolumeGroup", reflect.TypeOf((*MockElasticSanVolumeSnapshotClient)(nil).ListByVolumeGroup), ctx, resourceGroupName, elasticSanName, volumeGroupName, options) +} diff --git a/sources/azure/shared/models.go b/sources/azure/shared/models.go index a2a12cb6..2dab0456 100644 --- a/sources/azure/shared/models.go +++ b/sources/azure/shared/models.go @@ -223,7 +223,10 @@ const ( BatchDetector shared.Resource = "batch-detector" // ElasticSAN resources - VolumeSnapshot shared.Resource = "elastic-san-volume-snapshot" + ElasticSanResource shared.Resource = "elastic-san" + VolumeGroup shared.Resource = "volume-group" + Volume shared.Resource = "volume" + VolumeSnapshot shared.Resource = "elastic-san-volume-snapshot" // Authorization resources RoleAssignment shared.Resource = "role-assignment" diff --git a/sources/azure/shared/utils.go b/sources/azure/shared/utils.go index a06ed1a2..c6cb696c 100644 --- a/sources/azure/shared/utils.go +++ b/sources/azure/shared/utils.go @@ -51,6 +51,7 @@ func GetResourceIDPathKeys(resourceType string) []string { "azure-batch-batch-application": {"batchAccounts", "applications"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/applications/{applicationName}", "azure-batch-batch-pool": {"batchAccounts", "pools"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools/{poolName}", "azure-network-dns-record-set": {"dnszones"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/dnszones/{zoneName}/{recordType}/{relativeRecordSetName}" + "azure-elasticsan-elastic-san-volume-snapshot": {"elasticSans", "volumegroups", "snapshots"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ElasticSan/elasticSans/{elasticSanName}/volumegroups/{volumeGroupName}/snapshots/{snapshotName}" } if keys, ok := pathKeysMap[resourceType]; ok { diff --git a/sources/gcp/proc/proc_test.go b/sources/gcp/proc/proc_test.go index c5476e72..710db195 100644 --- a/sources/gcp/proc/proc_test.go +++ b/sources/gcp/proc/proc_test.go @@ -408,6 +408,7 @@ func TestNewProjectHealthChecker(t *testing.T) { if checker == nil { t.Fatal("expected checker to be non-nil") + return } if len(checker.projectIDs) != len(tt.projectIDs) { diff --git a/sources/snapshot/adapters/adapter_test.go b/sources/snapshot/adapters/adapter_test.go index 7952ca2b..bd55f35b 100644 --- a/sources/snapshot/adapters/adapter_test.go +++ b/sources/snapshot/adapters/adapter_test.go @@ -272,6 +272,7 @@ func TestNewSnapshotAdapter(t *testing.T) { adapter := NewSnapshotAdapter(index, "ec2-instance", []string{"us-east-1", "us-west-2"}) if adapter == nil { t.Fatal("Expected adapter, got nil") + return } if adapter.index != index { t.Error("Expected adapter to store index reference") diff --git a/sources/snapshot/adapters/index_test.go b/sources/snapshot/adapters/index_test.go index a5774e65..da01d495 100644 --- a/sources/snapshot/adapters/index_test.go +++ b/sources/snapshot/adapters/index_test.go @@ -70,6 +70,7 @@ func TestNewSnapshotIndex(t *testing.T) { if index == nil { t.Fatal("Expected index to be non-nil") + return } // Verify all items are indexed diff --git a/sources/transformer.go b/sources/transformer.go index 6cca672a..2a978d17 100644 --- a/sources/transformer.go +++ b/sources/transformer.go @@ -302,7 +302,25 @@ func (s *standardAdapterCore) Get(ctx context.Context, scope string, query strin return cachedItem[0], nil } - queryParts := strings.Split(query, shared.QuerySeparator) + var queryParts []string + if s.sourceType == string(azureshared.Azure) && strings.HasPrefix(query, "/subscriptions/") { + // Terraform mapping may pass full Azure resource ID; extract query parts by type. + if azureshared.GetResourceIDPathKeys(s.wrapper.Type()) == nil { + return nil, &sdp.QueryError{ + ErrorType: sdp.QueryError_OTHER, + ErrorString: fmt.Sprintf("no path keys defined for resource type %s to extract from query %s", s.wrapper.Type(), query), + } + } + queryParts = azureshared.ExtractPathParamsFromResourceIDByType(s.wrapper.Type(), query) + if queryParts == nil { + return nil, &sdp.QueryError{ + ErrorType: sdp.QueryError_OTHER, + ErrorString: fmt.Sprintf("failed to extract query parts from resource ID for resource type %s (invalid or unsupported format): %s", s.wrapper.Type(), query), + } + } + } else { + queryParts = strings.Split(query, shared.QuerySeparator) + } if len(queryParts) != len(s.wrapper.GetLookups()) { return nil, fmt.Errorf( "invalid query format: %s, expected: %s", From 3303f9f12bebdaddf5b69f917ed292674c4df792 Mon Sep 17 00:00:00 2001 From: Lionel Wilson <80872669+Lionel-Wilson@users.noreply.github.com> Date: Tue, 10 Mar 2026 18:10:37 +0000 Subject: [PATCH 07/18] feat: implement NetworkDefaultSecurityRule adapter (#4216) image > [!NOTE] > **Medium Risk** > Adds a new Azure discovery adapter and client wiring that will increase API calls and linked-query generation for NSG scans. Risk is moderate because it touches adapter initialization/registration and paging logic, but is isolated to a new resource type. > > **Overview** > Adds support for discovering Azure NSG *default* security rules by introducing a new `NetworkDefaultSecurityRule` searchable adapter, including `Get`, `Search`, and streaming search, and wiring it into the Azure manual adapter registry. > > Introduces a thin `DefaultSecurityRulesClient` wrapper (with generated GoMock) and updates resource-ID path extraction to understand `azure-network-default-security-rule`; includes a dedicated unit test suite covering paging, validation, and error cases. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 83470e2e2e56c5effbd6bbf5b777f1b1fc789bb9. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 3fb0c7bdbef4b58a368deeffa2e726c9a2aaa793 --- .../clients/default-security-rules-client.go | 35 ++ sources/azure/manual/adapters.go | 10 + .../manual/network-default-security-rule.go | 262 +++++++++++++++ .../network-default-security-rule_test.go | 300 ++++++++++++++++++ .../mock_default_security_rules_client.go | 72 +++++ sources/azure/shared/utils.go | 1 + 6 files changed, 680 insertions(+) create mode 100644 sources/azure/clients/default-security-rules-client.go create mode 100644 sources/azure/manual/network-default-security-rule.go create mode 100644 sources/azure/manual/network-default-security-rule_test.go create mode 100644 sources/azure/shared/mocks/mock_default_security_rules_client.go diff --git a/sources/azure/clients/default-security-rules-client.go b/sources/azure/clients/default-security-rules-client.go new file mode 100644 index 00000000..612876fb --- /dev/null +++ b/sources/azure/clients/default-security-rules-client.go @@ -0,0 +1,35 @@ +package clients + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v9" +) + +//go:generate mockgen -destination=../shared/mocks/mock_default_security_rules_client.go -package=mocks -source=default-security-rules-client.go + +// DefaultSecurityRulesPager is a type alias for the generic Pager interface with default security rules list response type. +type DefaultSecurityRulesPager = Pager[armnetwork.DefaultSecurityRulesClientListResponse] + +// DefaultSecurityRulesClient is an interface for interacting with Azure NSG default security rules (child of network security group). +type DefaultSecurityRulesClient interface { + Get(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, defaultSecurityRuleName string, options *armnetwork.DefaultSecurityRulesClientGetOptions) (armnetwork.DefaultSecurityRulesClientGetResponse, error) + NewListPager(resourceGroupName string, networkSecurityGroupName string, options *armnetwork.DefaultSecurityRulesClientListOptions) DefaultSecurityRulesPager +} + +type defaultSecurityRulesClient struct { + client *armnetwork.DefaultSecurityRulesClient +} + +func (c *defaultSecurityRulesClient) Get(ctx context.Context, resourceGroupName string, networkSecurityGroupName string, defaultSecurityRuleName string, options *armnetwork.DefaultSecurityRulesClientGetOptions) (armnetwork.DefaultSecurityRulesClientGetResponse, error) { + return c.client.Get(ctx, resourceGroupName, networkSecurityGroupName, defaultSecurityRuleName, options) +} + +func (c *defaultSecurityRulesClient) NewListPager(resourceGroupName string, networkSecurityGroupName string, options *armnetwork.DefaultSecurityRulesClientListOptions) DefaultSecurityRulesPager { + return c.client.NewListPager(resourceGroupName, networkSecurityGroupName, options) +} + +// NewDefaultSecurityRulesClient creates a new DefaultSecurityRulesClient from the Azure SDK client. +func NewDefaultSecurityRulesClient(client *armnetwork.DefaultSecurityRulesClient) DefaultSecurityRulesClient { + return &defaultSecurityRulesClient{client: client} +} diff --git a/sources/azure/manual/adapters.go b/sources/azure/manual/adapters.go index de518f3b..9378e4a3 100644 --- a/sources/azure/manual/adapters.go +++ b/sources/azure/manual/adapters.go @@ -237,6 +237,11 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred return nil, fmt.Errorf("failed to create security rules client: %w", err) } + defaultSecurityRulesClient, err := armnetwork.NewDefaultSecurityRulesClient(subscriptionID, cred, nil) + if err != nil { + return nil, fmt.Errorf("failed to create default security rules client: %w", err) + } + applicationGatewaysClient, err := armnetwork.NewApplicationGatewaysClient(subscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create application gateways client: %w", err) @@ -594,6 +599,10 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred clients.NewSecurityRulesClient(securityRulesClient), resourceGroupScopes, ), cache), + sources.WrapperToAdapter(NewNetworkDefaultSecurityRule( + clients.NewDefaultSecurityRulesClient(defaultSecurityRulesClient), + resourceGroupScopes, + ), cache), sources.WrapperToAdapter(NewNetworkApplicationGateway( clients.NewApplicationGatewaysClient(applicationGatewaysClient), resourceGroupScopes, @@ -763,6 +772,7 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred sources.WrapperToAdapter(NewNetworkNetworkSecurityGroup(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewNetworkApplicationSecurityGroup(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewNetworkSecurityRule(nil, placeholderResourceGroupScopes), noOpCache), + sources.WrapperToAdapter(NewNetworkDefaultSecurityRule(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewNetworkRouteTable(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewNetworkApplicationGateway(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewNetworkVirtualNetworkGateway(nil, placeholderResourceGroupScopes), noOpCache), diff --git a/sources/azure/manual/network-default-security-rule.go b/sources/azure/manual/network-default-security-rule.go new file mode 100644 index 00000000..84ed19f2 --- /dev/null +++ b/sources/azure/manual/network-default-security-rule.go @@ -0,0 +1,262 @@ +package manual + +import ( + "context" + "errors" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v9" + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/shared" + "github.com/overmindtech/cli/sources/stdlib" +) + +var NetworkDefaultSecurityRuleLookupByUniqueAttr = shared.NewItemTypeLookup("uniqueAttr", azureshared.NetworkDefaultSecurityRule) + +type networkDefaultSecurityRuleWrapper struct { + client clients.DefaultSecurityRulesClient + *azureshared.MultiResourceGroupBase +} + +// NewNetworkDefaultSecurityRule creates a new networkDefaultSecurityRuleWrapper instance (SearchableWrapper: child of network security group). +func NewNetworkDefaultSecurityRule(client clients.DefaultSecurityRulesClient, resourceGroupScopes []azureshared.ResourceGroupScope) sources.SearchableWrapper { + return &networkDefaultSecurityRuleWrapper{ + client: client, + MultiResourceGroupBase: azureshared.NewMultiResourceGroupBase( + resourceGroupScopes, + sdp.AdapterCategory_ADAPTER_CATEGORY_NETWORK, + azureshared.NetworkDefaultSecurityRule, + ), + } +} + +func (n networkDefaultSecurityRuleWrapper) Get(ctx context.Context, scope string, queryParts ...string) (*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 2 { + return nil, &sdp.QueryError{ + ErrorType: sdp.QueryError_OTHER, + ErrorString: "Get requires 2 query parts: networkSecurityGroupName and defaultSecurityRuleName", + Scope: scope, + ItemType: n.Type(), + } + } + nsgName := queryParts[0] + ruleName := queryParts[1] + if ruleName == "" { + return nil, azureshared.QueryError(errors.New("default security rule name cannot be empty"), scope, n.Type()) + } + + rgScope, err := n.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, n.Type()) + } + resp, err := n.client.Get(ctx, rgScope.ResourceGroup, nsgName, ruleName, nil) + if err != nil { + return nil, azureshared.QueryError(err, scope, n.Type()) + } + + return n.azureDefaultSecurityRuleToSDPItem(&resp.SecurityRule, nsgName, ruleName, scope) +} + +func (n networkDefaultSecurityRuleWrapper) GetLookups() sources.ItemTypeLookups { + return sources.ItemTypeLookups{ + NetworkNetworkSecurityGroupLookupByName, + NetworkDefaultSecurityRuleLookupByUniqueAttr, + } +} + +func (n networkDefaultSecurityRuleWrapper) Search(ctx context.Context, scope string, queryParts ...string) ([]*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 1 { + return nil, &sdp.QueryError{ + ErrorType: sdp.QueryError_OTHER, + ErrorString: "Search requires 1 query part: networkSecurityGroupName", + Scope: scope, + ItemType: n.Type(), + } + } + nsgName := queryParts[0] + + rgScope, err := n.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, n.Type()) + } + pager := n.client.NewListPager(rgScope.ResourceGroup, nsgName, nil) + + var items []*sdp.Item + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, azureshared.QueryError(err, scope, n.Type()) + } + for _, rule := range page.Value { + if rule == nil || rule.Name == nil { + continue + } + item, sdpErr := n.azureDefaultSecurityRuleToSDPItem(rule, nsgName, *rule.Name, scope) + if sdpErr != nil { + return nil, sdpErr + } + items = append(items, item) + } + } + return items, nil +} + +func (n networkDefaultSecurityRuleWrapper) SearchStream(ctx context.Context, stream discovery.QueryResultStream, cache sdpcache.Cache, cacheKey sdpcache.CacheKey, scope string, queryParts ...string) { + if len(queryParts) < 1 { + stream.SendError(azureshared.QueryError(errors.New("Search requires 1 query part: networkSecurityGroupName"), scope, n.Type())) + return + } + nsgName := queryParts[0] + + rgScope, err := n.ResourceGroupScopeFromScope(scope) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, n.Type())) + return + } + pager := n.client.NewListPager(rgScope.ResourceGroup, nsgName, nil) + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, n.Type())) + return + } + for _, rule := range page.Value { + if rule == nil || rule.Name == nil { + continue + } + item, sdpErr := n.azureDefaultSecurityRuleToSDPItem(rule, nsgName, *rule.Name, scope) + if sdpErr != nil { + stream.SendError(sdpErr) + continue + } + cache.StoreItem(ctx, item, shared.DefaultCacheDuration, cacheKey) + stream.SendItem(item) + } + } +} + +func (n networkDefaultSecurityRuleWrapper) SearchLookups() []sources.ItemTypeLookups { + return []sources.ItemTypeLookups{ + {NetworkNetworkSecurityGroupLookupByName}, + } +} + +func (n networkDefaultSecurityRuleWrapper) azureDefaultSecurityRuleToSDPItem(rule *armnetwork.SecurityRule, nsgName, ruleName, scope string) (*sdp.Item, *sdp.QueryError) { + attributes, err := shared.ToAttributesWithExclude(rule, "tags") + if err != nil { + return nil, azureshared.QueryError(err, scope, n.Type()) + } + + err = attributes.Set("uniqueAttr", shared.CompositeLookupKey(nsgName, ruleName)) + if err != nil { + return nil, azureshared.QueryError(err, scope, n.Type()) + } + + sdpItem := &sdp.Item{ + Type: azureshared.NetworkDefaultSecurityRule.String(), + UniqueAttribute: "uniqueAttr", + Attributes: attributes, + Scope: scope, + } + + // Link to parent Network Security Group + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkNetworkSecurityGroup.String(), + Method: sdp.QueryMethod_GET, + Query: nsgName, + Scope: scope, + }, + }) + + if rule.Properties != nil { + // Link to SourceApplicationSecurityGroups + if rule.Properties.SourceApplicationSecurityGroups != nil { + for _, asgRef := range rule.Properties.SourceApplicationSecurityGroups { + if asgRef != nil && asgRef.ID != nil { + asgName := azureshared.ExtractResourceName(*asgRef.ID) + if asgName != "" { + linkScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(*asgRef.ID); extractedScope != "" { + linkScope = extractedScope + } + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkApplicationSecurityGroup.String(), + Method: sdp.QueryMethod_GET, + Query: asgName, + Scope: linkScope, + }, + }) + } + } + } + } + + // Link to DestinationApplicationSecurityGroups + if rule.Properties.DestinationApplicationSecurityGroups != nil { + for _, asgRef := range rule.Properties.DestinationApplicationSecurityGroups { + if asgRef != nil && asgRef.ID != nil { + asgName := azureshared.ExtractResourceName(*asgRef.ID) + if asgName != "" { + linkScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(*asgRef.ID); extractedScope != "" { + linkScope = extractedScope + } + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkApplicationSecurityGroup.String(), + Method: sdp.QueryMethod_GET, + Query: asgName, + Scope: linkScope, + }, + }) + } + } + } + } + + // Link to stdlib.NetworkIP for source/destination address prefixes when they are IPs or CIDRs + if rule.Properties.SourceAddressPrefix != nil { + appendIPOrCIDRLinkIfValid(&sdpItem.LinkedItemQueries, *rule.Properties.SourceAddressPrefix) + } + for _, p := range rule.Properties.SourceAddressPrefixes { + if p != nil { + appendIPOrCIDRLinkIfValid(&sdpItem.LinkedItemQueries, *p) + } + } + if rule.Properties.DestinationAddressPrefix != nil { + appendIPOrCIDRLinkIfValid(&sdpItem.LinkedItemQueries, *rule.Properties.DestinationAddressPrefix) + } + for _, p := range rule.Properties.DestinationAddressPrefixes { + if p != nil { + appendIPOrCIDRLinkIfValid(&sdpItem.LinkedItemQueries, *p) + } + } + } + + return sdpItem, nil +} + +func (n networkDefaultSecurityRuleWrapper) PotentialLinks() map[shared.ItemType]bool { + return shared.NewItemTypesSet( + azureshared.NetworkNetworkSecurityGroup, + azureshared.NetworkApplicationSecurityGroup, + stdlib.NetworkIP, + ) +} + +// ref: https://learn.microsoft.com/en-us/rest/api/virtualnetwork/network-security-groups/get#defaultsecurityrules +func (n networkDefaultSecurityRuleWrapper) IAMPermissions() []string { + return []string{ + "Microsoft.Network/networkSecurityGroups/defaultSecurityRules/read", + } +} + +func (n networkDefaultSecurityRuleWrapper) PredefinedRole() string { + return "Reader" +} diff --git a/sources/azure/manual/network-default-security-rule_test.go b/sources/azure/manual/network-default-security-rule_test.go new file mode 100644 index 00000000..d900b59b --- /dev/null +++ b/sources/azure/manual/network-default-security-rule_test.go @@ -0,0 +1,300 @@ +package manual_test + +import ( + "context" + "errors" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v9" + "go.uber.org/mock/gomock" + + "github.com/overmindtech/cli/go/discovery" + sdp "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + "github.com/overmindtech/cli/sources/azure/manual" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/azure/shared/mocks" + "github.com/overmindtech/cli/sources/shared" +) + +type mockDefaultSecurityRulesPager struct { + pages []armnetwork.DefaultSecurityRulesClientListResponse + index int +} + +func (m *mockDefaultSecurityRulesPager) More() bool { + return m.index < len(m.pages) +} + +func (m *mockDefaultSecurityRulesPager) NextPage(ctx context.Context) (armnetwork.DefaultSecurityRulesClientListResponse, error) { + if m.index >= len(m.pages) { + return armnetwork.DefaultSecurityRulesClientListResponse{}, errors.New("no more pages") + } + page := m.pages[m.index] + m.index++ + return page, nil +} + +type errorDefaultSecurityRulesPager struct{} + +func (e *errorDefaultSecurityRulesPager) More() bool { + return true +} + +func (e *errorDefaultSecurityRulesPager) NextPage(ctx context.Context) (armnetwork.DefaultSecurityRulesClientListResponse, error) { + return armnetwork.DefaultSecurityRulesClientListResponse{}, errors.New("pager error") +} + +type testDefaultSecurityRulesClient struct { + *mocks.MockDefaultSecurityRulesClient + pager clients.DefaultSecurityRulesPager +} + +func (t *testDefaultSecurityRulesClient) NewListPager(resourceGroupName, networkSecurityGroupName string, options *armnetwork.DefaultSecurityRulesClientListOptions) clients.DefaultSecurityRulesPager { + return t.pager +} + +func TestNetworkDefaultSecurityRule(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + subscriptionID := "test-subscription" + resourceGroup := "test-rg" + nsgName := "test-nsg" + ruleName := "AllowVnetInBound" + + t.Run("Get", func(t *testing.T) { + rule := createAzureDefaultSecurityRule(ruleName, nsgName) + + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, nsgName, ruleName, nil).Return( + armnetwork.DefaultSecurityRulesClientGetResponse{ + SecurityRule: rule, + }, nil) + + testClient := &testDefaultSecurityRulesClient{MockDefaultSecurityRulesClient: mockClient} + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(nsgName, ruleName) + sdpItem, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + if sdpItem.GetType() != azureshared.NetworkDefaultSecurityRule.String() { + t.Errorf("Expected type %s, got %s", azureshared.NetworkDefaultSecurityRule, sdpItem.GetType()) + } + + if sdpItem.GetUniqueAttribute() != "uniqueAttr" { + t.Errorf("Expected unique attribute 'uniqueAttr', got %s", sdpItem.GetUniqueAttribute()) + } + + if sdpItem.UniqueAttributeValue() != shared.CompositeLookupKey(nsgName, ruleName) { + t.Errorf("Expected unique attribute value %s, got %s", shared.CompositeLookupKey(nsgName, ruleName), sdpItem.UniqueAttributeValue()) + } + + if sdpItem.GetScope() != subscriptionID+"."+resourceGroup { + t.Errorf("Expected scope %s, got %s", subscriptionID+"."+resourceGroup, sdpItem.GetScope()) + } + + if err := sdpItem.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + + t.Run("StaticTests", func(t *testing.T) { + queryTests := shared.QueryTests{ + { + ExpectedType: azureshared.NetworkNetworkSecurityGroup.String(), + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: nsgName, + ExpectedScope: subscriptionID + "." + resourceGroup, + }, + } + shared.RunStaticTests(t, adapter, sdpItem, queryTests) + }) + }) + + t.Run("Get_EmptyRuleName", func(t *testing.T) { + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + testClient := &testDefaultSecurityRulesClient{MockDefaultSecurityRulesClient: mockClient} + + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(nsgName, "") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when rule name is empty, but got nil") + } + }) + + t.Run("Get_InsufficientQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + testClient := &testDefaultSecurityRulesClient{MockDefaultSecurityRulesClient: mockClient} + + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], nsgName, true) + if qErr == nil { + t.Error("Expected error when providing insufficient query parts, but got nil") + } + }) + + t.Run("Search", func(t *testing.T) { + rule1 := createAzureDefaultSecurityRule("AllowVnetInBound", nsgName) + rule2 := createAzureDefaultSecurityRule("AllowAzureLoadBalancerInBound", nsgName) + + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + mockPager := &mockDefaultSecurityRulesPager{ + pages: []armnetwork.DefaultSecurityRulesClientListResponse{ + { + SecurityRuleListResult: armnetwork.SecurityRuleListResult{ + Value: []*armnetwork.SecurityRule{&rule1, &rule2}, + }, + }, + }, + } + + testClient := &testDefaultSecurityRulesClient{ + MockDefaultSecurityRulesClient: mockClient, + pager: mockPager, + } + + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable, ok := adapter.(discovery.SearchableAdapter) + if !ok { + t.Fatalf("Adapter does not support Search operation") + } + + sdpItems, err := searchable.Search(ctx, wrapper.Scopes()[0], nsgName, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if len(sdpItems) != 2 { + t.Fatalf("Expected 2 items, got: %d", len(sdpItems)) + } + + for _, item := range sdpItems { + if err := item.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + if item.GetType() != azureshared.NetworkDefaultSecurityRule.String() { + t.Errorf("Expected type %s, got %s", azureshared.NetworkDefaultSecurityRule, item.GetType()) + } + } + }) + + t.Run("Search_InvalidQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + testClient := &testDefaultSecurityRulesClient{MockDefaultSecurityRulesClient: mockClient} + + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + + _, qErr := wrapper.Search(ctx, wrapper.Scopes()[0]) + if qErr == nil { + t.Error("Expected error when providing no query parts, but got nil") + } + }) + + t.Run("Search_RuleWithNilName", func(t *testing.T) { + validRule := createAzureDefaultSecurityRule("AllowVnetInBound", nsgName) + + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + mockPager := &mockDefaultSecurityRulesPager{ + pages: []armnetwork.DefaultSecurityRulesClientListResponse{ + { + SecurityRuleListResult: armnetwork.SecurityRuleListResult{ + Value: []*armnetwork.SecurityRule{ + {Name: nil, ID: new(string)}, + &validRule, + }, + }, + }, + }, + } + + testClient := &testDefaultSecurityRulesClient{ + MockDefaultSecurityRulesClient: mockClient, + pager: mockPager, + } + + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable := adapter.(discovery.SearchableAdapter) + sdpItems, err := searchable.Search(ctx, wrapper.Scopes()[0], nsgName, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if len(sdpItems) != 1 { + t.Fatalf("Expected 1 item (nil name skipped), got: %d", len(sdpItems)) + } + if sdpItems[0].UniqueAttributeValue() != shared.CompositeLookupKey(nsgName, "AllowVnetInBound") { + t.Errorf("Expected unique value %s, got %s", shared.CompositeLookupKey(nsgName, "AllowVnetInBound"), sdpItems[0].UniqueAttributeValue()) + } + }) + + t.Run("ErrorHandling_Get", func(t *testing.T) { + expectedErr := errors.New("default security rule not found") + + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, nsgName, "nonexistent-rule", nil).Return( + armnetwork.DefaultSecurityRulesClientGetResponse{}, expectedErr) + + testClient := &testDefaultSecurityRulesClient{MockDefaultSecurityRulesClient: mockClient} + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(nsgName, "nonexistent-rule") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when getting non-existent rule, but got nil") + } + }) + + t.Run("ErrorHandling_Search", func(t *testing.T) { + mockClient := mocks.NewMockDefaultSecurityRulesClient(ctrl) + testClient := &testDefaultSecurityRulesClient{ + MockDefaultSecurityRulesClient: mockClient, + pager: &errorDefaultSecurityRulesPager{}, + } + + wrapper := manual.NewNetworkDefaultSecurityRule(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable := adapter.(discovery.SearchableAdapter) + _, err := searchable.Search(ctx, wrapper.Scopes()[0], nsgName, true) + if err == nil { + t.Error("Expected error from pager when NextPage returns an error, but got nil") + } + }) +} + +func createAzureDefaultSecurityRule(ruleName, nsgName string) armnetwork.SecurityRule { + idStr := "/subscriptions/test-subscription/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/" + nsgName + "/defaultSecurityRules/" + ruleName + typeStr := "Microsoft.Network/networkSecurityGroups/defaultSecurityRules" + access := armnetwork.SecurityRuleAccessAllow + direction := armnetwork.SecurityRuleDirectionInbound + protocol := armnetwork.SecurityRuleProtocolAsterisk + priority := int32(65000) + return armnetwork.SecurityRule{ + ID: &idStr, + Name: &ruleName, + Type: &typeStr, + Properties: &armnetwork.SecurityRulePropertiesFormat{ + Access: &access, + Direction: &direction, + Protocol: &protocol, + Priority: &priority, + }, + } +} diff --git a/sources/azure/shared/mocks/mock_default_security_rules_client.go b/sources/azure/shared/mocks/mock_default_security_rules_client.go new file mode 100644 index 00000000..e1f5088e --- /dev/null +++ b/sources/azure/shared/mocks/mock_default_security_rules_client.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: default-security-rules-client.go +// +// Generated by this command: +// +// mockgen -destination=../shared/mocks/mock_default_security_rules_client.go -package=mocks -source=default-security-rules-client.go +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v9" + clients "github.com/overmindtech/cli/sources/azure/clients" + gomock "go.uber.org/mock/gomock" +) + +// MockDefaultSecurityRulesClient is a mock of DefaultSecurityRulesClient interface. +type MockDefaultSecurityRulesClient struct { + ctrl *gomock.Controller + recorder *MockDefaultSecurityRulesClientMockRecorder + isgomock struct{} +} + +// MockDefaultSecurityRulesClientMockRecorder is the mock recorder for MockDefaultSecurityRulesClient. +type MockDefaultSecurityRulesClientMockRecorder struct { + mock *MockDefaultSecurityRulesClient +} + +// NewMockDefaultSecurityRulesClient creates a new mock instance. +func NewMockDefaultSecurityRulesClient(ctrl *gomock.Controller) *MockDefaultSecurityRulesClient { + mock := &MockDefaultSecurityRulesClient{ctrl: ctrl} + mock.recorder = &MockDefaultSecurityRulesClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDefaultSecurityRulesClient) EXPECT() *MockDefaultSecurityRulesClientMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockDefaultSecurityRulesClient) Get(ctx context.Context, resourceGroupName, networkSecurityGroupName, defaultSecurityRuleName string, options *armnetwork.DefaultSecurityRulesClientGetOptions) (armnetwork.DefaultSecurityRulesClientGetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, networkSecurityGroupName, defaultSecurityRuleName, options) + ret0, _ := ret[0].(armnetwork.DefaultSecurityRulesClientGetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockDefaultSecurityRulesClientMockRecorder) Get(ctx, resourceGroupName, networkSecurityGroupName, defaultSecurityRuleName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDefaultSecurityRulesClient)(nil).Get), ctx, resourceGroupName, networkSecurityGroupName, defaultSecurityRuleName, options) +} + +// NewListPager mocks base method. +func (m *MockDefaultSecurityRulesClient) NewListPager(resourceGroupName, networkSecurityGroupName string, options *armnetwork.DefaultSecurityRulesClientListOptions) clients.DefaultSecurityRulesPager { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewListPager", resourceGroupName, networkSecurityGroupName, options) + ret0, _ := ret[0].(clients.DefaultSecurityRulesPager) + return ret0 +} + +// NewListPager indicates an expected call of NewListPager. +func (mr *MockDefaultSecurityRulesClientMockRecorder) NewListPager(resourceGroupName, networkSecurityGroupName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListPager", reflect.TypeOf((*MockDefaultSecurityRulesClient)(nil).NewListPager), resourceGroupName, networkSecurityGroupName, options) +} diff --git a/sources/azure/shared/utils.go b/sources/azure/shared/utils.go index c6cb696c..7e54b6c7 100644 --- a/sources/azure/shared/utils.go +++ b/sources/azure/shared/utils.go @@ -48,6 +48,7 @@ func GetResourceIDPathKeys(resourceType string) []string { "azure-network-virtual-network-peering": {"virtualNetworks", "virtualNetworkPeerings"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnetName}/virtualNetworkPeerings/{peeringName}", "azure-network-route": {"routeTables", "routes"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/routeTables/{routeTableName}/routes/{routeName}", "azure-network-security-rule": {"networkSecurityGroups", "securityRules"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/networkSecurityGroups/{nsgName}/securityRules/{ruleName}", + "azure-network-default-security-rule": {"networkSecurityGroups", "defaultSecurityRules"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/networkSecurityGroups/{nsgName}/defaultSecurityRules/{ruleName}", "azure-batch-batch-application": {"batchAccounts", "applications"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/applications/{applicationName}", "azure-batch-batch-pool": {"batchAccounts", "pools"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools/{poolName}", "azure-network-dns-record-set": {"dnszones"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/dnszones/{zoneName}/{recordType}/{relativeRecordSetName}" From 159426551cfd085699f42118c64917b377cfb3a7 Mon Sep 17 00:00:00 2001 From: Lionel Wilson <80872669+Lionel-Wilson@users.noreply.github.com> Date: Tue, 10 Mar 2026 18:11:46 +0000 Subject: [PATCH 08/18] feat: implement ComputeDiskAccessPrivateEndpointConnection adapter (#4217) image --- > [!NOTE] > **Low Risk** > Adds a new read-only adapter and resource-ID parsing entry without changing existing adapter behavior; risk is mainly incorrect query-part parsing or linking causing missing/extra discovered items. > > **Overview** > Adds support for discovering Azure **Disk Access private endpoint connections** as a first-class item type. > > Introduces a new compute client interface + generated mock, a `SearchableWrapper` adapter that supports `Get` (by `diskAccessName` + connection name) and `Search/SearchStream` (list connections for a disk access), maps provisioning state to item health, and emits links to the parent `ComputeDiskAccess` and referenced `NetworkPrivateEndpoint`. > > Wires the new adapter into Azure `Adapters()` (including metadata-only mode) and updates `shared.GetResourceIDPathKeys` to parse this resource type from Azure resource IDs; adds unit tests covering happy paths, paging, nil-name filtering, and error handling. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fca452d9c38741050cb8789b70e89e5c94021b20. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: b5fa1330f689e5ff42d8a2a49e2621cad8986e62 --- ...cess-private-endpoint-connection-client.go | 35 ++ sources/azure/manual/adapters.go | 5 + ...disk-access-private-endpoint-connection.go | 235 +++++++++++++ ...access-private-endpoint-connection_test.go | 322 ++++++++++++++++++ ...cess_private_endpoint_connection_client.go | 72 ++++ sources/azure/shared/utils.go | 1 + 6 files changed, 670 insertions(+) create mode 100644 sources/azure/clients/compute-disk-access-private-endpoint-connection-client.go create mode 100644 sources/azure/manual/compute-disk-access-private-endpoint-connection.go create mode 100644 sources/azure/manual/compute-disk-access-private-endpoint-connection_test.go create mode 100644 sources/azure/shared/mocks/mock_compute_disk_access_private_endpoint_connection_client.go diff --git a/sources/azure/clients/compute-disk-access-private-endpoint-connection-client.go b/sources/azure/clients/compute-disk-access-private-endpoint-connection-client.go new file mode 100644 index 00000000..a47bab1e --- /dev/null +++ b/sources/azure/clients/compute-disk-access-private-endpoint-connection-client.go @@ -0,0 +1,35 @@ +package clients + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v7" +) + +//go:generate mockgen -destination=../shared/mocks/mock_compute_disk_access_private_endpoint_connection_client.go -package=mocks -source=compute-disk-access-private-endpoint-connection-client.go + +// ComputeDiskAccessPrivateEndpointConnectionsPager is a type alias for the generic Pager interface with disk access private endpoint connection list response type. +type ComputeDiskAccessPrivateEndpointConnectionsPager = Pager[armcompute.DiskAccessesClientListPrivateEndpointConnectionsResponse] + +// ComputeDiskAccessPrivateEndpointConnectionsClient is an interface for interacting with Azure disk access private endpoint connections. +type ComputeDiskAccessPrivateEndpointConnectionsClient interface { + Get(ctx context.Context, resourceGroupName string, diskAccessName string, privateEndpointConnectionName string) (armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse, error) + NewListPrivateEndpointConnectionsPager(resourceGroupName string, diskAccessName string, options *armcompute.DiskAccessesClientListPrivateEndpointConnectionsOptions) ComputeDiskAccessPrivateEndpointConnectionsPager +} + +type computeDiskAccessPrivateEndpointConnectionsClient struct { + client *armcompute.DiskAccessesClient +} + +func (c *computeDiskAccessPrivateEndpointConnectionsClient) Get(ctx context.Context, resourceGroupName string, diskAccessName string, privateEndpointConnectionName string) (armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse, error) { + return c.client.GetAPrivateEndpointConnection(ctx, resourceGroupName, diskAccessName, privateEndpointConnectionName, nil) +} + +func (c *computeDiskAccessPrivateEndpointConnectionsClient) NewListPrivateEndpointConnectionsPager(resourceGroupName string, diskAccessName string, options *armcompute.DiskAccessesClientListPrivateEndpointConnectionsOptions) ComputeDiskAccessPrivateEndpointConnectionsPager { + return c.client.NewListPrivateEndpointConnectionsPager(resourceGroupName, diskAccessName, options) +} + +// NewComputeDiskAccessPrivateEndpointConnectionsClient creates a new ComputeDiskAccessPrivateEndpointConnectionsClient from the Azure SDK DiskAccesses client. +func NewComputeDiskAccessPrivateEndpointConnectionsClient(client *armcompute.DiskAccessesClient) ComputeDiskAccessPrivateEndpointConnectionsClient { + return &computeDiskAccessPrivateEndpointConnectionsClient{client: client} +} diff --git a/sources/azure/manual/adapters.go b/sources/azure/manual/adapters.go index 9378e4a3..9cbeead3 100644 --- a/sources/azure/manual/adapters.go +++ b/sources/azure/manual/adapters.go @@ -671,6 +671,10 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred clients.NewDiskAccessesClient(diskAccessesClient), resourceGroupScopes, ), cache), + sources.WrapperToAdapter(NewComputeDiskAccessPrivateEndpointConnection( + clients.NewComputeDiskAccessPrivateEndpointConnectionsClient(diskAccessesClient), + resourceGroupScopes, + ), cache), sources.WrapperToAdapter(NewComputeDedicatedHostGroup( clients.NewDedicatedHostGroupsClient(dedicatedHostGroupsClient), resourceGroupScopes, @@ -791,6 +795,7 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred sources.WrapperToAdapter(NewComputeVirtualMachineExtension(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeProximityPlacementGroup(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeDiskAccess(nil, placeholderResourceGroupScopes), noOpCache), + sources.WrapperToAdapter(NewComputeDiskAccessPrivateEndpointConnection(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeDedicatedHostGroup(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeDedicatedHost(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeCapacityReservationGroup(nil, placeholderResourceGroupScopes), noOpCache), diff --git a/sources/azure/manual/compute-disk-access-private-endpoint-connection.go b/sources/azure/manual/compute-disk-access-private-endpoint-connection.go new file mode 100644 index 00000000..429364d9 --- /dev/null +++ b/sources/azure/manual/compute-disk-access-private-endpoint-connection.go @@ -0,0 +1,235 @@ +package manual + +import ( + "context" + "errors" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v7" + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/shared" +) + +var ComputeDiskAccessPrivateEndpointConnectionLookupByName = shared.NewItemTypeLookup("name", azureshared.ComputeDiskAccessPrivateEndpointConnection) + +type computeDiskAccessPrivateEndpointConnectionWrapper struct { + client clients.ComputeDiskAccessPrivateEndpointConnectionsClient + + *azureshared.MultiResourceGroupBase +} + +// NewComputeDiskAccessPrivateEndpointConnection returns a SearchableWrapper for Azure disk access private endpoint connections. +func NewComputeDiskAccessPrivateEndpointConnection(client clients.ComputeDiskAccessPrivateEndpointConnectionsClient, resourceGroupScopes []azureshared.ResourceGroupScope) sources.SearchableWrapper { + return &computeDiskAccessPrivateEndpointConnectionWrapper{ + client: client, + MultiResourceGroupBase: azureshared.NewMultiResourceGroupBase( + resourceGroupScopes, + sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + azureshared.ComputeDiskAccessPrivateEndpointConnection, + ), + } +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) Get(ctx context.Context, scope string, queryParts ...string) (*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 2 { + return nil, &sdp.QueryError{ + ErrorType: sdp.QueryError_OTHER, + ErrorString: "Get requires 2 query parts: diskAccessName and privateEndpointConnectionName", + Scope: scope, + ItemType: s.Type(), + } + } + diskAccessName := queryParts[0] + connectionName := queryParts[1] + + rgScope, err := s.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + resp, err := s.client.Get(ctx, rgScope.ResourceGroup, diskAccessName, connectionName) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + + item, sdpErr := s.azurePrivateEndpointConnectionToSDPItem(&resp.PrivateEndpointConnection, diskAccessName, connectionName, scope) + if sdpErr != nil { + return nil, sdpErr + } + return item, nil +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) GetLookups() sources.ItemTypeLookups { + return sources.ItemTypeLookups{ + ComputeDiskAccessLookupByName, + ComputeDiskAccessPrivateEndpointConnectionLookupByName, + } +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) Search(ctx context.Context, scope string, queryParts ...string) ([]*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 1 { + return nil, &sdp.QueryError{ + ErrorType: sdp.QueryError_OTHER, + ErrorString: "Search requires 1 query part: diskAccessName", + Scope: scope, + ItemType: s.Type(), + } + } + diskAccessName := queryParts[0] + + rgScope, err := s.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + pager := s.client.NewListPrivateEndpointConnectionsPager(rgScope.ResourceGroup, diskAccessName, nil) + + var items []*sdp.Item + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + + for _, conn := range page.Value { + if conn == nil || conn.Name == nil { + continue + } + + item, sdpErr := s.azurePrivateEndpointConnectionToSDPItem(conn, diskAccessName, *conn.Name, scope) + if sdpErr != nil { + return nil, sdpErr + } + items = append(items, item) + } + } + + return items, nil +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) SearchStream(ctx context.Context, stream discovery.QueryResultStream, cache sdpcache.Cache, cacheKey sdpcache.CacheKey, scope string, queryParts ...string) { + if len(queryParts) < 1 { + stream.SendError(azureshared.QueryError(errors.New("Search requires 1 query part: diskAccessName"), scope, s.Type())) + return + } + diskAccessName := queryParts[0] + + rgScope, err := s.ResourceGroupScopeFromScope(scope) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, s.Type())) + return + } + pager := s.client.NewListPrivateEndpointConnectionsPager(rgScope.ResourceGroup, diskAccessName, nil) + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, s.Type())) + return + } + for _, conn := range page.Value { + if conn == nil || conn.Name == nil { + continue + } + item, sdpErr := s.azurePrivateEndpointConnectionToSDPItem(conn, diskAccessName, *conn.Name, scope) + if sdpErr != nil { + stream.SendError(sdpErr) + continue + } + cache.StoreItem(ctx, item, shared.DefaultCacheDuration, cacheKey) + stream.SendItem(item) + } + } +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) SearchLookups() []sources.ItemTypeLookups { + return []sources.ItemTypeLookups{ + { + ComputeDiskAccessLookupByName, + }, + } +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) PotentialLinks() map[shared.ItemType]bool { + return map[shared.ItemType]bool{ + azureshared.ComputeDiskAccess: true, + azureshared.NetworkPrivateEndpoint: true, + } +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) azurePrivateEndpointConnectionToSDPItem(conn *armcompute.PrivateEndpointConnection, diskAccessName, connectionName, scope string) (*sdp.Item, *sdp.QueryError) { + attributes, err := shared.ToAttributesWithExclude(conn) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + + err = attributes.Set("uniqueAttr", shared.CompositeLookupKey(diskAccessName, connectionName)) + if err != nil { + return nil, azureshared.QueryError(err, scope, s.Type()) + } + + sdpItem := &sdp.Item{ + Type: azureshared.ComputeDiskAccessPrivateEndpointConnection.String(), + UniqueAttribute: "uniqueAttr", + Attributes: attributes, + Scope: scope, + } + + // Health from provisioning state + if conn.Properties != nil && conn.Properties.ProvisioningState != nil { + switch *conn.Properties.ProvisioningState { + case armcompute.PrivateEndpointConnectionProvisioningStateSucceeded: + sdpItem.Health = sdp.Health_HEALTH_OK.Enum() + case armcompute.PrivateEndpointConnectionProvisioningStateCreating, + armcompute.PrivateEndpointConnectionProvisioningStateDeleting: + sdpItem.Health = sdp.Health_HEALTH_PENDING.Enum() + case armcompute.PrivateEndpointConnectionProvisioningStateFailed: + sdpItem.Health = sdp.Health_HEALTH_ERROR.Enum() + default: + sdpItem.Health = sdp.Health_HEALTH_UNKNOWN.Enum() + } + } + + // Link to parent Disk Access + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ComputeDiskAccess.String(), + Method: sdp.QueryMethod_GET, + Query: diskAccessName, + Scope: scope, + }, + }) + + // Link to Network Private Endpoint when present (may be in different resource group) + if conn.Properties != nil && conn.Properties.PrivateEndpoint != nil && conn.Properties.PrivateEndpoint.ID != nil { + peID := *conn.Properties.PrivateEndpoint.ID + peName := azureshared.ExtractResourceName(peID) + if peName != "" { + linkedScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(peID); extractedScope != "" { + linkedScope = extractedScope + } + sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkPrivateEndpoint.String(), + Method: sdp.QueryMethod_GET, + Query: peName, + Scope: linkedScope, + }, + }) + } + } + + return sdpItem, nil +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) IAMPermissions() []string { + return []string{ + "Microsoft.Compute/diskAccesses/privateEndpointConnections/read", + } +} + +func (s computeDiskAccessPrivateEndpointConnectionWrapper) PredefinedRole() string { + return "Reader" +} diff --git a/sources/azure/manual/compute-disk-access-private-endpoint-connection_test.go b/sources/azure/manual/compute-disk-access-private-endpoint-connection_test.go new file mode 100644 index 00000000..9418325b --- /dev/null +++ b/sources/azure/manual/compute-disk-access-private-endpoint-connection_test.go @@ -0,0 +1,322 @@ +package manual_test + +import ( + "context" + "errors" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v7" + "go.uber.org/mock/gomock" + + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + "github.com/overmindtech/cli/sources/azure/manual" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/azure/shared/mocks" + "github.com/overmindtech/cli/sources/shared" +) + +type mockComputeDiskAccessPrivateEndpointConnectionsPager struct { + pages []armcompute.DiskAccessesClientListPrivateEndpointConnectionsResponse + index int +} + +func (m *mockComputeDiskAccessPrivateEndpointConnectionsPager) More() bool { + return m.index < len(m.pages) +} + +func (m *mockComputeDiskAccessPrivateEndpointConnectionsPager) NextPage(ctx context.Context) (armcompute.DiskAccessesClientListPrivateEndpointConnectionsResponse, error) { + if m.index >= len(m.pages) { + return armcompute.DiskAccessesClientListPrivateEndpointConnectionsResponse{}, errors.New("no more pages") + } + page := m.pages[m.index] + m.index++ + return page, nil +} + +type testComputeDiskAccessPrivateEndpointConnectionsClient struct { + *mocks.MockComputeDiskAccessPrivateEndpointConnectionsClient + pager clients.ComputeDiskAccessPrivateEndpointConnectionsPager +} + +func (t *testComputeDiskAccessPrivateEndpointConnectionsClient) NewListPrivateEndpointConnectionsPager(resourceGroupName string, diskAccessName string, options *armcompute.DiskAccessesClientListPrivateEndpointConnectionsOptions) clients.ComputeDiskAccessPrivateEndpointConnectionsPager { + return t.pager +} + +func TestComputeDiskAccessPrivateEndpointConnection(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + subscriptionID := "test-subscription" + resourceGroup := "test-rg" + diskAccessName := "test-disk-access" + connectionName := "test-pec" + + t.Run("Get", func(t *testing.T) { + conn := createAzureComputeDiskAccessPrivateEndpointConnection(connectionName, "") + + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, diskAccessName, connectionName).Return( + armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse{ + PrivateEndpointConnection: *conn, + }, nil) + + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient} + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(diskAccessName, connectionName) + sdpItem, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + if sdpItem.GetType() != azureshared.ComputeDiskAccessPrivateEndpointConnection.String() { + t.Errorf("Expected type %s, got %s", azureshared.ComputeDiskAccessPrivateEndpointConnection.String(), sdpItem.GetType()) + } + + if sdpItem.GetUniqueAttribute() != "uniqueAttr" { + t.Errorf("Expected unique attribute 'uniqueAttr', got %s", sdpItem.GetUniqueAttribute()) + } + + if sdpItem.UniqueAttributeValue() != shared.CompositeLookupKey(diskAccessName, connectionName) { + t.Errorf("Expected unique attribute value %s, got %s", shared.CompositeLookupKey(diskAccessName, connectionName), sdpItem.UniqueAttributeValue()) + } + + if sdpItem.GetScope() != subscriptionID+"."+resourceGroup { + t.Errorf("Expected scope %s, got %s", subscriptionID+"."+resourceGroup, sdpItem.GetScope()) + } + + if err := sdpItem.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + + t.Run("StaticTests", func(t *testing.T) { + linkedQueries := sdpItem.GetLinkedItemQueries() + if len(linkedQueries) < 1 { + t.Fatalf("Expected at least 1 linked query, got: %d", len(linkedQueries)) + } + + foundDiskAccess := false + for _, lq := range linkedQueries { + if lq.GetQuery().GetType() == azureshared.ComputeDiskAccess.String() { + foundDiskAccess = true + if lq.GetQuery().GetMethod() != sdp.QueryMethod_GET { + t.Errorf("Expected ComputeDiskAccess link method GET, got %v", lq.GetQuery().GetMethod()) + } + if lq.GetQuery().GetQuery() != diskAccessName { + t.Errorf("Expected ComputeDiskAccess query %s, got %s", diskAccessName, lq.GetQuery().GetQuery()) + } + } + } + if !foundDiskAccess { + t.Error("Expected linked query to ComputeDiskAccess") + } + }) + }) + + t.Run("Get_WithPrivateEndpointLink", func(t *testing.T) { + peID := "/subscriptions/" + subscriptionID + "/resourceGroups/" + resourceGroup + "/providers/Microsoft.Network/privateEndpoints/test-pe" + conn := createAzureComputeDiskAccessPrivateEndpointConnection(connectionName, peID) + + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, diskAccessName, connectionName).Return( + armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse{ + PrivateEndpointConnection: *conn, + }, nil) + + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient} + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(diskAccessName, connectionName) + sdpItem, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + foundPrivateEndpoint := false + for _, lq := range sdpItem.GetLinkedItemQueries() { + if lq.GetQuery().GetType() == azureshared.NetworkPrivateEndpoint.String() { + foundPrivateEndpoint = true + if lq.GetQuery().GetQuery() != "test-pe" { + t.Errorf("Expected NetworkPrivateEndpoint query 'test-pe', got %s", lq.GetQuery().GetQuery()) + } + break + } + } + if !foundPrivateEndpoint { + t.Error("Expected linked query to NetworkPrivateEndpoint when PrivateEndpoint ID is set") + } + }) + + t.Run("GetWithInsufficientQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient} + + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], diskAccessName, true) + if qErr == nil { + t.Error("Expected error when providing insufficient query parts, but got nil") + } + }) + + t.Run("Search", func(t *testing.T) { + conn1 := createAzureComputeDiskAccessPrivateEndpointConnection("pec-1", "") + conn2 := createAzureComputeDiskAccessPrivateEndpointConnection("pec-2", "") + + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + mockPager := &mockComputeDiskAccessPrivateEndpointConnectionsPager{ + pages: []armcompute.DiskAccessesClientListPrivateEndpointConnectionsResponse{ + { + PrivateEndpointConnectionListResult: armcompute.PrivateEndpointConnectionListResult{ + Value: []*armcompute.PrivateEndpointConnection{conn1, conn2}, + }, + }, + }, + } + + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{ + MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient, + pager: mockPager, + } + + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable, ok := adapter.(discovery.SearchableAdapter) + if !ok { + t.Fatalf("Adapter does not support Search operation") + } + + sdpItems, err := searchable.Search(ctx, wrapper.Scopes()[0], diskAccessName, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if len(sdpItems) != 2 { + t.Fatalf("Expected 2 items, got: %d", len(sdpItems)) + } + + for _, item := range sdpItems { + if err := item.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + if item.GetType() != azureshared.ComputeDiskAccessPrivateEndpointConnection.String() { + t.Errorf("Expected type %s, got %s", azureshared.ComputeDiskAccessPrivateEndpointConnection.String(), item.GetType()) + } + } + }) + + t.Run("Search_NilNameSkipped", func(t *testing.T) { + validConn := createAzureComputeDiskAccessPrivateEndpointConnection("valid-pec", "") + + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + mockPager := &mockComputeDiskAccessPrivateEndpointConnectionsPager{ + pages: []armcompute.DiskAccessesClientListPrivateEndpointConnectionsResponse{ + { + PrivateEndpointConnectionListResult: armcompute.PrivateEndpointConnectionListResult{ + Value: []*armcompute.PrivateEndpointConnection{ + {Name: nil}, + validConn, + }, + }, + }, + }, + } + + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{ + MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient, + pager: mockPager, + } + + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable, ok := adapter.(discovery.SearchableAdapter) + if !ok { + t.Fatalf("Adapter does not support Search operation") + } + + sdpItems, err := searchable.Search(ctx, wrapper.Scopes()[0], diskAccessName, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if len(sdpItems) != 1 { + t.Fatalf("Expected 1 item (nil name skipped), got: %d", len(sdpItems)) + } + if sdpItems[0].UniqueAttributeValue() != shared.CompositeLookupKey(diskAccessName, "valid-pec") { + t.Errorf("Expected unique value %s, got %s", shared.CompositeLookupKey(diskAccessName, "valid-pec"), sdpItems[0].UniqueAttributeValue()) + } + }) + + t.Run("Search_InvalidQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient} + + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + + _, qErr := wrapper.Search(ctx, wrapper.Scopes()[0]) + if qErr == nil { + t.Error("Expected error when providing no query parts, but got nil") + } + }) + + t.Run("ErrorHandling_Get", func(t *testing.T) { + expectedErr := errors.New("private endpoint connection not found") + + mockClient := mocks.NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, diskAccessName, "nonexistent-pec").Return( + armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse{}, expectedErr) + + testClient := &testComputeDiskAccessPrivateEndpointConnectionsClient{MockComputeDiskAccessPrivateEndpointConnectionsClient: mockClient} + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(testClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(diskAccessName, "nonexistent-pec") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when getting non-existent private endpoint connection, but got nil") + } + }) + + t.Run("PotentialLinks", func(t *testing.T) { + wrapper := manual.NewComputeDiskAccessPrivateEndpointConnection(nil, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + links := wrapper.PotentialLinks() + if !links[azureshared.ComputeDiskAccess] { + t.Error("Expected ComputeDiskAccess in PotentialLinks") + } + if !links[azureshared.NetworkPrivateEndpoint] { + t.Error("Expected NetworkPrivateEndpoint in PotentialLinks") + } + }) +} + +func createAzureComputeDiskAccessPrivateEndpointConnection(connectionName, privateEndpointID string) *armcompute.PrivateEndpointConnection { + state := armcompute.PrivateEndpointConnectionProvisioningStateSucceeded + status := armcompute.PrivateEndpointServiceConnectionStatusApproved + conn := &armcompute.PrivateEndpointConnection{ + ID: new("/subscriptions/test-subscription/resourceGroups/test-rg/providers/Microsoft.Compute/diskAccesses/test-disk-access/privateEndpointConnections/" + connectionName), + Name: new(connectionName), + Type: new("Microsoft.Compute/diskAccesses/privateEndpointConnections"), + Properties: &armcompute.PrivateEndpointConnectionProperties{ + ProvisioningState: &state, + PrivateLinkServiceConnectionState: &armcompute.PrivateLinkServiceConnectionState{ + Status: &status, + }, + }, + } + if privateEndpointID != "" { + conn.Properties.PrivateEndpoint = &armcompute.PrivateEndpoint{ + ID: new(privateEndpointID), + } + } + return conn +} diff --git a/sources/azure/shared/mocks/mock_compute_disk_access_private_endpoint_connection_client.go b/sources/azure/shared/mocks/mock_compute_disk_access_private_endpoint_connection_client.go new file mode 100644 index 00000000..2b30a74e --- /dev/null +++ b/sources/azure/shared/mocks/mock_compute_disk_access_private_endpoint_connection_client.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: compute-disk-access-private-endpoint-connection-client.go +// +// Generated by this command: +// +// mockgen -destination=../shared/mocks/mock_compute_disk_access_private_endpoint_connection_client.go -package=mocks -source=compute-disk-access-private-endpoint-connection-client.go +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + armcompute "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v7" + clients "github.com/overmindtech/cli/sources/azure/clients" + gomock "go.uber.org/mock/gomock" +) + +// MockComputeDiskAccessPrivateEndpointConnectionsClient is a mock of ComputeDiskAccessPrivateEndpointConnectionsClient interface. +type MockComputeDiskAccessPrivateEndpointConnectionsClient struct { + ctrl *gomock.Controller + recorder *MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder + isgomock struct{} +} + +// MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder is the mock recorder for MockComputeDiskAccessPrivateEndpointConnectionsClient. +type MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder struct { + mock *MockComputeDiskAccessPrivateEndpointConnectionsClient +} + +// NewMockComputeDiskAccessPrivateEndpointConnectionsClient creates a new mock instance. +func NewMockComputeDiskAccessPrivateEndpointConnectionsClient(ctrl *gomock.Controller) *MockComputeDiskAccessPrivateEndpointConnectionsClient { + mock := &MockComputeDiskAccessPrivateEndpointConnectionsClient{ctrl: ctrl} + mock.recorder = &MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockComputeDiskAccessPrivateEndpointConnectionsClient) EXPECT() *MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockComputeDiskAccessPrivateEndpointConnectionsClient) Get(ctx context.Context, resourceGroupName, diskAccessName, privateEndpointConnectionName string) (armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, diskAccessName, privateEndpointConnectionName) + ret0, _ := ret[0].(armcompute.DiskAccessesClientGetAPrivateEndpointConnectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder) Get(ctx, resourceGroupName, diskAccessName, privateEndpointConnectionName any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockComputeDiskAccessPrivateEndpointConnectionsClient)(nil).Get), ctx, resourceGroupName, diskAccessName, privateEndpointConnectionName) +} + +// NewListPrivateEndpointConnectionsPager mocks base method. +func (m *MockComputeDiskAccessPrivateEndpointConnectionsClient) NewListPrivateEndpointConnectionsPager(resourceGroupName, diskAccessName string, options *armcompute.DiskAccessesClientListPrivateEndpointConnectionsOptions) clients.ComputeDiskAccessPrivateEndpointConnectionsPager { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewListPrivateEndpointConnectionsPager", resourceGroupName, diskAccessName, options) + ret0, _ := ret[0].(clients.ComputeDiskAccessPrivateEndpointConnectionsPager) + return ret0 +} + +// NewListPrivateEndpointConnectionsPager indicates an expected call of NewListPrivateEndpointConnectionsPager. +func (mr *MockComputeDiskAccessPrivateEndpointConnectionsClientMockRecorder) NewListPrivateEndpointConnectionsPager(resourceGroupName, diskAccessName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListPrivateEndpointConnectionsPager", reflect.TypeOf((*MockComputeDiskAccessPrivateEndpointConnectionsClient)(nil).NewListPrivateEndpointConnectionsPager), resourceGroupName, diskAccessName, options) +} diff --git a/sources/azure/shared/utils.go b/sources/azure/shared/utils.go index 7e54b6c7..72f305ad 100644 --- a/sources/azure/shared/utils.go +++ b/sources/azure/shared/utils.go @@ -53,6 +53,7 @@ func GetResourceIDPathKeys(resourceType string) []string { "azure-batch-batch-pool": {"batchAccounts", "pools"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools/{poolName}", "azure-network-dns-record-set": {"dnszones"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/dnszones/{zoneName}/{recordType}/{relativeRecordSetName}" "azure-elasticsan-elastic-san-volume-snapshot": {"elasticSans", "volumegroups", "snapshots"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ElasticSan/elasticSans/{elasticSanName}/volumegroups/{volumeGroupName}/snapshots/{snapshotName}" + "azure-compute-disk-access-private-endpoint-connection": {"diskAccesses", "privateEndpointConnections"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Compute/diskAccesses/{diskAccessName}/privateEndpointConnections/{connectionName}" } if keys, ok := pathKeysMap[resourceType]; ok { From 4a7eb59956694b1e1eafd789f53357dfa866dbdb Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Wed, 11 Mar 2026 10:02:46 +0100 Subject: [PATCH 09/18] [ENG-3089] Relax bbolt cache durability to fix goroutine pileup (#4221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Skip `fdatasync` on every bbolt commit in the sdpcache layer by setting `NoSync: true` and `NoFreelistSync: true` - Eliminates the single-writer bottleneck that cascaded into 36K stuck goroutines under load (bbolt serializes write transactions behind fdatasync, ~930 pool workers were queuing on the write lock) - Safe because sdpcache is a pure cache -- crash durability provides no value ## Linear Ticket - **Ticket**: [ENG-3089](https://linear.app/overmind/issue/ENG-3089/relax-bbolt-cache-durability-to-fix-goroutine-pileup-under-load) — Relax bbolt cache durability to fix goroutine pileup under load - **Purpose**: Remove the fdatasync bottleneck that causes cascading goroutine pileups when sources are under heavy query load - **Priority**: Urgent ## Changes Single file change in `go/sdpcache/bolt_cache.go`: 1. Added a package-level `cacheOpenOptions` variable with `NoSync: true`, `NoFreelistSync: true`, and the existing `Timeout: 5s` 2. Replaced all 7 inline `&bbolt.Options{Timeout: 5 * time.Second}` with `cacheOpenOptions` All sdpcache tests pass. No API or behavioral change -- only the fsync guarantee is relaxed, which is irrelevant for a cache. Made with [Cursor](https://cursor.com) --- > [!NOTE] > **Medium Risk** > Disables bbolt fsync and freelist syncing for the cache DB, which can improve throughput but increases the chance of cache corruption/loss after crashes or power failures. > > **Overview** > Introduces a shared `cacheOpenOptions` for all `bbolt.Open` calls in `sdpcache` that sets `NoSync` and `NoFreelistSync` (keeping the existing 5s `Timeout`) to avoid per-commit `fdatasync` overhead. > > All cache DB open/reopen paths (startup, deletion recovery, and compaction temp DB creation/reopen) are updated to use these relaxed durability settings. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 60297db5a8b4e78b25a685c30ad8242f84ed17b1. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 4de3a30393489e86e14f68b16c8bbd81b8f1f3da --- go/sdpcache/bolt_cache.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/go/sdpcache/bolt_cache.go b/go/sdpcache/bolt_cache.go index de81b8d6..a024a229 100644 --- a/go/sdpcache/bolt_cache.go +++ b/go/sdpcache/bolt_cache.go @@ -31,6 +31,16 @@ var ( deletedBytesKey = []byte("deletedBytes") ) +// cacheOpenOptions are the bbolt options used for every Open call in this +// package. Since this is a cache layer, crash durability is unnecessary: +// - NoSync skips fdatasync per commit, removing the single-writer bottleneck. +// - NoFreelistSync skips persisting the freelist, reducing write amplification. +var cacheOpenOptions = &bbolt.Options{ + Timeout: 5 * time.Second, + NoSync: true, + NoFreelistSync: true, +} + // DefaultCompactThreshold is the default threshold for triggering compaction (100MB) const DefaultCompactThreshold = 100 * 1024 * 1024 @@ -234,9 +244,7 @@ func NewBoltCache(path string, opts ...BoltCacheOption) (*BoltCache, error) { } // bbolt.Open will open an existing file if present, or create a new one - db, err := bbolt.Open(path, 0o600, &bbolt.Options{ - Timeout: 5 * time.Second, - }) + db, err := bbolt.Open(path, 0o600, cacheOpenOptions) if err != nil { return nil, fmt.Errorf("failed to open bolt database: %w", err) } @@ -457,7 +465,7 @@ func (c *BoltCache) deleteCacheFileLocked(ctx context.Context, span trace.Span) c.resetDeletedBytes() // Reopen the database - db, err := bbolt.Open(c.path, 0o600, &bbolt.Options{Timeout: 5 * time.Second}) + db, err := bbolt.Open(c.path, 0o600, cacheOpenOptions) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, "failed to reopen database") @@ -1341,13 +1349,13 @@ func (c *BoltCache) compact(ctx context.Context) error { } // Open the destination database - dstDB, err := bbolt.Open(tempPath, 0o600, &bbolt.Options{Timeout: 5 * time.Second}) + dstDB, err := bbolt.Open(tempPath, 0o600, cacheOpenOptions) if err != nil { if isDiskFullError(err) { // Attempt cleanup first - use locked version since we already hold the lock c.purgeLocked(ctx, time.Now()) // Try again - dstDB, err = bbolt.Open(tempPath, 0o600, &bbolt.Options{Timeout: 5 * time.Second}) + dstDB, err = bbolt.Open(tempPath, 0o600, cacheOpenOptions) if err != nil { return handleDiskFull(err, "temp database creation") } @@ -1364,7 +1372,7 @@ func (c *BoltCache) compact(ctx context.Context) error { // Attempt cleanup first - use locked version since we already hold the lock c.purgeLocked(ctx, time.Now()) // Try compaction again - dstDB2, retryErr := bbolt.Open(tempPath, 0o600, &bbolt.Options{Timeout: 5 * time.Second}) + dstDB2, retryErr := bbolt.Open(tempPath, 0o600, cacheOpenOptions) if retryErr != nil { return handleDiskFull(retryErr, "temp database creation after cleanup") } @@ -1395,12 +1403,12 @@ func (c *BoltCache) compact(ctx context.Context) error { // Replace the old file with the compacted one if err := os.Rename(tempPath, c.path); err != nil { // Try to reopen the original database - c.db, _ = bbolt.Open(c.path, 0o600, &bbolt.Options{Timeout: 5 * time.Second}) + c.db, _ = bbolt.Open(c.path, 0o600, cacheOpenOptions) return handleDiskFull(err, "rename") } // Reopen the database - db, err := bbolt.Open(c.path, 0o600, &bbolt.Options{Timeout: 5 * time.Second}) + db, err := bbolt.Open(c.path, 0o600, cacheOpenOptions) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, "failed to reopen database") From 274fb064264fe9d9d9d2574d444015423cb9f9a7 Mon Sep 17 00:00:00 2001 From: Lionel Wilson <80872669+Lionel-Wilson@users.noreply.github.com> Date: Wed, 11 Mar 2026 09:12:14 +0000 Subject: [PATCH 10/18] feat: implement ElasticSanPool adapter (#4218) image --- > [!NOTE] > **Medium Risk** > Adds a new Azure discovery adapter and wires it into adapter initialization, introducing new Azure SDK calls and item-linking logic that could affect discovery completeness/performance but not security-critical flows. > > **Overview** > Adds first-class discovery support for Azure Elastic SAN pools. > > Introduces a new `ElasticSanClient` wrapper around the Azure SDK plus a `NewElasticSan` manual adapter that supports `List`, `ListStream`, and `Get`, maps resources into SDP items (tags/health), and emits links to related `ElasticSanVolumeGroup` (SEARCH) and `NetworkPrivateEndpoint` (GET) resources. Wires the adapter into `manual/adapters.go` by initializing `armelasticsan.NewElasticSansClient` and registering the adapter (including the metadata-only nil-client path), and adds unit tests + generated GoMock for the new client. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f25b3ccbcbd2327205c52c84d28c5416570fdfa5. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 9e98c7c8a21cbaaa192c5a6842fa8d1a1016ab68 --- sources/azure/clients/elastic-san-client.go | 35 ++ sources/azure/manual/adapters.go | 10 + sources/azure/manual/elastic-san.go | 217 ++++++++++++ sources/azure/manual/elastic-san_test.go | 322 ++++++++++++++++++ .../shared/mocks/mock_elastic_san_client.go | 72 ++++ 5 files changed, 656 insertions(+) create mode 100644 sources/azure/clients/elastic-san-client.go create mode 100644 sources/azure/manual/elastic-san.go create mode 100644 sources/azure/manual/elastic-san_test.go create mode 100644 sources/azure/shared/mocks/mock_elastic_san_client.go diff --git a/sources/azure/clients/elastic-san-client.go b/sources/azure/clients/elastic-san-client.go new file mode 100644 index 00000000..6e708767 --- /dev/null +++ b/sources/azure/clients/elastic-san-client.go @@ -0,0 +1,35 @@ +package clients + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" +) + +//go:generate mockgen -destination=../shared/mocks/mock_elastic_san_client.go -package=mocks -source=elastic-san-client.go + +// ElasticSanPager is a type alias for the generic Pager interface with Elastic SAN list response type. +type ElasticSanPager = Pager[armelasticsan.ElasticSansClientListByResourceGroupResponse] + +// ElasticSanClient is an interface for interacting with Azure Elastic SAN (pool) resources. +type ElasticSanClient interface { + Get(ctx context.Context, resourceGroupName string, elasticSanName string, options *armelasticsan.ElasticSansClientGetOptions) (armelasticsan.ElasticSansClientGetResponse, error) + NewListByResourceGroupPager(resourceGroupName string, options *armelasticsan.ElasticSansClientListByResourceGroupOptions) ElasticSanPager +} + +type elasticSanClient struct { + client *armelasticsan.ElasticSansClient +} + +func (c *elasticSanClient) Get(ctx context.Context, resourceGroupName string, elasticSanName string, options *armelasticsan.ElasticSansClientGetOptions) (armelasticsan.ElasticSansClientGetResponse, error) { + return c.client.Get(ctx, resourceGroupName, elasticSanName, options) +} + +func (c *elasticSanClient) NewListByResourceGroupPager(resourceGroupName string, options *armelasticsan.ElasticSansClientListByResourceGroupOptions) ElasticSanPager { + return c.client.NewListByResourceGroupPager(resourceGroupName, options) +} + +// NewElasticSanClient creates a new ElasticSanClient from the Azure SDK client. +func NewElasticSanClient(client *armelasticsan.ElasticSansClient) ElasticSanClient { + return &elasticSanClient{client: client} +} diff --git a/sources/azure/manual/adapters.go b/sources/azure/manual/adapters.go index 9cbeead3..c3ded5b8 100644 --- a/sources/azure/manual/adapters.go +++ b/sources/azure/manual/adapters.go @@ -418,6 +418,11 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred return nil, fmt.Errorf("failed to create snapshots client: %w", err) } + elasticSansClient, err := armelasticsan.NewElasticSansClient(subscriptionID, cred, nil) + if err != nil { + return nil, fmt.Errorf("failed to create elastic sans client: %w", err) + } + elasticSanVolumeSnapshotsClient, err := armelasticsan.NewVolumeSnapshotsClient(subscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create elastic san volume snapshots client: %w", err) @@ -711,6 +716,10 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred clients.NewSnapshotsClient(snapshotsClient), resourceGroupScopes, ), cache), + sources.WrapperToAdapter(NewElasticSan( + clients.NewElasticSanClient(elasticSansClient), + resourceGroupScopes, + ), cache), sources.WrapperToAdapter(NewElasticSanVolumeSnapshot( clients.NewElasticSanVolumeSnapshotClient(elasticSanVolumeSnapshotsClient), resourceGroupScopes, @@ -805,6 +814,7 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred sources.WrapperToAdapter(NewComputeGallery(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeGalleryImage(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeSnapshot(nil, placeholderResourceGroupScopes), noOpCache), + sources.WrapperToAdapter(NewElasticSan(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewElasticSanVolumeSnapshot(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeSharedGalleryImage(nil, subscriptionID), noOpCache), sources.WrapperToAdapter(NewNetworkPrivateEndpoint(nil, placeholderResourceGroupScopes), noOpCache), diff --git a/sources/azure/manual/elastic-san.go b/sources/azure/manual/elastic-san.go new file mode 100644 index 00000000..fe498f94 --- /dev/null +++ b/sources/azure/manual/elastic-san.go @@ -0,0 +1,217 @@ +package manual + +import ( + "context" + "errors" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/shared" +) + +type elasticSanWrapper struct { + client clients.ElasticSanClient + + *azureshared.MultiResourceGroupBase +} + +func NewElasticSan(client clients.ElasticSanClient, resourceGroupScopes []azureshared.ResourceGroupScope) sources.ListableWrapper { + return &elasticSanWrapper{ + client: client, + MultiResourceGroupBase: azureshared.NewMultiResourceGroupBase( + resourceGroupScopes, + sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + azureshared.ElasticSan, + ), + } +} + +// ref: https://learn.microsoft.com/en-us/rest/api/elasticsan/elastic-sans/list-by-resource-group +func (e elasticSanWrapper) List(ctx context.Context, scope string) ([]*sdp.Item, *sdp.QueryError) { + rgScope, err := e.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + pager := e.client.NewListByResourceGroupPager(rgScope.ResourceGroup, nil) + + var items []*sdp.Item + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + for _, elasticSan := range page.Value { + if elasticSan.Name == nil { + continue + } + item, sdpErr := e.azureElasticSanToSDPItem(elasticSan, scope) + if sdpErr != nil { + return nil, sdpErr + } + items = append(items, item) + } + } + + return items, nil +} + +func (e elasticSanWrapper) ListStream(ctx context.Context, stream discovery.QueryResultStream, cache sdpcache.Cache, cacheKey sdpcache.CacheKey, scope string) { + rgScope, err := e.ResourceGroupScopeFromScope(scope) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, e.Type())) + return + } + pager := e.client.NewListByResourceGroupPager(rgScope.ResourceGroup, nil) + + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, e.Type())) + return + } + + for _, elasticSan := range page.Value { + if elasticSan.Name == nil { + continue + } + item, sdpErr := e.azureElasticSanToSDPItem(elasticSan, scope) + if sdpErr != nil { + stream.SendError(sdpErr) + continue + } + cache.StoreItem(ctx, item, shared.DefaultCacheDuration, cacheKey) + stream.SendItem(item) + } + } +} + +// ref: https://learn.microsoft.com/en-us/rest/api/elasticsan/elastic-sans/get +func (e elasticSanWrapper) Get(ctx context.Context, scope string, queryParts ...string) (*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 1 { + return nil, azureshared.QueryError(errors.New("queryParts must be at least 1 and be the Elastic SAN name"), scope, e.Type()) + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + return nil, azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, e.Type()) + } + + rgScope, err := e.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + resp, err := e.client.Get(ctx, rgScope.ResourceGroup, elasticSanName, nil) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + return e.azureElasticSanToSDPItem(&resp.ElasticSan, scope) +} + +func (e elasticSanWrapper) azureElasticSanToSDPItem(elasticSan *armelasticsan.ElasticSan, scope string) (*sdp.Item, *sdp.QueryError) { + if elasticSan.Name == nil { + return nil, azureshared.QueryError(errors.New("elasticSan name is nil"), scope, e.Type()) + } + attributes, err := shared.ToAttributesWithExclude(elasticSan, "tags") + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + + item := &sdp.Item{ + Type: azureshared.ElasticSan.String(), + UniqueAttribute: "name", + Attributes: attributes, + Scope: scope, + Tags: azureshared.ConvertAzureTags(elasticSan.Tags), + LinkedItemQueries: []*sdp.LinkedItemQuery{}, + } + + // Link to Private Endpoints via PrivateEndpointConnections + if elasticSan.Properties != nil && elasticSan.Properties.PrivateEndpointConnections != nil { + for _, pec := range elasticSan.Properties.PrivateEndpointConnections { + if pec != nil && pec.Properties != nil && pec.Properties.PrivateEndpoint != nil && pec.Properties.PrivateEndpoint.ID != nil { + peName := azureshared.ExtractResourceName(*pec.Properties.PrivateEndpoint.ID) + if peName != "" { + linkedScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(*pec.Properties.PrivateEndpoint.ID); extractedScope != "" { + linkedScope = extractedScope + } + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkPrivateEndpoint.String(), + Method: sdp.QueryMethod_GET, + Query: peName, + Scope: linkedScope, + }, + }) + } + } + } + } + + // Link to child Volume Groups (SEARCH by parent Elastic SAN name) + if elasticSan.Name != nil && *elasticSan.Name != "" { + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSanVolumeGroup.String(), + Method: sdp.QueryMethod_SEARCH, + Query: *elasticSan.Name, + Scope: scope, + }, + }) + } + + // Health from provisioning state + if elasticSan.Properties != nil && elasticSan.Properties.ProvisioningState != nil { + switch *elasticSan.Properties.ProvisioningState { + case armelasticsan.ProvisioningStatesSucceeded: + item.Health = sdp.Health_HEALTH_OK.Enum() + case armelasticsan.ProvisioningStatesCreating, armelasticsan.ProvisioningStatesUpdating, armelasticsan.ProvisioningStatesDeleting, + armelasticsan.ProvisioningStatesPending, armelasticsan.ProvisioningStatesRestoring: + item.Health = sdp.Health_HEALTH_PENDING.Enum() + case armelasticsan.ProvisioningStatesFailed, armelasticsan.ProvisioningStatesCanceled, + armelasticsan.ProvisioningStatesDeleted, armelasticsan.ProvisioningStatesInvalid: + item.Health = sdp.Health_HEALTH_ERROR.Enum() + default: + item.Health = sdp.Health_HEALTH_UNKNOWN.Enum() + } + } + + return item, nil +} + +func (e elasticSanWrapper) GetLookups() sources.ItemTypeLookups { + return sources.ItemTypeLookups{ + ElasticSanLookupByName, // defined in elastic-san-volume-snapshot.go + } +} + +func (e elasticSanWrapper) PotentialLinks() map[shared.ItemType]bool { + return shared.NewItemTypesSet( + azureshared.ElasticSanVolumeGroup, + azureshared.NetworkPrivateEndpoint, + ) +} + +// ref: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/elastic_san +func (e elasticSanWrapper) TerraformMappings() []*sdp.TerraformMapping { + return []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_GET, + TerraformQueryMap: "azurerm_elastic_san.name", + }, + } +} + +func (e elasticSanWrapper) IAMPermissions() []string { + return []string{ + "Microsoft.ElasticSan/elasticSans/read", + } +} + +func (e elasticSanWrapper) PredefinedRole() string { + return "Reader" +} diff --git a/sources/azure/manual/elastic-san_test.go b/sources/azure/manual/elastic-san_test.go new file mode 100644 index 00000000..670214ec --- /dev/null +++ b/sources/azure/manual/elastic-san_test.go @@ -0,0 +1,322 @@ +package manual_test + +import ( + "context" + "errors" + "sync" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + "go.uber.org/mock/gomock" + + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/manual" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/azure/shared/mocks" + "github.com/overmindtech/cli/sources/shared" +) + +func createAzureElasticSan(name string) *armelasticsan.ElasticSan { + baseSize := int64(1) + extendedSize := int64(2) + provisioningState := armelasticsan.ProvisioningStatesSucceeded + return &armelasticsan.ElasticSan{ + ID: new("/subscriptions/sub/resourceGroups/rg/providers/Microsoft.ElasticSan/elasticSans/" + name), + Name: new(name), + Location: new("eastus"), + Type: new("Microsoft.ElasticSan/elasticSans"), + Tags: map[string]*string{"env": new("test")}, + Properties: &armelasticsan.Properties{ + BaseSizeTiB: &baseSize, + ExtendedCapacitySizeTiB: &extendedSize, + ProvisioningState: &provisioningState, + VolumeGroupCount: new(int64(0)), + }, + } +} + +func createAzureElasticSanWithPrivateEndpoint(name, subscriptionID, resourceGroup string) *armelasticsan.ElasticSan { + es := createAzureElasticSan(name) + es.Properties.PrivateEndpointConnections = []*armelasticsan.PrivateEndpointConnection{ + { + ID: new("/subscriptions/" + subscriptionID + "/resourceGroups/" + resourceGroup + "/providers/Microsoft.ElasticSan/elasticSans/" + name + "/privateEndpointConnections/pec-1"), + Name: new("pec-1"), + Properties: &armelasticsan.PrivateEndpointConnectionProperties{ + PrivateEndpoint: &armelasticsan.PrivateEndpoint{ + ID: new("/subscriptions/" + subscriptionID + "/resourceGroups/" + resourceGroup + "/providers/Microsoft.Network/privateEndpoints/test-pe"), + }, + }, + }, + } + return es +} + +type mockElasticSanPager struct { + pages []armelasticsan.ElasticSansClientListByResourceGroupResponse + index int +} + +func (m *mockElasticSanPager) More() bool { + return m.index < len(m.pages) +} + +func (m *mockElasticSanPager) NextPage(ctx context.Context) (armelasticsan.ElasticSansClientListByResourceGroupResponse, error) { + if m.index >= len(m.pages) { + return armelasticsan.ElasticSansClientListByResourceGroupResponse{}, errors.New("no more pages") + } + page := m.pages[m.index] + m.index++ + return page, nil +} + +func TestElasticSan(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + subscriptionID := "test-subscription" + resourceGroup := "test-rg" + scope := subscriptionID + "." + resourceGroup + + t.Run("Get", func(t *testing.T) { + elasticSanName := "test-elastic-san" + es := createAzureElasticSan(elasticSanName) + + mockClient := mocks.NewMockElasticSanClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, elasticSanName, nil).Return( + armelasticsan.ElasticSansClientGetResponse{ + ElasticSan: *es, + }, nil) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + sdpItem, qErr := adapter.Get(ctx, scope, elasticSanName, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + if sdpItem.GetType() != azureshared.ElasticSan.String() { + t.Errorf("Expected type %s, got %s", azureshared.ElasticSan.String(), sdpItem.GetType()) + } + + if sdpItem.GetUniqueAttribute() != "name" { + t.Errorf("Expected unique attribute 'name', got %s", sdpItem.GetUniqueAttribute()) + } + + if sdpItem.UniqueAttributeValue() != elasticSanName { + t.Errorf("Expected unique attribute value %s, got %s", elasticSanName, sdpItem.UniqueAttributeValue()) + } + + if sdpItem.GetTags()["env"] != "test" { + t.Errorf("Expected tag 'env=test', got: %v", sdpItem.GetTags()["env"]) + } + + t.Run("StaticTests", func(t *testing.T) { + // ElasticSanVolumeGroup SEARCH link (parent→child); no private endpoints in createAzureElasticSan + shared.RunStaticTests(t, adapter, sdpItem, shared.QueryTests{ + { + ExpectedType: azureshared.ElasticSanVolumeGroup.String(), + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: elasticSanName, + ExpectedScope: scope, + }, + }) + }) + }) + + t.Run("GetWithPrivateEndpointLink", func(t *testing.T) { + elasticSanName := "test-elastic-san-pe" + es := createAzureElasticSanWithPrivateEndpoint(elasticSanName, subscriptionID, resourceGroup) + + mockClient := mocks.NewMockElasticSanClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, elasticSanName, nil).Return( + armelasticsan.ElasticSansClientGetResponse{ + ElasticSan: *es, + }, nil) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + sdpItem, qErr := adapter.Get(ctx, scope, elasticSanName, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + queryTests := shared.QueryTests{ + { + ExpectedType: azureshared.ElasticSanVolumeGroup.String(), + ExpectedMethod: sdp.QueryMethod_SEARCH, + ExpectedQuery: elasticSanName, + ExpectedScope: scope, + }, + { + ExpectedType: azureshared.NetworkPrivateEndpoint.String(), + ExpectedMethod: sdp.QueryMethod_GET, + ExpectedQuery: "test-pe", + ExpectedScope: scope, + }, + } + shared.RunStaticTests(t, adapter, sdpItem, queryTests) + }) + + t.Run("List", func(t *testing.T) { + es1 := createAzureElasticSan("es-1") + es2 := createAzureElasticSan("es-2") + + mockClient := mocks.NewMockElasticSanClient(ctrl) + mockPager := &mockElasticSanPager{ + pages: []armelasticsan.ElasticSansClientListByResourceGroupResponse{ + {List: armelasticsan.List{Value: []*armelasticsan.ElasticSan{es1, es2}}}, + }, + } + mockClient.EXPECT().NewListByResourceGroupPager(resourceGroup, nil).Return(mockPager) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + listable, ok := adapter.(discovery.ListableAdapter) + if !ok { + t.Fatalf("Adapter does not support List operation") + } + + sdpItems, err := listable.List(ctx, scope, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if len(sdpItems) != 2 { + t.Fatalf("Expected 2 items, got: %d", len(sdpItems)) + } + + for _, item := range sdpItems { + if item.Validate() != nil { + t.Fatalf("Expected no validation error, got: %v", item.Validate()) + } + } + }) + + t.Run("ListStream", func(t *testing.T) { + es := createAzureElasticSan("es-stream") + + mockClient := mocks.NewMockElasticSanClient(ctrl) + mockPager := &mockElasticSanPager{ + pages: []armelasticsan.ElasticSansClientListByResourceGroupResponse{ + {List: armelasticsan.List{Value: []*armelasticsan.ElasticSan{es}}}, + }, + } + mockClient.EXPECT().NewListByResourceGroupPager(resourceGroup, nil).Return(mockPager) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + wg := &sync.WaitGroup{} + wg.Add(1) + + var items []*sdp.Item + mockItemHandler := func(item *sdp.Item) { + items = append(items, item) + wg.Done() + } + + var errs []error + mockErrorHandler := func(err error) { + errs = append(errs, err) + } + + stream := discovery.NewQueryResultStream(mockItemHandler, mockErrorHandler) + + listStreamable, ok := adapter.(discovery.ListStreamableAdapter) + if !ok { + t.Fatalf("Adapter does not support ListStream operation") + } + + listStreamable.ListStream(ctx, scope, true, stream) + wg.Wait() + + if len(errs) != 0 { + t.Fatalf("Expected no errors, got: %v", errs) + } + + if len(items) != 1 { + t.Fatalf("Expected 1 item, got: %d", len(items)) + } + + if items[0].GetType() != azureshared.ElasticSan.String() { + t.Errorf("Expected type %s, got %s", azureshared.ElasticSan.String(), items[0].GetType()) + } + }) + + t.Run("ListWithNilName", func(t *testing.T) { + es1 := createAzureElasticSan("es-1") + esNilName := &armelasticsan.ElasticSan{ + Name: nil, + Location: new("eastus"), + Tags: map[string]*string{"env": new("test")}, + } + + mockClient := mocks.NewMockElasticSanClient(ctrl) + mockPager := &mockElasticSanPager{ + pages: []armelasticsan.ElasticSansClientListByResourceGroupResponse{ + {List: armelasticsan.List{Value: []*armelasticsan.ElasticSan{es1, esNilName}}}, + }, + } + mockClient.EXPECT().NewListByResourceGroupPager(resourceGroup, nil).Return(mockPager) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + listable, ok := adapter.(discovery.ListableAdapter) + if !ok { + t.Fatalf("Adapter does not support List operation") + } + + sdpItems, err := listable.List(ctx, scope, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if len(sdpItems) != 1 { + t.Fatalf("Expected 1 item (nil name skipped), got: %d", len(sdpItems)) + } + }) + + t.Run("ErrorHandling", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, "nonexistent", nil).Return( + armelasticsan.ElasticSansClientGetResponse{}, errors.New("elastic san not found")) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + _, qErr := adapter.Get(ctx, scope, "nonexistent", true) + if qErr == nil { + t.Error("Expected error when getting non-existent Elastic SAN, but got nil") + } + }) + + t.Run("GetWithEmptyName", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanClient(ctrl) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + _, qErr := adapter.Get(ctx, scope, "", true) + if qErr == nil { + t.Error("Expected error when getting Elastic SAN with empty name, but got nil") + } + }) + + t.Run("GetWithInsufficientQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanClient(ctrl) + + wrapper := manual.NewElasticSan(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + _, qErr := wrapper.Get(ctx, scope) + if qErr == nil { + t.Error("Expected error when getting Elastic SAN with insufficient query parts, but got nil") + } + }) +} diff --git a/sources/azure/shared/mocks/mock_elastic_san_client.go b/sources/azure/shared/mocks/mock_elastic_san_client.go new file mode 100644 index 00000000..516f9fa1 --- /dev/null +++ b/sources/azure/shared/mocks/mock_elastic_san_client.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: elastic-san-client.go +// +// Generated by this command: +// +// mockgen -destination=../shared/mocks/mock_elastic_san_client.go -package=mocks -source=elastic-san-client.go +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + armelasticsan "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + clients "github.com/overmindtech/cli/sources/azure/clients" + gomock "go.uber.org/mock/gomock" +) + +// MockElasticSanClient is a mock of ElasticSanClient interface. +type MockElasticSanClient struct { + ctrl *gomock.Controller + recorder *MockElasticSanClientMockRecorder + isgomock struct{} +} + +// MockElasticSanClientMockRecorder is the mock recorder for MockElasticSanClient. +type MockElasticSanClientMockRecorder struct { + mock *MockElasticSanClient +} + +// NewMockElasticSanClient creates a new mock instance. +func NewMockElasticSanClient(ctrl *gomock.Controller) *MockElasticSanClient { + mock := &MockElasticSanClient{ctrl: ctrl} + mock.recorder = &MockElasticSanClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockElasticSanClient) EXPECT() *MockElasticSanClientMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockElasticSanClient) Get(ctx context.Context, resourceGroupName, elasticSanName string, options *armelasticsan.ElasticSansClientGetOptions) (armelasticsan.ElasticSansClientGetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, elasticSanName, options) + ret0, _ := ret[0].(armelasticsan.ElasticSansClientGetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockElasticSanClientMockRecorder) Get(ctx, resourceGroupName, elasticSanName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockElasticSanClient)(nil).Get), ctx, resourceGroupName, elasticSanName, options) +} + +// NewListByResourceGroupPager mocks base method. +func (m *MockElasticSanClient) NewListByResourceGroupPager(resourceGroupName string, options *armelasticsan.ElasticSansClientListByResourceGroupOptions) clients.ElasticSanPager { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewListByResourceGroupPager", resourceGroupName, options) + ret0, _ := ret[0].(clients.ElasticSanPager) + return ret0 +} + +// NewListByResourceGroupPager indicates an expected call of NewListByResourceGroupPager. +func (mr *MockElasticSanClientMockRecorder) NewListByResourceGroupPager(resourceGroupName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListByResourceGroupPager", reflect.TypeOf((*MockElasticSanClient)(nil).NewListByResourceGroupPager), resourceGroupName, options) +} From 99ce1dd6d986af5ae91a8231c337e1f16ae93835 Mon Sep 17 00:00:00 2001 From: Elliot Waddington Date: Wed, 11 Mar 2026 12:47:53 +0100 Subject: [PATCH 11/18] =?UTF-8?q?ENG-3047=20Phase=201=20=E2=80=94=20UTM=20?= =?UTF-8?q?Attribution=20on=20External=20Links=20(#4214)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Implementation Notes — Deviations from Plan Parts 1, 2b, and 3 were implemented exactly as specified. Part 2a (CLI `terraform_plan.go`) has the following deviations, all driven by UX feedback during implementation: ### CLI Output Formatting Changes * **Change-level link:** Instead of a raw URL, now renders as a clickable OSC 8 hyperlink with text "Open in Overmind ↗" (matching the GitHub PR comment's "Open in Overmind ↗" wording) * **Preamble text:** Changed from "Check the blast radius graph and risks at:" to "View the blast radius graph and risks:" * **Link indentation:** Removed — both per-risk and change-level links have no indentation * **Inter-risk spacing:** Added extra blank line between risk blocks for readability * **Description-to-link spacing:** "View risk ↗" immediately follows the description (no blank line) ### Terminal Compatibility (not in original plan) Added `supportsHyperlinks()` detection to gracefully handle terminals that don't support OSC 8: * **TTY check:** Skips hyperlinks when stdout is not a terminal (piped output, file redirect) * **CI check:** Skips hyperlinks when `$CI` is set * **Env heuristics:** Checks `$TERM_PROGRAM`, `$VTE_VERSION`, `$TERM` (kitty, 256color), and `$TMUX` to detect modern terminals * **Fallback:** Renders raw URLs instead of hyperlinks in unsupported environments * `renderLink()` helper: Wraps the detection logic — returns OSC 8 hyperlink or raw URL ### Additional Tests (plan said no test changes needed) * `TestBuildChangeMarkdownUTMAttribution` — asserts `utm_source=github-comment` on change, signals, and risk URLs in generated PR markdown * `TestEnvSupportsHyperlinks` — 9 test cases covering CI, dumb terminal, screen, tmux, TERM_PROGRAM, VTE_VERSION, kitty, 256color, and no-signal scenarios * `TestRenderLinkFallback` — verifies raw URL fallback when stdout is not a TTY * `TestRenderRiskPreview` — visual inspection test using real lipgloss styles, ommited from CI test runs * `TestTerminalHyperlink` — verifies OSC 8 escape sequence format ### Files Changed * `services/api-server/service/changesservice.go` — UTM on 4 URLs (as planned) * `services/api-server/service/changesservice_test.go` — new UTM assertion test * `services/api-server/service/runtask.go` — UTM on 5 URLs (as planned) * `cli/cmd/terraform_plan.go` — per-risk hyperlinks, terminal detection, UTM params * `cli/cmd/terraform_plan_test.go` — new test file with hyperlink, detection, and visual preview tests * `cli/cmd/changes_submit_plan.go` — UTM on change URL (as planned) > [!NOTE] > **Low Risk** > Low risk: changes are limited to URL formatting/output (UTM query params + clickable terminal links) and add tests; minimal impact beyond link rendering and attribution tracking. > > **Overview** > Adds UTM attribution parameters to Overmind links emitted by the CLI, GitHub comment markdown, and HCP Terraform task outcomes (including per-risk deep links), and includes the CLI version on `utm_source=cli` links. > > Improves `terraform plan` CLI output by rendering OSC 8 clickable hyperlinks when running in a compatible TTY, with environment-based detection and new unit/preview tests to validate link rendering and UTM presence. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 126f33b4e7412264727c493c2541b4246caf9b4a. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: d9143a2ac795069df3872be9b1c7b232644f58f0 --- cmd/changes_submit_plan.go | 3 +- cmd/terraform_plan.go | 60 +++++++++++++- cmd/terraform_plan_test.go | 157 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 cmd/terraform_plan_test.go diff --git a/cmd/changes_submit_plan.go b/cmd/changes_submit_plan.go index d3d8171d..2eff689f 100644 --- a/cmd/changes_submit_plan.go +++ b/cmd/changes_submit_plan.go @@ -14,6 +14,7 @@ import ( "github.com/overmindtech/cli/knowledge" "github.com/overmindtech/cli/tfutils" "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/tracing" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -311,7 +312,7 @@ func SubmitPlan(cmd *cobra.Command, args []string) error { } app, _ = strings.CutSuffix(app, "/") - changeUrl := fmt.Sprintf("%v/changes/%v", app, changeUUID) + changeUrl := fmt.Sprintf("%v/changes/%v?utm_source=cli&cli_version=%v", app, changeUUID, tracing.Version()) log.WithContext(ctx).WithFields(lf).WithField("change-url", changeUrl).Info("Change ready") fmt.Println(changeUrl) diff --git a/cmd/terraform_plan.go b/cmd/terraform_plan.go index 0bf762af..b7c67e7e 100644 --- a/cmd/terraform_plan.go +++ b/cmd/terraform_plan.go @@ -19,6 +19,7 @@ import ( "github.com/overmindtech/cli/knowledge" "github.com/overmindtech/cli/tfutils" "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/tracing" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -445,12 +446,17 @@ retryLoop: Bold(true). Render(r.GetTitle()) - bits = append(bits, (fmt.Sprintf("%v%v\n\n%v\n\n", + bits = append(bits, fmt.Sprintf("%v%v\n\n%v", title, severity, - wordwrap.String(r.GetDescription(), min(160, pterm.GetTerminalWidth()-4))))) + wordwrap.String(r.GetDescription(), min(160, pterm.GetTerminalWidth()-4)))) + + riskUUID, _ := uuid.FromBytes(r.GetUUID()) + riskURL := fmt.Sprintf("%v/blast-radius?selectedRisk=%v&utm_source=cli&cli_version=%v", changeUrl.String(), riskUUID.String(), tracing.Version()) + bits = append(bits, fmt.Sprintf("%v\n\n", osc8Hyperlink(riskURL, "View risk ↗"))) } - bits = append(bits, fmt.Sprintf("\nCheck the blast radius graph and risks at:\n%v\n\n", changeUrl.String())) + changeURLWithUTM := fmt.Sprintf("%v?utm_source=cli&cli_version=%v", changeUrl.String(), tracing.Version()) + bits = append(bits, fmt.Sprintf("\nView the blast radius graph and risks:\n%v\n\n", osc8Hyperlink(changeURLWithUTM, "Open in Overmind ↗"))) } pterm.Fprintln(multi.NewWriter(), strings.Join(bits, "\n")) @@ -458,6 +464,54 @@ retryLoop: return nil } +// supportsOSCHyperlinks checks if the terminal likely supports OSC 8 hyperlinks. +// Combines a TTY check with environment-based heuristics. +func supportsOSCHyperlinks() bool { + if fi, err := os.Stdout.Stat(); err != nil || fi.Mode()&os.ModeCharDevice == 0 { + return false + } + return envSupportsOSCHyperlinks() +} + +// envSupportsOSCHyperlinks checks environment variables to determine if the terminal +// likely supports OSC 8 hyperlinks. Split out from supportsOSCHyperlinks so that tests +// can exercise the env heuristics in isolation — go test pipes stdout, so the +// TTY check in supportsOSCHyperlinks always fails under test. +func envSupportsOSCHyperlinks() bool { + if os.Getenv("CI") != "" { + return false + } + if term := os.Getenv("TERM"); term == "dumb" { + return false + } + if strings.HasPrefix(os.Getenv("TERM"), "screen") && os.Getenv("TMUX") == "" { + return false + } + if os.Getenv("TERM_PROGRAM") != "" { + return true + } + if os.Getenv("VTE_VERSION") != "" { + return true + } + if os.Getenv("TERM") == "xterm-kitty" { + return true + } + if strings.Contains(os.Getenv("TERM"), "256color") { + return true + } + return false +} + +// osc8Hyperlink returns an OSC 8 hyperlink if the terminal supports it, otherwise +// the raw URL. Supported by iTerm2, GNOME Terminal, Windows Terminal, WezTerm, +// kitty, Alacritty; degrades gracefully in unsupported terminals. +func osc8Hyperlink(url, text string) string { + if supportsOSCHyperlinks() { + return fmt.Sprintf("\033]8;;%s\033\\%s\033]8;;\033\\", url, text) + } + return url +} + // getTicketLinkFromPlan reads the plan file to create a unique hash to identify this change func getTicketLinkFromPlan(planFile string) (string, error) { plan, err := os.ReadFile(planFile) //nolint:gosec // G703: planFile is from the local user's CLI args; reading their chosen file is the intended behavior of this CLI tool diff --git a/cmd/terraform_plan_test.go b/cmd/terraform_plan_test.go new file mode 100644 index 00000000..9f330321 --- /dev/null +++ b/cmd/terraform_plan_test.go @@ -0,0 +1,157 @@ +package cmd + +import ( + "fmt" + "os" + "strings" + "testing" + + lipgloss "charm.land/lipgloss/v2" + "github.com/muesli/reflow/wordwrap" +) + +func TestOSC8Hyperlink(t *testing.T) { + t.Parallel() + + url := "https://app.overmind.tech/changes/abc/blast-radius?selectedRisk=xyz&utm_source=cli&cli_version=0.42.0" + text := "View risk ↗" + + // In tests, stdout is not a TTY, so supportsOSCHyperlinks() returns false + // and osc8Hyperlink falls back to the raw URL. + result := osc8Hyperlink(url, text) + if result != url { + t.Errorf("osc8Hyperlink() = %q, want raw URL %q when stdout is not a TTY", result, url) + } +} + +func TestEnvSupportsOSC8(t *testing.T) { + tests := []struct { + name string + env map[string]string + want bool + }{ + {"CI disables", map[string]string{"CI": "true"}, false}, + {"dumb terminal", map[string]string{"TERM": "dumb"}, false}, + {"screen without tmux", map[string]string{"TERM": "screen"}, false}, + {"screen with tmux and 256color", map[string]string{"TERM": "screen-256color", "TMUX": "/tmp/tmux-1000/default,12345,0"}, true}, + {"TERM_PROGRAM set", map[string]string{"TERM_PROGRAM": "iTerm.app"}, true}, + {"VTE_VERSION set", map[string]string{"VTE_VERSION": "6800"}, true}, + {"xterm-kitty", map[string]string{"TERM": "xterm-kitty"}, true}, + {"256color", map[string]string{"TERM": "xterm-256color"}, true}, + {"no signals", map[string]string{}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("CI", "") + t.Setenv("TERM", "") + t.Setenv("TMUX", "") + t.Setenv("TERM_PROGRAM", "") + t.Setenv("VTE_VERSION", "") + for k, v := range tt.env { + t.Setenv(k, v) + } + if got := envSupportsOSCHyperlinks(); got != tt.want { + t.Errorf("envSupportsOSCHyperlinks() = %v, want %v", got, tt.want) + } + }) + } +} + +// TestRenderRiskPreview prints an exact replica of the CLI risk output using +// the real lipgloss styles and theme. Run from an interactive terminal with: +// +// go test ./cli/cmd/ -run TestRenderRiskPreview -v +// +// This is a visual inspection test, not an assertion-based test. It formats the +// OSC 8 escape directly because go test pipes stdout through the test runner, +// which fails the TTY check in supportsOSCHyperlinks. The real CLI runs in the user's +// terminal where the TTY check passes naturally. +func TestRenderRiskPreview(t *testing.T) { + if os.Getenv("CI") == "true" { + t.Skip("visual inspection test — skipped in CI") + } + InitPalette() + + changeURL := "https://app.overmind.tech/changes/d7f79e24-d123-40f2-9f5d-7296cff5fc7b" + cliVersion := "0.42.0" + + type fakeRisk struct { + title string + description string + severity string + riskUUID string + } + + risks := []fakeRisk{ + { + title: "Security group opens port 22 to 0.0.0.0/0", + description: "Opening SSH to all IPs exposes the instance to brute-force attacks and unauthorized access. The security group sg-0abc123 allows inbound TCP/22 from 0.0.0.0/0, making it reachable from any IP on the internet.", + severity: "high", + riskUUID: "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + }, + { + title: "Load balancer target group has no health check", + description: "Without health checks, traffic may be routed to unhealthy instances causing user-facing errors. Target group arn:aws:elasticloadbalancing:us-east-1:123456:tg/my-tg has no health check configured.", + severity: "medium", + riskUUID: "b2c3d4e5-f6a7-8901-bcde-f12345678901", + }, + { + title: "Route table change may affect private subnet connectivity", + description: "Modifying route table rtb-0def456 could disrupt connectivity for instances in subnet-789ghi that rely on the NAT gateway for outbound traffic.", + severity: "low", + riskUUID: "c3d4e5f6-a7b8-9012-cdef-123456789012", + }, + } + + osc8 := func(url, text string) string { + return fmt.Sprintf("\033]8;;%s\033\\%s\033]8;;\033\\", url, text) + } + + bits := []string{"", ""} + bits = append(bits, styleH1().Render("Potential Risks")) + bits = append(bits, "") + + for _, r := range risks { + var severity string + switch r.severity { + case "high": + severity = lipgloss.NewStyle(). + Background(ColorPalette.BgDanger). + Foreground(ColorPalette.LabelTitle). + Padding(0, 1). + Bold(true). + Render("High ‼") + case "medium": + severity = lipgloss.NewStyle(). + Background(ColorPalette.BgWarning). + Foreground(ColorPalette.LabelTitle). + Padding(0, 1). + Render("Medium !") + case "low": + severity = lipgloss.NewStyle(). + Background(ColorPalette.LabelBase). + Foreground(ColorPalette.LabelTitle). + Padding(0, 1). + Render("Low ⓘ ") + } + + title := lipgloss.NewStyle(). + Foreground(ColorPalette.BgMain). + PaddingRight(1). + Bold(true). + Render(r.title) + + bits = append(bits, fmt.Sprintf("%v%v\n\n%v", + title, + severity, + wordwrap.String(r.description, 160))) + + riskURL := fmt.Sprintf("%v/blast-radius?selectedRisk=%v&utm_source=cli&cli_version=%v", changeURL, r.riskUUID, cliVersion) + bits = append(bits, fmt.Sprintf("%v\n\n", osc8(riskURL, "View risk ↗"))) + } + + changeURLWithUTM := fmt.Sprintf("%v?utm_source=cli&cli_version=%v", changeURL, cliVersion) + bits = append(bits, fmt.Sprintf("\nView the blast radius graph and risks:\n%v\n\n", osc8(changeURLWithUTM, "Open in Overmind ↗"))) + + fmt.Println(strings.Join(bits, "\n")) +} From 0960861bcb2365e7a763c20d91263c31f8784a08 Mon Sep 17 00:00:00 2001 From: Lionel Wilson <80872669+Lionel-Wilson@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:18:58 +0000 Subject: [PATCH 12/18] Eng 3006 create an adapter for elasticsanvolumegroup (#4219) image --- > [!NOTE] > **Medium Risk** > Mostly additive discovery logic, but it changes adapter initialization and resource-ID parsing; `shared/utils.go` modifications appear to have missing map-entry commas which could break builds and should be verified. > > **Overview** > Adds new Azure discovery adapters for **Elastic SAN** and **Elastic SAN Volume Groups**, including SDK client wrappers/interfaces, adapter registration in `manual/adapters.go`, and comprehensive unit tests plus generated GoMock clients. > > The new Volume Group adapter supports `Get`/`Search`/streaming and emits rich linked-item queries (Elastic SAN parent, volumes/snapshots children, private endpoints, subnets, Key Vault, UAI, DNS) and health mapping from provisioning state; `shared/utils.go` is extended to parse volume-group resource IDs. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4b82060b80817f7cfe6ae129887851de76b61afd. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 13b4a371e9a7b1a4a5cb574dc420a5b2d2040d46 --- .../elastic-san-volume-group-client.go | 35 ++ sources/azure/manual/adapters.go | 10 + .../azure/manual/elastic-san-volume-group.go | 366 ++++++++++++++++++ .../manual/elastic-san-volume-group_test.go | 222 +++++++++++ .../mock_elastic_san_volume_group_client.go | 72 ++++ sources/azure/shared/utils.go | 1 + 6 files changed, 706 insertions(+) create mode 100644 sources/azure/clients/elastic-san-volume-group-client.go create mode 100644 sources/azure/manual/elastic-san-volume-group.go create mode 100644 sources/azure/manual/elastic-san-volume-group_test.go create mode 100644 sources/azure/shared/mocks/mock_elastic_san_volume_group_client.go diff --git a/sources/azure/clients/elastic-san-volume-group-client.go b/sources/azure/clients/elastic-san-volume-group-client.go new file mode 100644 index 00000000..24164f5a --- /dev/null +++ b/sources/azure/clients/elastic-san-volume-group-client.go @@ -0,0 +1,35 @@ +package clients + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" +) + +//go:generate mockgen -destination=../shared/mocks/mock_elastic_san_volume_group_client.go -package=mocks -source=elastic-san-volume-group-client.go + +// ElasticSanVolumeGroupPager is a type alias for the generic Pager interface with volume group list response type. +type ElasticSanVolumeGroupPager = Pager[armelasticsan.VolumeGroupsClientListByElasticSanResponse] + +// ElasticSanVolumeGroupClient is an interface for interacting with Azure Elastic SAN volume groups. +type ElasticSanVolumeGroupClient interface { + Get(ctx context.Context, resourceGroupName string, elasticSanName string, volumeGroupName string, options *armelasticsan.VolumeGroupsClientGetOptions) (armelasticsan.VolumeGroupsClientGetResponse, error) + NewListByElasticSanPager(resourceGroupName string, elasticSanName string, options *armelasticsan.VolumeGroupsClientListByElasticSanOptions) ElasticSanVolumeGroupPager +} + +type elasticSanVolumeGroupClient struct { + client *armelasticsan.VolumeGroupsClient +} + +func (c *elasticSanVolumeGroupClient) Get(ctx context.Context, resourceGroupName string, elasticSanName string, volumeGroupName string, options *armelasticsan.VolumeGroupsClientGetOptions) (armelasticsan.VolumeGroupsClientGetResponse, error) { + return c.client.Get(ctx, resourceGroupName, elasticSanName, volumeGroupName, options) +} + +func (c *elasticSanVolumeGroupClient) NewListByElasticSanPager(resourceGroupName string, elasticSanName string, options *armelasticsan.VolumeGroupsClientListByElasticSanOptions) ElasticSanVolumeGroupPager { + return c.client.NewListByElasticSanPager(resourceGroupName, elasticSanName, options) +} + +// NewElasticSanVolumeGroupClient creates a new ElasticSanVolumeGroupClient from the Azure SDK client. +func NewElasticSanVolumeGroupClient(client *armelasticsan.VolumeGroupsClient) ElasticSanVolumeGroupClient { + return &elasticSanVolumeGroupClient{client: client} +} diff --git a/sources/azure/manual/adapters.go b/sources/azure/manual/adapters.go index c3ded5b8..5f164a81 100644 --- a/sources/azure/manual/adapters.go +++ b/sources/azure/manual/adapters.go @@ -428,6 +428,11 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred return nil, fmt.Errorf("failed to create elastic san volume snapshots client: %w", err) } + elasticSanVolumeGroupsClient, err := armelasticsan.NewVolumeGroupsClient(subscriptionID, cred, nil) + if err != nil { + return nil, fmt.Errorf("failed to create elastic san volume groups client: %w", err) + } + sharedGalleryImagesClient, err := armcompute.NewSharedGalleryImagesClient(subscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create shared gallery images client: %w", err) @@ -724,6 +729,10 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred clients.NewElasticSanVolumeSnapshotClient(elasticSanVolumeSnapshotsClient), resourceGroupScopes, ), cache), + sources.WrapperToAdapter(NewElasticSanVolumeGroup( + clients.NewElasticSanVolumeGroupClient(elasticSanVolumeGroupsClient), + resourceGroupScopes, + ), cache), ) } @@ -816,6 +825,7 @@ func Adapters(ctx context.Context, subscriptionID string, regions []string, cred sources.WrapperToAdapter(NewComputeSnapshot(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewElasticSan(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewElasticSanVolumeSnapshot(nil, placeholderResourceGroupScopes), noOpCache), + sources.WrapperToAdapter(NewElasticSanVolumeGroup(nil, placeholderResourceGroupScopes), noOpCache), sources.WrapperToAdapter(NewComputeSharedGalleryImage(nil, subscriptionID), noOpCache), sources.WrapperToAdapter(NewNetworkPrivateEndpoint(nil, placeholderResourceGroupScopes), noOpCache), ) diff --git a/sources/azure/manual/elastic-san-volume-group.go b/sources/azure/manual/elastic-san-volume-group.go new file mode 100644 index 00000000..16dde194 --- /dev/null +++ b/sources/azure/manual/elastic-san-volume-group.go @@ -0,0 +1,366 @@ +package manual + +import ( + "context" + "errors" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/clients" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/shared" + "github.com/overmindtech/cli/sources/stdlib" +) + +type elasticSanVolumeGroupWrapper struct { + client clients.ElasticSanVolumeGroupClient + *azureshared.MultiResourceGroupBase +} + +func NewElasticSanVolumeGroup(client clients.ElasticSanVolumeGroupClient, resourceGroupScopes []azureshared.ResourceGroupScope) sources.SearchableWrapper { + return &elasticSanVolumeGroupWrapper{ + client: client, + MultiResourceGroupBase: azureshared.NewMultiResourceGroupBase( + resourceGroupScopes, + sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE, + azureshared.ElasticSanVolumeGroup, + ), + } +} + +func (e elasticSanVolumeGroupWrapper) Get(ctx context.Context, scope string, queryParts ...string) (*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 2 { + return nil, azureshared.QueryError(errors.New("Get requires 2 query parts: elasticSanName and volumeGroupName"), scope, e.Type()) + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + return nil, azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, e.Type()) + } + volumeGroupName := queryParts[1] + if volumeGroupName == "" { + return nil, azureshared.QueryError(errors.New("volumeGroupName cannot be empty"), scope, e.Type()) + } + + rgScope, err := e.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + resp, err := e.client.Get(ctx, rgScope.ResourceGroup, elasticSanName, volumeGroupName, nil) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + return e.azureVolumeGroupToSDPItem(&resp.VolumeGroup, elasticSanName, volumeGroupName, scope) +} + +func (e elasticSanVolumeGroupWrapper) GetLookups() sources.ItemTypeLookups { + return sources.ItemTypeLookups{ + ElasticSanLookupByName, + ElasticSanVolumeGroupLookupByName, + } +} + +func (e elasticSanVolumeGroupWrapper) Search(ctx context.Context, scope string, queryParts ...string) ([]*sdp.Item, *sdp.QueryError) { + if len(queryParts) < 1 { + return nil, azureshared.QueryError(errors.New("Search requires 1 query part: elasticSanName"), scope, e.Type()) + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + return nil, azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, e.Type()) + } + + rgScope, err := e.ResourceGroupScopeFromScope(scope) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + pager := e.client.NewListByElasticSanPager(rgScope.ResourceGroup, elasticSanName, nil) + + var items []*sdp.Item + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + for _, vg := range page.Value { + if vg.Name == nil { + continue + } + item, sdpErr := e.azureVolumeGroupToSDPItem(vg, elasticSanName, *vg.Name, scope) + if sdpErr != nil { + return nil, sdpErr + } + items = append(items, item) + } + } + return items, nil +} + +func (e elasticSanVolumeGroupWrapper) SearchStream(ctx context.Context, stream discovery.QueryResultStream, cache sdpcache.Cache, cacheKey sdpcache.CacheKey, scope string, queryParts ...string) { + if len(queryParts) < 1 { + stream.SendError(azureshared.QueryError(errors.New("Search requires 1 query part: elasticSanName"), scope, e.Type())) + return + } + elasticSanName := queryParts[0] + if elasticSanName == "" { + stream.SendError(azureshared.QueryError(errors.New("elasticSanName cannot be empty"), scope, e.Type())) + return + } + + rgScope, err := e.ResourceGroupScopeFromScope(scope) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, e.Type())) + return + } + pager := e.client.NewListByElasticSanPager(rgScope.ResourceGroup, elasticSanName, nil) + + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + stream.SendError(azureshared.QueryError(err, scope, e.Type())) + return + } + for _, vg := range page.Value { + if vg.Name == nil { + continue + } + item, sdpErr := e.azureVolumeGroupToSDPItem(vg, elasticSanName, *vg.Name, scope) + if sdpErr != nil { + stream.SendError(sdpErr) + continue + } + cache.StoreItem(ctx, item, shared.DefaultCacheDuration, cacheKey) + stream.SendItem(item) + } + } +} + +func (e elasticSanVolumeGroupWrapper) SearchLookups() []sources.ItemTypeLookups { + return []sources.ItemTypeLookups{ + {ElasticSanLookupByName}, + } +} + +func (e elasticSanVolumeGroupWrapper) azureVolumeGroupToSDPItem(vg *armelasticsan.VolumeGroup, elasticSanName, volumeGroupName, scope string) (*sdp.Item, *sdp.QueryError) { + if vg.Name == nil { + return nil, azureshared.QueryError(errors.New("volume group name is nil"), scope, e.Type()) + } + attributes, err := shared.ToAttributesWithExclude(vg, "tags") + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + err = attributes.Set("uniqueAttr", shared.CompositeLookupKey(elasticSanName, volumeGroupName)) + if err != nil { + return nil, azureshared.QueryError(err, scope, e.Type()) + } + + item := &sdp.Item{ + Type: azureshared.ElasticSanVolumeGroup.String(), + UniqueAttribute: "uniqueAttr", + Attributes: attributes, + Scope: scope, + LinkedItemQueries: []*sdp.LinkedItemQuery{}, + } + + // Link to parent Elastic SAN + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSan.String(), + Method: sdp.QueryMethod_GET, + Query: elasticSanName, + Scope: scope, + }, + }) + + // Link to User Assigned Identities from top-level Identity (map keys are ARM resource IDs) + if vg.Identity != nil && vg.Identity.UserAssignedIdentities != nil { + for identityResourceID := range vg.Identity.UserAssignedIdentities { + if identityResourceID == "" { + continue + } + identityName := azureshared.ExtractResourceName(identityResourceID) + if identityName != "" { + linkedScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(identityResourceID); extractedScope != "" { + linkedScope = extractedScope + } + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ManagedIdentityUserAssignedIdentity.String(), + Method: sdp.QueryMethod_GET, + Query: identityName, + Scope: linkedScope, + }, + }) + } + } + } + + // Link to Private Endpoints via PrivateEndpointConnections + if vg.Properties != nil && vg.Properties.PrivateEndpointConnections != nil { + for _, pec := range vg.Properties.PrivateEndpointConnections { + if pec != nil && pec.Properties != nil && pec.Properties.PrivateEndpoint != nil && pec.Properties.PrivateEndpoint.ID != nil { + peName := azureshared.ExtractResourceName(*pec.Properties.PrivateEndpoint.ID) + if peName != "" { + linkedScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(*pec.Properties.PrivateEndpoint.ID); extractedScope != "" { + linkedScope = extractedScope + } + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkPrivateEndpoint.String(), + Method: sdp.QueryMethod_GET, + Query: peName, + Scope: linkedScope, + }, + }) + } + } + } + } + + // Link to child Volume Snapshots (SEARCH by parent Elastic SAN + Volume Group) + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSanVolumeSnapshot.String(), + Method: sdp.QueryMethod_SEARCH, + Query: shared.CompositeLookupKey(elasticSanName, volumeGroupName), + Scope: scope, + }, + }) + + // Link to child Volumes (SEARCH by parent Elastic SAN + Volume Group) + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ElasticSanVolume.String(), + Method: sdp.QueryMethod_SEARCH, + Query: shared.CompositeLookupKey(elasticSanName, volumeGroupName), + Scope: scope, + }, + }) + + // Link to subnets from NetworkACLs virtual network rules + if vg.Properties != nil && vg.Properties.NetworkACLs != nil && vg.Properties.NetworkACLs.VirtualNetworkRules != nil { + for _, rule := range vg.Properties.NetworkACLs.VirtualNetworkRules { + if rule != nil && rule.VirtualNetworkResourceID != nil && *rule.VirtualNetworkResourceID != "" { + subnetID := *rule.VirtualNetworkResourceID + params := azureshared.ExtractPathParamsFromResourceID(subnetID, []string{"virtualNetworks", "subnets"}) + if len(params) >= 2 && params[0] != "" && params[1] != "" { + linkedScope := azureshared.ExtractScopeFromResourceID(subnetID) + if linkedScope == "" { + linkedScope = scope + } + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.NetworkSubnet.String(), + Method: sdp.QueryMethod_GET, + Query: shared.CompositeLookupKey(params[0], params[1]), + Scope: linkedScope, + }, + }) + } + } + } + } + + // Link to Key Vault and encryption identity from EncryptionProperties + if vg.Properties != nil && vg.Properties.EncryptionProperties != nil { + enc := vg.Properties.EncryptionProperties + // Link to User Assigned Identity used for encryption (same pattern as storage-account.go) + if enc.EncryptionIdentity != nil && enc.EncryptionIdentity.EncryptionUserAssignedIdentity != nil { + identityResourceID := *enc.EncryptionIdentity.EncryptionUserAssignedIdentity + identityName := azureshared.ExtractResourceName(identityResourceID) + if identityName != "" { + linkedScope := scope + if extractedScope := azureshared.ExtractScopeFromResourceID(identityResourceID); extractedScope != "" { + linkedScope = extractedScope + } + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.ManagedIdentityUserAssignedIdentity.String(), + Method: sdp.QueryMethod_GET, + Query: identityName, + Scope: linkedScope, + }, + }) + } + } + // Link to Key Vault and DNS from KeyVaultURI (DNS-resolvable hostname) + if enc.KeyVaultProperties != nil && enc.KeyVaultProperties.KeyVaultURI != nil && *enc.KeyVaultProperties.KeyVaultURI != "" { + keyVaultURI := *enc.KeyVaultProperties.KeyVaultURI + vaultName := azureshared.ExtractVaultNameFromURI(keyVaultURI) + if vaultName != "" { + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: azureshared.KeyVaultVault.String(), + Method: sdp.QueryMethod_GET, + Query: vaultName, + Scope: scope, // Key Vault URI does not contain resource group + }, + }) + } + if dnsName := azureshared.ExtractDNSFromURL(keyVaultURI); dnsName != "" { + item.LinkedItemQueries = append(item.LinkedItemQueries, &sdp.LinkedItemQuery{ + Query: &sdp.Query{ + Type: stdlib.NetworkDNS.String(), + Method: sdp.QueryMethod_SEARCH, + Query: dnsName, + Scope: "global", + }, + }) + } + } + } + + // Health from provisioning state + if vg.Properties != nil && vg.Properties.ProvisioningState != nil { + switch *vg.Properties.ProvisioningState { + case armelasticsan.ProvisioningStatesSucceeded: + item.Health = sdp.Health_HEALTH_OK.Enum() + case armelasticsan.ProvisioningStatesCreating, armelasticsan.ProvisioningStatesUpdating, armelasticsan.ProvisioningStatesDeleting, + armelasticsan.ProvisioningStatesPending, armelasticsan.ProvisioningStatesRestoring: + item.Health = sdp.Health_HEALTH_PENDING.Enum() + case armelasticsan.ProvisioningStatesFailed, armelasticsan.ProvisioningStatesCanceled, + armelasticsan.ProvisioningStatesDeleted, armelasticsan.ProvisioningStatesInvalid: + item.Health = sdp.Health_HEALTH_ERROR.Enum() + default: + item.Health = sdp.Health_HEALTH_UNKNOWN.Enum() + } + } + + return item, nil +} + +func (e elasticSanVolumeGroupWrapper) PotentialLinks() map[shared.ItemType]bool { + return map[shared.ItemType]bool{ + azureshared.ElasticSan: true, + azureshared.ElasticSanVolume: true, + azureshared.ElasticSanVolumeSnapshot: true, + azureshared.NetworkPrivateEndpoint: true, + azureshared.NetworkSubnet: true, + azureshared.KeyVaultVault: true, + azureshared.ManagedIdentityUserAssignedIdentity: true, + stdlib.NetworkDNS: true, + } +} + +// ref: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/elastic_san_volume_group +func (e elasticSanVolumeGroupWrapper) TerraformMappings() []*sdp.TerraformMapping { + return []*sdp.TerraformMapping{ + { + TerraformMethod: sdp.QueryMethod_GET, + TerraformQueryMap: "azurerm_elastic_san_volume_group.id", + }, + } +} + +func (e elasticSanVolumeGroupWrapper) IAMPermissions() []string { + return []string{ + "Microsoft.ElasticSan/elasticSans/volumegroups/read", + } +} + +func (e elasticSanVolumeGroupWrapper) PredefinedRole() string { + return "Reader" +} diff --git a/sources/azure/manual/elastic-san-volume-group_test.go b/sources/azure/manual/elastic-san-volume-group_test.go new file mode 100644 index 00000000..baa27c54 --- /dev/null +++ b/sources/azure/manual/elastic-san-volume-group_test.go @@ -0,0 +1,222 @@ +package manual_test + +import ( + "context" + "errors" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + "go.uber.org/mock/gomock" + + "github.com/overmindtech/cli/go/discovery" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdpcache" + "github.com/overmindtech/cli/sources" + "github.com/overmindtech/cli/sources/azure/manual" + azureshared "github.com/overmindtech/cli/sources/azure/shared" + "github.com/overmindtech/cli/sources/azure/shared/mocks" + "github.com/overmindtech/cli/sources/shared" +) + +// mockElasticSanVolumeGroupPager is a simple mock implementation of ElasticSanVolumeGroupPager +type mockElasticSanVolumeGroupPager struct { + pages []armelasticsan.VolumeGroupsClientListByElasticSanResponse + index int +} + +func (m *mockElasticSanVolumeGroupPager) More() bool { + return m.index < len(m.pages) +} + +func (m *mockElasticSanVolumeGroupPager) NextPage(ctx context.Context) (armelasticsan.VolumeGroupsClientListByElasticSanResponse, error) { + if m.index >= len(m.pages) { + return armelasticsan.VolumeGroupsClientListByElasticSanResponse{}, errors.New("no more pages") + } + page := m.pages[m.index] + m.index++ + return page, nil +} + +func createAzureElasticSanVolumeGroup(name string) *armelasticsan.VolumeGroup { + provisioningState := armelasticsan.ProvisioningStatesSucceeded + return &armelasticsan.VolumeGroup{ + ID: new("/subscriptions/sub/resourceGroups/rg/providers/Microsoft.ElasticSan/elasticSans/es/volumegroups/" + name), + Name: new(name), + Type: new("Microsoft.ElasticSan/elasticSans/volumegroups"), + Properties: &armelasticsan.VolumeGroupProperties{ + ProvisioningState: &provisioningState, + }, + } +} + +func TestElasticSanVolumeGroup(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + subscriptionID := "test-subscription" + resourceGroup := "test-rg" + elasticSanName := "test-elastic-san" + volumeGroupName := "test-volume-group" + + t.Run("Get", func(t *testing.T) { + vg := createAzureElasticSanVolumeGroup(volumeGroupName) + + mockClient := mocks.NewMockElasticSanVolumeGroupClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, elasticSanName, volumeGroupName, nil).Return( + armelasticsan.VolumeGroupsClientGetResponse{ + VolumeGroup: *vg, + }, nil) + + wrapper := manual.NewElasticSanVolumeGroup(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(elasticSanName, volumeGroupName) + sdpItem, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr != nil { + t.Fatalf("Expected no error, got: %v", qErr) + } + + if sdpItem.GetType() != azureshared.ElasticSanVolumeGroup.String() { + t.Errorf("Expected type %s, got %s", azureshared.ElasticSanVolumeGroup.String(), sdpItem.GetType()) + } + + if sdpItem.GetUniqueAttribute() != "uniqueAttr" { + t.Errorf("Expected unique attribute 'uniqueAttr', got %s", sdpItem.GetUniqueAttribute()) + } + + expectedUnique := shared.CompositeLookupKey(elasticSanName, volumeGroupName) + if sdpItem.UniqueAttributeValue() != expectedUnique { + t.Errorf("Expected unique attribute value %s, got %s", expectedUnique, sdpItem.UniqueAttributeValue()) + } + + if sdpItem.GetScope() != subscriptionID+"."+resourceGroup { + t.Errorf("Expected scope %s, got %s", subscriptionID+"."+resourceGroup, sdpItem.GetScope()) + } + + if err := sdpItem.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + + t.Run("StaticTests", func(t *testing.T) { + scope := subscriptionID + "." + resourceGroup + queryTests := shared.QueryTests{ + {ExpectedType: azureshared.ElasticSan.String(), ExpectedMethod: sdp.QueryMethod_GET, ExpectedQuery: elasticSanName, ExpectedScope: scope}, + {ExpectedType: azureshared.ElasticSanVolumeSnapshot.String(), ExpectedMethod: sdp.QueryMethod_SEARCH, ExpectedQuery: shared.CompositeLookupKey(elasticSanName, volumeGroupName), ExpectedScope: scope}, + {ExpectedType: azureshared.ElasticSanVolume.String(), ExpectedMethod: sdp.QueryMethod_SEARCH, ExpectedQuery: shared.CompositeLookupKey(elasticSanName, volumeGroupName), ExpectedScope: scope}, + } + shared.RunStaticTests(t, adapter, sdpItem, queryTests) + }) + }) + + t.Run("GetWithInsufficientQueryParts", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanVolumeGroupClient(ctrl) + wrapper := manual.NewElasticSanVolumeGroup(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], elasticSanName, true) + if qErr == nil { + t.Error("Expected error when providing insufficient query parts, but got nil") + } + }) + + t.Run("GetWithEmptyName", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanVolumeGroupClient(ctrl) + wrapper := manual.NewElasticSanVolumeGroup(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(elasticSanName, "") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when volume group name is empty, but got nil") + } + }) + + t.Run("ErrorHandling", func(t *testing.T) { + mockClient := mocks.NewMockElasticSanVolumeGroupClient(ctrl) + mockClient.EXPECT().Get(ctx, resourceGroup, elasticSanName, "nonexistent", nil).Return( + armelasticsan.VolumeGroupsClientGetResponse{}, errors.New("volume group not found")) + + wrapper := manual.NewElasticSanVolumeGroup(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + query := shared.CompositeLookupKey(elasticSanName, "nonexistent") + _, qErr := adapter.Get(ctx, wrapper.Scopes()[0], query, true) + if qErr == nil { + t.Error("Expected error when resource not found, but got nil") + } + }) + + t.Run("Search", func(t *testing.T) { + vg1 := createAzureElasticSanVolumeGroup("vg-1") + vg2 := createAzureElasticSanVolumeGroup("vg-2") + + mockClient := mocks.NewMockElasticSanVolumeGroupClient(ctrl) + mockPager := &mockElasticSanVolumeGroupPager{ + pages: []armelasticsan.VolumeGroupsClientListByElasticSanResponse{ + { + VolumeGroupList: armelasticsan.VolumeGroupList{ + Value: []*armelasticsan.VolumeGroup{vg1, vg2}, + }, + }, + }, + } + mockClient.EXPECT().NewListByElasticSanPager(resourceGroup, elasticSanName, nil).Return(mockPager) + + wrapper := manual.NewElasticSanVolumeGroup(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + searchable, ok := adapter.(discovery.SearchableAdapter) + if !ok { + t.Fatalf("Adapter does not support Search operation") + } + + query := elasticSanName + items, err := searchable.Search(ctx, wrapper.Scopes()[0], query, true) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + if len(items) != 2 { + t.Fatalf("Expected 2 items, got %d", len(items)) + } + for _, item := range items { + if err := item.Validate(); err != nil { + t.Fatalf("Expected no validation error, got: %v", err) + } + } + }) + + t.Run("SearchStream", func(t *testing.T) { + vg := createAzureElasticSanVolumeGroup("stream-vg") + mockClient := mocks.NewMockElasticSanVolumeGroupClient(ctrl) + mockPager := &mockElasticSanVolumeGroupPager{ + pages: []armelasticsan.VolumeGroupsClientListByElasticSanResponse{ + { + VolumeGroupList: armelasticsan.VolumeGroupList{ + Value: []*armelasticsan.VolumeGroup{vg}, + }, + }, + }, + } + mockClient.EXPECT().NewListByElasticSanPager(resourceGroup, elasticSanName, nil).Return(mockPager) + + wrapper := manual.NewElasticSanVolumeGroup(mockClient, []azureshared.ResourceGroupScope{azureshared.NewResourceGroupScope(subscriptionID, resourceGroup)}) + adapter := sources.WrapperToAdapter(wrapper, sdpcache.NewNoOpCache()) + + streamable, ok := adapter.(discovery.SearchStreamableAdapter) + if !ok { + t.Fatalf("Adapter does not support SearchStream operation") + } + + query := elasticSanName + stream := discovery.NewRecordingQueryResultStream() + streamable.SearchStream(ctx, wrapper.Scopes()[0], query, true, stream) + items := stream.GetItems() + if len(items) != 1 { + t.Fatalf("Expected 1 item from stream, got %d", len(items)) + } + if items[0].GetType() != azureshared.ElasticSanVolumeGroup.String() { + t.Errorf("Expected type %s, got %s", azureshared.ElasticSanVolumeGroup.String(), items[0].GetType()) + } + }) +} diff --git a/sources/azure/shared/mocks/mock_elastic_san_volume_group_client.go b/sources/azure/shared/mocks/mock_elastic_san_volume_group_client.go new file mode 100644 index 00000000..7805e687 --- /dev/null +++ b/sources/azure/shared/mocks/mock_elastic_san_volume_group_client.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: elastic-san-volume-group-client.go +// +// Generated by this command: +// +// mockgen -destination=../shared/mocks/mock_elastic_san_volume_group_client.go -package=mocks -source=elastic-san-volume-group-client.go +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + armelasticsan "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" + clients "github.com/overmindtech/cli/sources/azure/clients" + gomock "go.uber.org/mock/gomock" +) + +// MockElasticSanVolumeGroupClient is a mock of ElasticSanVolumeGroupClient interface. +type MockElasticSanVolumeGroupClient struct { + ctrl *gomock.Controller + recorder *MockElasticSanVolumeGroupClientMockRecorder + isgomock struct{} +} + +// MockElasticSanVolumeGroupClientMockRecorder is the mock recorder for MockElasticSanVolumeGroupClient. +type MockElasticSanVolumeGroupClientMockRecorder struct { + mock *MockElasticSanVolumeGroupClient +} + +// NewMockElasticSanVolumeGroupClient creates a new mock instance. +func NewMockElasticSanVolumeGroupClient(ctrl *gomock.Controller) *MockElasticSanVolumeGroupClient { + mock := &MockElasticSanVolumeGroupClient{ctrl: ctrl} + mock.recorder = &MockElasticSanVolumeGroupClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockElasticSanVolumeGroupClient) EXPECT() *MockElasticSanVolumeGroupClientMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockElasticSanVolumeGroupClient) Get(ctx context.Context, resourceGroupName, elasticSanName, volumeGroupName string, options *armelasticsan.VolumeGroupsClientGetOptions) (armelasticsan.VolumeGroupsClientGetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, elasticSanName, volumeGroupName, options) + ret0, _ := ret[0].(armelasticsan.VolumeGroupsClientGetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockElasticSanVolumeGroupClientMockRecorder) Get(ctx, resourceGroupName, elasticSanName, volumeGroupName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockElasticSanVolumeGroupClient)(nil).Get), ctx, resourceGroupName, elasticSanName, volumeGroupName, options) +} + +// NewListByElasticSanPager mocks base method. +func (m *MockElasticSanVolumeGroupClient) NewListByElasticSanPager(resourceGroupName, elasticSanName string, options *armelasticsan.VolumeGroupsClientListByElasticSanOptions) clients.ElasticSanVolumeGroupPager { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewListByElasticSanPager", resourceGroupName, elasticSanName, options) + ret0, _ := ret[0].(clients.ElasticSanVolumeGroupPager) + return ret0 +} + +// NewListByElasticSanPager indicates an expected call of NewListByElasticSanPager. +func (mr *MockElasticSanVolumeGroupClientMockRecorder) NewListByElasticSanPager(resourceGroupName, elasticSanName, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListByElasticSanPager", reflect.TypeOf((*MockElasticSanVolumeGroupClient)(nil).NewListByElasticSanPager), resourceGroupName, elasticSanName, options) +} diff --git a/sources/azure/shared/utils.go b/sources/azure/shared/utils.go index 72f305ad..605b5f4d 100644 --- a/sources/azure/shared/utils.go +++ b/sources/azure/shared/utils.go @@ -52,6 +52,7 @@ func GetResourceIDPathKeys(resourceType string) []string { "azure-batch-batch-application": {"batchAccounts", "applications"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/applications/{applicationName}", "azure-batch-batch-pool": {"batchAccounts", "pools"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools/{poolName}", "azure-network-dns-record-set": {"dnszones"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/dnszones/{zoneName}/{recordType}/{relativeRecordSetName}" + "azure-elasticsan-elastic-san-volume-group": {"elasticSans", "volumegroups"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ElasticSan/elasticSans/{elasticSanName}/volumegroups/{volumeGroupName}" "azure-elasticsan-elastic-san-volume-snapshot": {"elasticSans", "volumegroups", "snapshots"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ElasticSan/elasticSans/{elasticSanName}/volumegroups/{volumeGroupName}/snapshots/{snapshotName}" "azure-compute-disk-access-private-endpoint-connection": {"diskAccesses", "privateEndpointConnections"}, // "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Compute/diskAccesses/{diskAccessName}/privateEndpointConnections/{connectionName}" } From dbebe8114847948110384c935d2e4c152738d2ac Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 12 Mar 2026 09:12:23 +0100 Subject: [PATCH 13/18] [ENG-3098] Phase 1: Backend -- Accumulate Partial Plans (#4233) ## Summary - Relax `mapped_item_diffs` PK from `change_external_id` to `id` so multiple rows can be stored per change, enabling accumulation of partial Terraform plans from parallel CI workflows (e.g. Atlantis) - Add `AddPlannedChanges` RPC that appends planned change items to an existing change without triggering analysis - Modify `StartChangeAnalysis` to load and combine pre-stored items with any items provided in the request ## Linear Ticket - **Ticket**: [ENG-3098](https://linear.app/overmind/issue/ENG-3098/phase-1-backend-accumulate-partial-plans) -- Phase 1: Backend -- Accumulate Partial Plans - **Project**: [Multi-Plan Submission & GitHub App PR Commenting](https://linear.app/overmind/project/multi-plan-submission-and-github-app-pr-commenting-7b3d32c2ff24) - **Purpose**: Enable CI systems that produce multiple Terraform plans in parallel to submit each plan independently and trigger a single unified analysis - **Approver**: TP Honey ## Changes ### Schema & Queries - **Migration** (`20260311113037_relax_mapped_item_diffs_pk.sql`): Drops PK on `change_external_id`, adds PK on `id`, adds btree index on `change_external_id` - **SQLC queries**: `GetMappedItemDiff` and `GetMappedItemDiffsForAllModifications` changed from `:one` to `:many`; new `SetPlannedChangesStored` query added - All callers updated with `flattenMappedItemDiffs` helper across `changesservice.go`, `changetimeline.go`, `labelservice.go`, `signalservice.go`, `crm_sync.go`, and `area51/` ### Proto - New `AddPlannedChanges` RPC + `AddPlannedChangesRequest`/`AddPlannedChangesResponse` messages in `ChangesService` ### Handlers - `AddPlannedChanges`: validates auth, checks change is in `DEFINING` status, appends items via `InsertMappedItemDiff`, sets `planned_changes_stored` flag - `StartChangeAnalysis`: always loads stored items and combines with any provided items (supports single-plan, multi-plan, and hybrid flows) ### Tests - `TestAddPlannedChanges`: 6 subtests covering append, accumulate, flag verification, empty rejection, non-existent change - `TestAddPlannedChangesConcurrent`: 10 goroutines inserting in parallel, verifying no data loss - `TestWriteMappedItemDiffs`: updated to verify multi-row insert succeeds (was testing PK conflict) - All existing test callers updated for `:many` return type ## Deviations from Approved Plan ### 1. `StartChangeAnalysis` combines stored + provided items (not either/or) **Plan**: When `changingItems` is empty, load from DB. When provided, use them directly. **Implementation**: Always loads stored items and appends to provided items, supporting a hybrid flow. **Why**: Review feedback from @DavidS-ovm -- the endpoint should work when items are both stored AND provided, combining both rather than picking one. ### 2. No error on empty `changingItems` with no stored items **Plan**: Return `CodeFailedPrecondition` when both provided and stored items are empty. **Implementation**: Allow empty items through (analysis runs with empty set as before). **Why**: The existing `TestStartChangeAnalysis/UpdatePlannedChanges_with_no_changes` test calls `StartChangeAnalysis` with empty items and expects success (no-op when River is unconfigured). Adding an error here broke backward compatibility. ### 3. Additional callers updated beyond plan **Plan**: Listed 4 callers to update (`changesservice.go` x3, `changetimeline.go` x1). **Implementation**: Also updated callers in `labelservice.go` (x2), `signalservice.go` (x1), `crm_sync.go` (x1), `area51/changes.go` (x3), `area51/llm.go` (x3) -- 10 additional call sites. **Why**: The plan identified callers by grep but missed callers in other packages. All callers of `GetMappedItemDiff` must be updated for the `:one` to `:many` change. ### 4. `ErrNoRows` guards removed (not replaced) **Plan**: Did not explicitly address `pgx.ErrNoRows` handling. **Implementation**: Removed `ErrNoRows` guards at all `GetMappedItemDiff` call sites. **Why**: With `:many` queries, pgx returns an empty slice and `nil` error instead of `ErrNoRows` ([pgx#2251](https://github.com/jackc/pgx/issues/2251)). The guards were dead code. ### 5. `flattenMappedItemDiffs` duplicated in `area51` package **Plan**: Single helper in `changesservice.go`. **Implementation**: Added a second copy in `area51/changes.go` because `area51` is a separate package and cannot import from `service`. **Why**: Go package boundaries -- the `area51` package has its own callers of `GetMappedItemDiff`. ### 6. `schema.sql` manually edited (not generated by PG16) **Plan**: Generate via `make_migration.sh` + `reset_database.sh`. **Implementation**: Generated locally with PG18 (only version available in cloud agent), then manually corrected to match PG16 `pg_dump` format. **Why**: Cloud agent environment lacks Docker Compose services (PG16 runs as a sidecar in devcontainer). Installed PG18 from Debian packages as a workaround. The schema.sql was corrected to match CI's PG16 output by reverting to the parent commit's file and applying only the PK + index changes. ### 7. No changes to `CalculateMappedResources` logic **Plan**: Update comments in `CalculateMappedResources` to reflect new semantics. **Implementation**: Done as planned -- comment updated from "avoid primary key conflicts" to "replace pre-stored partial plans with resolved results". No functional changes. Enable accumulation of partial change plans by modifying the `mapped_item_diffs` schema, adding an RPC to store items, and updating `StartChangeAnalysis` to load them.
Open in Web Open in Cursor 
--------- GitOrigin-RevId: 19d327de5a8ada8cef3a4d7629821c2fc6a9fe27 --- go/sdp-go/changes.pb.go | 880 +++++++++++++----------- go/sdp-go/sdpconnect/changes.connect.go | 37 + 2 files changed, 530 insertions(+), 387 deletions(-) diff --git a/go/sdp-go/changes.pb.go b/go/sdp-go/changes.pb.go index 51259dff..9de6b493 100644 --- a/go/sdp-go/changes.pb.go +++ b/go/sdp-go/changes.pb.go @@ -535,7 +535,7 @@ func (x StartChangeResponse_State) Number() protoreflect.EnumNumber { // Deprecated: Use StartChangeResponse_State.Descriptor instead. func (StartChangeResponse_State) EnumDescriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{86, 0} + return file_changes_proto_rawDescGZIP(), []int{88, 0} } type EndChangeResponse_State int32 @@ -591,7 +591,7 @@ func (x EndChangeResponse_State) Number() protoreflect.EnumNumber { // Deprecated: Use EndChangeResponse_State.Descriptor instead. func (EndChangeResponse_State) EnumDescriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{88, 0} + return file_changes_proto_rawDescGZIP(), []int{90, 0} } type Risk_Severity int32 @@ -643,7 +643,7 @@ func (x Risk_Severity) Number() protoreflect.EnumNumber { // Deprecated: Use Risk_Severity.Descriptor instead. func (Risk_Severity) EnumDescriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{91, 0} + return file_changes_proto_rawDescGZIP(), []int{93, 0} } type ChangeAnalysisStatus_Status int32 @@ -698,7 +698,7 @@ func (x ChangeAnalysisStatus_Status) Number() protoreflect.EnumNumber { // Deprecated: Use ChangeAnalysisStatus_Status.Descriptor instead. func (ChangeAnalysisStatus_Status) EnumDescriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{92, 0} + return file_changes_proto_rawDescGZIP(), []int{94, 0} } type LabelRule struct { @@ -3291,6 +3291,100 @@ func (*StartChangeAnalysisResponse) Descriptor() ([]byte, []int) { return file_changes_proto_rawDescGZIP(), []int{43} } +// AddPlannedChangesRequest appends a batch of planned changes to an existing +// change without triggering analysis. Used by multi-plan workflows (e.g. +// Atlantis parallel planning) where each plan step submits independently. +type AddPlannedChangesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The change to append items to + ChangeUUID []byte `protobuf:"bytes,1,opt,name=changeUUID,proto3" json:"changeUUID,omitempty"` + // The planned change items to append + ChangingItems []*MappedItemDiff `protobuf:"bytes,2,rep,name=changingItems,proto3" json:"changingItems,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddPlannedChangesRequest) Reset() { + *x = AddPlannedChangesRequest{} + mi := &file_changes_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddPlannedChangesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddPlannedChangesRequest) ProtoMessage() {} + +func (x *AddPlannedChangesRequest) ProtoReflect() protoreflect.Message { + mi := &file_changes_proto_msgTypes[44] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddPlannedChangesRequest.ProtoReflect.Descriptor instead. +func (*AddPlannedChangesRequest) Descriptor() ([]byte, []int) { + return file_changes_proto_rawDescGZIP(), []int{44} +} + +func (x *AddPlannedChangesRequest) GetChangeUUID() []byte { + if x != nil { + return x.ChangeUUID + } + return nil +} + +func (x *AddPlannedChangesRequest) GetChangingItems() []*MappedItemDiff { + if x != nil { + return x.ChangingItems + } + return nil +} + +// AddPlannedChangesResponse is intentionally empty; errors use ConnectRPC codes. +type AddPlannedChangesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddPlannedChangesResponse) Reset() { + *x = AddPlannedChangesResponse{} + mi := &file_changes_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddPlannedChangesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddPlannedChangesResponse) ProtoMessage() {} + +func (x *AddPlannedChangesResponse) ProtoReflect() protoreflect.Message { + mi := &file_changes_proto_msgTypes[45] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddPlannedChangesResponse.ProtoReflect.Descriptor instead. +func (*AddPlannedChangesResponse) Descriptor() ([]byte, []int) { + return file_changes_proto_rawDescGZIP(), []int{45} +} + type ListHomeChangesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Pagination *PaginationRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` @@ -3301,7 +3395,7 @@ type ListHomeChangesRequest struct { func (x *ListHomeChangesRequest) Reset() { *x = ListHomeChangesRequest{} - mi := &file_changes_proto_msgTypes[44] + mi := &file_changes_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3313,7 +3407,7 @@ func (x *ListHomeChangesRequest) String() string { func (*ListHomeChangesRequest) ProtoMessage() {} func (x *ListHomeChangesRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[44] + mi := &file_changes_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3326,7 +3420,7 @@ func (x *ListHomeChangesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListHomeChangesRequest.ProtoReflect.Descriptor instead. func (*ListHomeChangesRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{44} + return file_changes_proto_rawDescGZIP(), []int{46} } func (x *ListHomeChangesRequest) GetPagination() *PaginationRequest { @@ -3360,7 +3454,7 @@ type ChangeFiltersRequest struct { func (x *ChangeFiltersRequest) Reset() { *x = ChangeFiltersRequest{} - mi := &file_changes_proto_msgTypes[45] + mi := &file_changes_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3372,7 +3466,7 @@ func (x *ChangeFiltersRequest) String() string { func (*ChangeFiltersRequest) ProtoMessage() {} func (x *ChangeFiltersRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[45] + mi := &file_changes_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3385,7 +3479,7 @@ func (x *ChangeFiltersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeFiltersRequest.ProtoReflect.Descriptor instead. func (*ChangeFiltersRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{45} + return file_changes_proto_rawDescGZIP(), []int{47} } func (x *ChangeFiltersRequest) GetRepos() []string { @@ -3440,7 +3534,7 @@ type ListHomeChangesResponse struct { func (x *ListHomeChangesResponse) Reset() { *x = ListHomeChangesResponse{} - mi := &file_changes_proto_msgTypes[46] + mi := &file_changes_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3452,7 +3546,7 @@ func (x *ListHomeChangesResponse) String() string { func (*ListHomeChangesResponse) ProtoMessage() {} func (x *ListHomeChangesResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[46] + mi := &file_changes_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3465,7 +3559,7 @@ func (x *ListHomeChangesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListHomeChangesResponse.ProtoReflect.Descriptor instead. func (*ListHomeChangesResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{46} + return file_changes_proto_rawDescGZIP(), []int{48} } func (x *ListHomeChangesResponse) GetChanges() []*ChangeSummary { @@ -3490,7 +3584,7 @@ type PopulateChangeFiltersRequest struct { func (x *PopulateChangeFiltersRequest) Reset() { *x = PopulateChangeFiltersRequest{} - mi := &file_changes_proto_msgTypes[47] + mi := &file_changes_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3502,7 +3596,7 @@ func (x *PopulateChangeFiltersRequest) String() string { func (*PopulateChangeFiltersRequest) ProtoMessage() {} func (x *PopulateChangeFiltersRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[47] + mi := &file_changes_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3515,7 +3609,7 @@ func (x *PopulateChangeFiltersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PopulateChangeFiltersRequest.ProtoReflect.Descriptor instead. func (*PopulateChangeFiltersRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{47} + return file_changes_proto_rawDescGZIP(), []int{49} } type PopulateChangeFiltersResponse struct { @@ -3528,7 +3622,7 @@ type PopulateChangeFiltersResponse struct { func (x *PopulateChangeFiltersResponse) Reset() { *x = PopulateChangeFiltersResponse{} - mi := &file_changes_proto_msgTypes[48] + mi := &file_changes_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3540,7 +3634,7 @@ func (x *PopulateChangeFiltersResponse) String() string { func (*PopulateChangeFiltersResponse) ProtoMessage() {} func (x *PopulateChangeFiltersResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[48] + mi := &file_changes_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3553,7 +3647,7 @@ func (x *PopulateChangeFiltersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PopulateChangeFiltersResponse.ProtoReflect.Descriptor instead. func (*PopulateChangeFiltersResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{48} + return file_changes_proto_rawDescGZIP(), []int{50} } func (x *PopulateChangeFiltersResponse) GetRepos() []string { @@ -3584,7 +3678,7 @@ type ItemDiffSummary struct { func (x *ItemDiffSummary) Reset() { *x = ItemDiffSummary{} - mi := &file_changes_proto_msgTypes[49] + mi := &file_changes_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3596,7 +3690,7 @@ func (x *ItemDiffSummary) String() string { func (*ItemDiffSummary) ProtoMessage() {} func (x *ItemDiffSummary) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[49] + mi := &file_changes_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3609,7 +3703,7 @@ func (x *ItemDiffSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use ItemDiffSummary.ProtoReflect.Descriptor instead. func (*ItemDiffSummary) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{49} + return file_changes_proto_rawDescGZIP(), []int{51} } func (x *ItemDiffSummary) GetItem() *Reference { @@ -3658,7 +3752,7 @@ type ItemDiff struct { func (x *ItemDiff) Reset() { *x = ItemDiff{} - mi := &file_changes_proto_msgTypes[50] + mi := &file_changes_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3670,7 +3764,7 @@ func (x *ItemDiff) String() string { func (*ItemDiff) ProtoMessage() {} func (x *ItemDiff) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[50] + mi := &file_changes_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3683,7 +3777,7 @@ func (x *ItemDiff) ProtoReflect() protoreflect.Message { // Deprecated: Use ItemDiff.ProtoReflect.Descriptor instead. func (*ItemDiff) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{50} + return file_changes_proto_rawDescGZIP(), []int{52} } func (x *ItemDiff) GetItem() *Reference { @@ -3737,7 +3831,7 @@ type EnrichedTags struct { func (x *EnrichedTags) Reset() { *x = EnrichedTags{} - mi := &file_changes_proto_msgTypes[51] + mi := &file_changes_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3749,7 +3843,7 @@ func (x *EnrichedTags) String() string { func (*EnrichedTags) ProtoMessage() {} func (x *EnrichedTags) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[51] + mi := &file_changes_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3762,7 +3856,7 @@ func (x *EnrichedTags) ProtoReflect() protoreflect.Message { // Deprecated: Use EnrichedTags.ProtoReflect.Descriptor instead. func (*EnrichedTags) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{51} + return file_changes_proto_rawDescGZIP(), []int{53} } func (x *EnrichedTags) GetTagValue() map[string]*TagValue { @@ -3787,7 +3881,7 @@ type TagValue struct { func (x *TagValue) Reset() { *x = TagValue{} - mi := &file_changes_proto_msgTypes[52] + mi := &file_changes_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3799,7 +3893,7 @@ func (x *TagValue) String() string { func (*TagValue) ProtoMessage() {} func (x *TagValue) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[52] + mi := &file_changes_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3812,7 +3906,7 @@ func (x *TagValue) ProtoReflect() protoreflect.Message { // Deprecated: Use TagValue.ProtoReflect.Descriptor instead. func (*TagValue) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{52} + return file_changes_proto_rawDescGZIP(), []int{54} } func (x *TagValue) GetValue() isTagValue_Value { @@ -3866,7 +3960,7 @@ type UserTagValue struct { func (x *UserTagValue) Reset() { *x = UserTagValue{} - mi := &file_changes_proto_msgTypes[53] + mi := &file_changes_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3878,7 +3972,7 @@ func (x *UserTagValue) String() string { func (*UserTagValue) ProtoMessage() {} func (x *UserTagValue) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[53] + mi := &file_changes_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3891,7 +3985,7 @@ func (x *UserTagValue) ProtoReflect() protoreflect.Message { // Deprecated: Use UserTagValue.ProtoReflect.Descriptor instead. func (*UserTagValue) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{53} + return file_changes_proto_rawDescGZIP(), []int{55} } func (x *UserTagValue) GetValue() string { @@ -3913,7 +4007,7 @@ type AutoTagValue struct { func (x *AutoTagValue) Reset() { *x = AutoTagValue{} - mi := &file_changes_proto_msgTypes[54] + mi := &file_changes_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3925,7 +4019,7 @@ func (x *AutoTagValue) String() string { func (*AutoTagValue) ProtoMessage() {} func (x *AutoTagValue) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[54] + mi := &file_changes_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3938,7 +4032,7 @@ func (x *AutoTagValue) ProtoReflect() protoreflect.Message { // Deprecated: Use AutoTagValue.ProtoReflect.Descriptor instead. func (*AutoTagValue) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{54} + return file_changes_proto_rawDescGZIP(), []int{56} } func (x *AutoTagValue) GetValue() string { @@ -3981,7 +4075,7 @@ type Label struct { func (x *Label) Reset() { *x = Label{} - mi := &file_changes_proto_msgTypes[55] + mi := &file_changes_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3993,7 +4087,7 @@ func (x *Label) String() string { func (*Label) ProtoMessage() {} func (x *Label) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[55] + mi := &file_changes_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4006,7 +4100,7 @@ func (x *Label) ProtoReflect() protoreflect.Message { // Deprecated: Use Label.ProtoReflect.Descriptor instead. func (*Label) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{55} + return file_changes_proto_rawDescGZIP(), []int{57} } func (x *Label) GetType() LabelType { @@ -4105,7 +4199,7 @@ type ChangeSummary struct { func (x *ChangeSummary) Reset() { *x = ChangeSummary{} - mi := &file_changes_proto_msgTypes[56] + mi := &file_changes_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4117,7 +4211,7 @@ func (x *ChangeSummary) String() string { func (*ChangeSummary) ProtoMessage() {} func (x *ChangeSummary) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[56] + mi := &file_changes_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4130,7 +4224,7 @@ func (x *ChangeSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeSummary.ProtoReflect.Descriptor instead. func (*ChangeSummary) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{56} + return file_changes_proto_rawDescGZIP(), []int{58} } func (x *ChangeSummary) GetUUID() []byte { @@ -4273,7 +4367,7 @@ type Change struct { func (x *Change) Reset() { *x = Change{} - mi := &file_changes_proto_msgTypes[57] + mi := &file_changes_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4285,7 +4379,7 @@ func (x *Change) String() string { func (*Change) ProtoMessage() {} func (x *Change) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[57] + mi := &file_changes_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4298,7 +4392,7 @@ func (x *Change) ProtoReflect() protoreflect.Message { // Deprecated: Use Change.ProtoReflect.Descriptor instead. func (*Change) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{57} + return file_changes_proto_rawDescGZIP(), []int{59} } func (x *Change) GetMetadata() *ChangeMetadata { @@ -4366,7 +4460,7 @@ type ChangeMetadata struct { func (x *ChangeMetadata) Reset() { *x = ChangeMetadata{} - mi := &file_changes_proto_msgTypes[58] + mi := &file_changes_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4378,7 +4472,7 @@ func (x *ChangeMetadata) String() string { func (*ChangeMetadata) ProtoMessage() {} func (x *ChangeMetadata) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[58] + mi := &file_changes_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4391,7 +4485,7 @@ func (x *ChangeMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeMetadata.ProtoReflect.Descriptor instead. func (*ChangeMetadata) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{58} + return file_changes_proto_rawDescGZIP(), []int{60} } func (x *ChangeMetadata) GetUUID() []byte { @@ -4596,7 +4690,7 @@ type ChangeProperties struct { func (x *ChangeProperties) Reset() { *x = ChangeProperties{} - mi := &file_changes_proto_msgTypes[59] + mi := &file_changes_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4608,7 +4702,7 @@ func (x *ChangeProperties) String() string { func (*ChangeProperties) ProtoMessage() {} func (x *ChangeProperties) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[59] + mi := &file_changes_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4621,7 +4715,7 @@ func (x *ChangeProperties) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeProperties.ProtoReflect.Descriptor instead. func (*ChangeProperties) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{59} + return file_changes_proto_rawDescGZIP(), []int{61} } func (x *ChangeProperties) GetTitle() string { @@ -4755,7 +4849,7 @@ type GithubChangeInfo struct { func (x *GithubChangeInfo) Reset() { *x = GithubChangeInfo{} - mi := &file_changes_proto_msgTypes[60] + mi := &file_changes_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4767,7 +4861,7 @@ func (x *GithubChangeInfo) String() string { func (*GithubChangeInfo) ProtoMessage() {} func (x *GithubChangeInfo) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[60] + mi := &file_changes_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4780,7 +4874,7 @@ func (x *GithubChangeInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use GithubChangeInfo.ProtoReflect.Descriptor instead. func (*GithubChangeInfo) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{60} + return file_changes_proto_rawDescGZIP(), []int{62} } func (x *GithubChangeInfo) GetAuthorUsername() string { @@ -4820,7 +4914,7 @@ type ListChangesRequest struct { func (x *ListChangesRequest) Reset() { *x = ListChangesRequest{} - mi := &file_changes_proto_msgTypes[61] + mi := &file_changes_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4832,7 +4926,7 @@ func (x *ListChangesRequest) String() string { func (*ListChangesRequest) ProtoMessage() {} func (x *ListChangesRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[61] + mi := &file_changes_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4845,7 +4939,7 @@ func (x *ListChangesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesRequest.ProtoReflect.Descriptor instead. func (*ListChangesRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{61} + return file_changes_proto_rawDescGZIP(), []int{63} } type ListChangesResponse struct { @@ -4857,7 +4951,7 @@ type ListChangesResponse struct { func (x *ListChangesResponse) Reset() { *x = ListChangesResponse{} - mi := &file_changes_proto_msgTypes[62] + mi := &file_changes_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4869,7 +4963,7 @@ func (x *ListChangesResponse) String() string { func (*ListChangesResponse) ProtoMessage() {} func (x *ListChangesResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[62] + mi := &file_changes_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4882,7 +4976,7 @@ func (x *ListChangesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesResponse.ProtoReflect.Descriptor instead. func (*ListChangesResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{62} + return file_changes_proto_rawDescGZIP(), []int{64} } func (x *ListChangesResponse) GetChanges() []*Change { @@ -4902,7 +4996,7 @@ type ListChangesByStatusRequest struct { func (x *ListChangesByStatusRequest) Reset() { *x = ListChangesByStatusRequest{} - mi := &file_changes_proto_msgTypes[63] + mi := &file_changes_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4914,7 +5008,7 @@ func (x *ListChangesByStatusRequest) String() string { func (*ListChangesByStatusRequest) ProtoMessage() {} func (x *ListChangesByStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[63] + mi := &file_changes_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4927,7 +5021,7 @@ func (x *ListChangesByStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesByStatusRequest.ProtoReflect.Descriptor instead. func (*ListChangesByStatusRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{63} + return file_changes_proto_rawDescGZIP(), []int{65} } func (x *ListChangesByStatusRequest) GetStatus() ChangeStatus { @@ -4946,7 +5040,7 @@ type ListChangesByStatusResponse struct { func (x *ListChangesByStatusResponse) Reset() { *x = ListChangesByStatusResponse{} - mi := &file_changes_proto_msgTypes[64] + mi := &file_changes_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4958,7 +5052,7 @@ func (x *ListChangesByStatusResponse) String() string { func (*ListChangesByStatusResponse) ProtoMessage() {} func (x *ListChangesByStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[64] + mi := &file_changes_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4971,7 +5065,7 @@ func (x *ListChangesByStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesByStatusResponse.ProtoReflect.Descriptor instead. func (*ListChangesByStatusResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{64} + return file_changes_proto_rawDescGZIP(), []int{66} } func (x *ListChangesByStatusResponse) GetChanges() []*Change { @@ -4991,7 +5085,7 @@ type CreateChangeRequest struct { func (x *CreateChangeRequest) Reset() { *x = CreateChangeRequest{} - mi := &file_changes_proto_msgTypes[65] + mi := &file_changes_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5003,7 +5097,7 @@ func (x *CreateChangeRequest) String() string { func (*CreateChangeRequest) ProtoMessage() {} func (x *CreateChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[65] + mi := &file_changes_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5016,7 +5110,7 @@ func (x *CreateChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateChangeRequest.ProtoReflect.Descriptor instead. func (*CreateChangeRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{65} + return file_changes_proto_rawDescGZIP(), []int{67} } func (x *CreateChangeRequest) GetProperties() *ChangeProperties { @@ -5035,7 +5129,7 @@ type CreateChangeResponse struct { func (x *CreateChangeResponse) Reset() { *x = CreateChangeResponse{} - mi := &file_changes_proto_msgTypes[66] + mi := &file_changes_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5047,7 +5141,7 @@ func (x *CreateChangeResponse) String() string { func (*CreateChangeResponse) ProtoMessage() {} func (x *CreateChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[66] + mi := &file_changes_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5060,7 +5154,7 @@ func (x *CreateChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateChangeResponse.ProtoReflect.Descriptor instead. func (*CreateChangeResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{66} + return file_changes_proto_rawDescGZIP(), []int{68} } func (x *CreateChangeResponse) GetChange() *Change { @@ -5085,7 +5179,7 @@ type GetChangeRequest struct { func (x *GetChangeRequest) Reset() { *x = GetChangeRequest{} - mi := &file_changes_proto_msgTypes[67] + mi := &file_changes_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5097,7 +5191,7 @@ func (x *GetChangeRequest) String() string { func (*GetChangeRequest) ProtoMessage() {} func (x *GetChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[67] + mi := &file_changes_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5110,7 +5204,7 @@ func (x *GetChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeRequest.ProtoReflect.Descriptor instead. func (*GetChangeRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{67} + return file_changes_proto_rawDescGZIP(), []int{69} } func (x *GetChangeRequest) GetUUID() []byte { @@ -5136,7 +5230,7 @@ type GetChangeByTicketLinkRequest struct { func (x *GetChangeByTicketLinkRequest) Reset() { *x = GetChangeByTicketLinkRequest{} - mi := &file_changes_proto_msgTypes[68] + mi := &file_changes_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5148,7 +5242,7 @@ func (x *GetChangeByTicketLinkRequest) String() string { func (*GetChangeByTicketLinkRequest) ProtoMessage() {} func (x *GetChangeByTicketLinkRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[68] + mi := &file_changes_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5161,7 +5255,7 @@ func (x *GetChangeByTicketLinkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeByTicketLinkRequest.ProtoReflect.Descriptor instead. func (*GetChangeByTicketLinkRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{68} + return file_changes_proto_rawDescGZIP(), []int{70} } func (x *GetChangeByTicketLinkRequest) GetTicketLink() string { @@ -5191,7 +5285,7 @@ type GetChangeSummaryRequest struct { func (x *GetChangeSummaryRequest) Reset() { *x = GetChangeSummaryRequest{} - mi := &file_changes_proto_msgTypes[69] + mi := &file_changes_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5203,7 +5297,7 @@ func (x *GetChangeSummaryRequest) String() string { func (*GetChangeSummaryRequest) ProtoMessage() {} func (x *GetChangeSummaryRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[69] + mi := &file_changes_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5216,7 +5310,7 @@ func (x *GetChangeSummaryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeSummaryRequest.ProtoReflect.Descriptor instead. func (*GetChangeSummaryRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{69} + return file_changes_proto_rawDescGZIP(), []int{71} } func (x *GetChangeSummaryRequest) GetUUID() []byte { @@ -5263,7 +5357,7 @@ type GetChangeSummaryResponse struct { func (x *GetChangeSummaryResponse) Reset() { *x = GetChangeSummaryResponse{} - mi := &file_changes_proto_msgTypes[70] + mi := &file_changes_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5275,7 +5369,7 @@ func (x *GetChangeSummaryResponse) String() string { func (*GetChangeSummaryResponse) ProtoMessage() {} func (x *GetChangeSummaryResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[70] + mi := &file_changes_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5288,7 +5382,7 @@ func (x *GetChangeSummaryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeSummaryResponse.ProtoReflect.Descriptor instead. func (*GetChangeSummaryResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{70} + return file_changes_proto_rawDescGZIP(), []int{72} } func (x *GetChangeSummaryResponse) GetChange() string { @@ -5309,7 +5403,7 @@ type GetChangeSignalsRequest struct { func (x *GetChangeSignalsRequest) Reset() { *x = GetChangeSignalsRequest{} - mi := &file_changes_proto_msgTypes[71] + mi := &file_changes_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5321,7 +5415,7 @@ func (x *GetChangeSignalsRequest) String() string { func (*GetChangeSignalsRequest) ProtoMessage() {} func (x *GetChangeSignalsRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[71] + mi := &file_changes_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5334,7 +5428,7 @@ func (x *GetChangeSignalsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeSignalsRequest.ProtoReflect.Descriptor instead. func (*GetChangeSignalsRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{71} + return file_changes_proto_rawDescGZIP(), []int{73} } func (x *GetChangeSignalsRequest) GetUUID() []byte { @@ -5360,7 +5454,7 @@ type GetChangeSignalsResponse struct { func (x *GetChangeSignalsResponse) Reset() { *x = GetChangeSignalsResponse{} - mi := &file_changes_proto_msgTypes[72] + mi := &file_changes_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5372,7 +5466,7 @@ func (x *GetChangeSignalsResponse) String() string { func (*GetChangeSignalsResponse) ProtoMessage() {} func (x *GetChangeSignalsResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[72] + mi := &file_changes_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5385,7 +5479,7 @@ func (x *GetChangeSignalsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeSignalsResponse.ProtoReflect.Descriptor instead. func (*GetChangeSignalsResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{72} + return file_changes_proto_rawDescGZIP(), []int{74} } func (x *GetChangeSignalsResponse) GetSignals() string { @@ -5404,7 +5498,7 @@ type GetChangeResponse struct { func (x *GetChangeResponse) Reset() { *x = GetChangeResponse{} - mi := &file_changes_proto_msgTypes[73] + mi := &file_changes_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5416,7 +5510,7 @@ func (x *GetChangeResponse) String() string { func (*GetChangeResponse) ProtoMessage() {} func (x *GetChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[73] + mi := &file_changes_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5429,7 +5523,7 @@ func (x *GetChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeResponse.ProtoReflect.Descriptor instead. func (*GetChangeResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{73} + return file_changes_proto_rawDescGZIP(), []int{75} } func (x *GetChangeResponse) GetChange() *Change { @@ -5449,7 +5543,7 @@ type GetChangeRisksRequest struct { func (x *GetChangeRisksRequest) Reset() { *x = GetChangeRisksRequest{} - mi := &file_changes_proto_msgTypes[74] + mi := &file_changes_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5461,7 +5555,7 @@ func (x *GetChangeRisksRequest) String() string { func (*GetChangeRisksRequest) ProtoMessage() {} func (x *GetChangeRisksRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[74] + mi := &file_changes_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5474,7 +5568,7 @@ func (x *GetChangeRisksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeRisksRequest.ProtoReflect.Descriptor instead. func (*GetChangeRisksRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{74} + return file_changes_proto_rawDescGZIP(), []int{76} } func (x *GetChangeRisksRequest) GetUUID() []byte { @@ -5502,7 +5596,7 @@ type ChangeRiskMetadata struct { func (x *ChangeRiskMetadata) Reset() { *x = ChangeRiskMetadata{} - mi := &file_changes_proto_msgTypes[75] + mi := &file_changes_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5514,7 +5608,7 @@ func (x *ChangeRiskMetadata) String() string { func (*ChangeRiskMetadata) ProtoMessage() {} func (x *ChangeRiskMetadata) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[75] + mi := &file_changes_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5527,7 +5621,7 @@ func (x *ChangeRiskMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeRiskMetadata.ProtoReflect.Descriptor instead. func (*ChangeRiskMetadata) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{75} + return file_changes_proto_rawDescGZIP(), []int{77} } func (x *ChangeRiskMetadata) GetChangeAnalysisStatus() *ChangeAnalysisStatus { @@ -5574,7 +5668,7 @@ type GetChangeRisksResponse struct { func (x *GetChangeRisksResponse) Reset() { *x = GetChangeRisksResponse{} - mi := &file_changes_proto_msgTypes[76] + mi := &file_changes_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5586,7 +5680,7 @@ func (x *GetChangeRisksResponse) String() string { func (*GetChangeRisksResponse) ProtoMessage() {} func (x *GetChangeRisksResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[76] + mi := &file_changes_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5599,7 +5693,7 @@ func (x *GetChangeRisksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChangeRisksResponse.ProtoReflect.Descriptor instead. func (*GetChangeRisksResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{76} + return file_changes_proto_rawDescGZIP(), []int{78} } func (x *GetChangeRisksResponse) GetChangeRiskMetadata() *ChangeRiskMetadata { @@ -5620,7 +5714,7 @@ type UpdateChangeRequest struct { func (x *UpdateChangeRequest) Reset() { *x = UpdateChangeRequest{} - mi := &file_changes_proto_msgTypes[77] + mi := &file_changes_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5632,7 +5726,7 @@ func (x *UpdateChangeRequest) String() string { func (*UpdateChangeRequest) ProtoMessage() {} func (x *UpdateChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[77] + mi := &file_changes_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5645,7 +5739,7 @@ func (x *UpdateChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateChangeRequest.ProtoReflect.Descriptor instead. func (*UpdateChangeRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{77} + return file_changes_proto_rawDescGZIP(), []int{79} } func (x *UpdateChangeRequest) GetUUID() []byte { @@ -5671,7 +5765,7 @@ type UpdateChangeResponse struct { func (x *UpdateChangeResponse) Reset() { *x = UpdateChangeResponse{} - mi := &file_changes_proto_msgTypes[78] + mi := &file_changes_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5683,7 +5777,7 @@ func (x *UpdateChangeResponse) String() string { func (*UpdateChangeResponse) ProtoMessage() {} func (x *UpdateChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[78] + mi := &file_changes_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5696,7 +5790,7 @@ func (x *UpdateChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateChangeResponse.ProtoReflect.Descriptor instead. func (*UpdateChangeResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{78} + return file_changes_proto_rawDescGZIP(), []int{80} } func (x *UpdateChangeResponse) GetChange() *Change { @@ -5716,7 +5810,7 @@ type DeleteChangeRequest struct { func (x *DeleteChangeRequest) Reset() { *x = DeleteChangeRequest{} - mi := &file_changes_proto_msgTypes[79] + mi := &file_changes_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5728,7 +5822,7 @@ func (x *DeleteChangeRequest) String() string { func (*DeleteChangeRequest) ProtoMessage() {} func (x *DeleteChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[79] + mi := &file_changes_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5741,7 +5835,7 @@ func (x *DeleteChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteChangeRequest.ProtoReflect.Descriptor instead. func (*DeleteChangeRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{79} + return file_changes_proto_rawDescGZIP(), []int{81} } func (x *DeleteChangeRequest) GetUUID() []byte { @@ -5761,7 +5855,7 @@ type ListChangesBySnapshotUUIDRequest struct { func (x *ListChangesBySnapshotUUIDRequest) Reset() { *x = ListChangesBySnapshotUUIDRequest{} - mi := &file_changes_proto_msgTypes[80] + mi := &file_changes_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5773,7 +5867,7 @@ func (x *ListChangesBySnapshotUUIDRequest) String() string { func (*ListChangesBySnapshotUUIDRequest) ProtoMessage() {} func (x *ListChangesBySnapshotUUIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[80] + mi := &file_changes_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5786,7 +5880,7 @@ func (x *ListChangesBySnapshotUUIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesBySnapshotUUIDRequest.ProtoReflect.Descriptor instead. func (*ListChangesBySnapshotUUIDRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{80} + return file_changes_proto_rawDescGZIP(), []int{82} } func (x *ListChangesBySnapshotUUIDRequest) GetUUID() []byte { @@ -5805,7 +5899,7 @@ type ListChangesBySnapshotUUIDResponse struct { func (x *ListChangesBySnapshotUUIDResponse) Reset() { *x = ListChangesBySnapshotUUIDResponse{} - mi := &file_changes_proto_msgTypes[81] + mi := &file_changes_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5817,7 +5911,7 @@ func (x *ListChangesBySnapshotUUIDResponse) String() string { func (*ListChangesBySnapshotUUIDResponse) ProtoMessage() {} func (x *ListChangesBySnapshotUUIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[81] + mi := &file_changes_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5830,7 +5924,7 @@ func (x *ListChangesBySnapshotUUIDResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListChangesBySnapshotUUIDResponse.ProtoReflect.Descriptor instead. func (*ListChangesBySnapshotUUIDResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{81} + return file_changes_proto_rawDescGZIP(), []int{83} } func (x *ListChangesBySnapshotUUIDResponse) GetChanges() []*Change { @@ -5848,7 +5942,7 @@ type DeleteChangeResponse struct { func (x *DeleteChangeResponse) Reset() { *x = DeleteChangeResponse{} - mi := &file_changes_proto_msgTypes[82] + mi := &file_changes_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5860,7 +5954,7 @@ func (x *DeleteChangeResponse) String() string { func (*DeleteChangeResponse) ProtoMessage() {} func (x *DeleteChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[82] + mi := &file_changes_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5873,7 +5967,7 @@ func (x *DeleteChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteChangeResponse.ProtoReflect.Descriptor instead. func (*DeleteChangeResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{82} + return file_changes_proto_rawDescGZIP(), []int{84} } type RefreshStateRequest struct { @@ -5884,7 +5978,7 @@ type RefreshStateRequest struct { func (x *RefreshStateRequest) Reset() { *x = RefreshStateRequest{} - mi := &file_changes_proto_msgTypes[83] + mi := &file_changes_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5896,7 +5990,7 @@ func (x *RefreshStateRequest) String() string { func (*RefreshStateRequest) ProtoMessage() {} func (x *RefreshStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[83] + mi := &file_changes_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5909,7 +6003,7 @@ func (x *RefreshStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshStateRequest.ProtoReflect.Descriptor instead. func (*RefreshStateRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{83} + return file_changes_proto_rawDescGZIP(), []int{85} } type RefreshStateResponse struct { @@ -5920,7 +6014,7 @@ type RefreshStateResponse struct { func (x *RefreshStateResponse) Reset() { *x = RefreshStateResponse{} - mi := &file_changes_proto_msgTypes[84] + mi := &file_changes_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5932,7 +6026,7 @@ func (x *RefreshStateResponse) String() string { func (*RefreshStateResponse) ProtoMessage() {} func (x *RefreshStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[84] + mi := &file_changes_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5945,7 +6039,7 @@ func (x *RefreshStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshStateResponse.ProtoReflect.Descriptor instead. func (*RefreshStateResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{84} + return file_changes_proto_rawDescGZIP(), []int{86} } type StartChangeRequest struct { @@ -5957,7 +6051,7 @@ type StartChangeRequest struct { func (x *StartChangeRequest) Reset() { *x = StartChangeRequest{} - mi := &file_changes_proto_msgTypes[85] + mi := &file_changes_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5969,7 +6063,7 @@ func (x *StartChangeRequest) String() string { func (*StartChangeRequest) ProtoMessage() {} func (x *StartChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[85] + mi := &file_changes_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5982,7 +6076,7 @@ func (x *StartChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartChangeRequest.ProtoReflect.Descriptor instead. func (*StartChangeRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{85} + return file_changes_proto_rawDescGZIP(), []int{87} } func (x *StartChangeRequest) GetChangeUUID() []byte { @@ -6003,7 +6097,7 @@ type StartChangeResponse struct { func (x *StartChangeResponse) Reset() { *x = StartChangeResponse{} - mi := &file_changes_proto_msgTypes[86] + mi := &file_changes_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6015,7 +6109,7 @@ func (x *StartChangeResponse) String() string { func (*StartChangeResponse) ProtoMessage() {} func (x *StartChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[86] + mi := &file_changes_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6028,7 +6122,7 @@ func (x *StartChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartChangeResponse.ProtoReflect.Descriptor instead. func (*StartChangeResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{86} + return file_changes_proto_rawDescGZIP(), []int{88} } func (x *StartChangeResponse) GetState() StartChangeResponse_State { @@ -6061,7 +6155,7 @@ type EndChangeRequest struct { func (x *EndChangeRequest) Reset() { *x = EndChangeRequest{} - mi := &file_changes_proto_msgTypes[87] + mi := &file_changes_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6073,7 +6167,7 @@ func (x *EndChangeRequest) String() string { func (*EndChangeRequest) ProtoMessage() {} func (x *EndChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[87] + mi := &file_changes_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6086,7 +6180,7 @@ func (x *EndChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EndChangeRequest.ProtoReflect.Descriptor instead. func (*EndChangeRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{87} + return file_changes_proto_rawDescGZIP(), []int{89} } func (x *EndChangeRequest) GetChangeUUID() []byte { @@ -6107,7 +6201,7 @@ type EndChangeResponse struct { func (x *EndChangeResponse) Reset() { *x = EndChangeResponse{} - mi := &file_changes_proto_msgTypes[88] + mi := &file_changes_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6119,7 +6213,7 @@ func (x *EndChangeResponse) String() string { func (*EndChangeResponse) ProtoMessage() {} func (x *EndChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[88] + mi := &file_changes_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6132,7 +6226,7 @@ func (x *EndChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EndChangeResponse.ProtoReflect.Descriptor instead. func (*EndChangeResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{88} + return file_changes_proto_rawDescGZIP(), []int{90} } func (x *EndChangeResponse) GetState() EndChangeResponse_State { @@ -6164,7 +6258,7 @@ type StartChangeSimpleResponse struct { func (x *StartChangeSimpleResponse) Reset() { *x = StartChangeSimpleResponse{} - mi := &file_changes_proto_msgTypes[89] + mi := &file_changes_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6176,7 +6270,7 @@ func (x *StartChangeSimpleResponse) String() string { func (*StartChangeSimpleResponse) ProtoMessage() {} func (x *StartChangeSimpleResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[89] + mi := &file_changes_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6189,7 +6283,7 @@ func (x *StartChangeSimpleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartChangeSimpleResponse.ProtoReflect.Descriptor instead. func (*StartChangeSimpleResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{89} + return file_changes_proto_rawDescGZIP(), []int{91} } type EndChangeSimpleResponse struct { @@ -6204,7 +6298,7 @@ type EndChangeSimpleResponse struct { func (x *EndChangeSimpleResponse) Reset() { *x = EndChangeSimpleResponse{} - mi := &file_changes_proto_msgTypes[90] + mi := &file_changes_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6216,7 +6310,7 @@ func (x *EndChangeSimpleResponse) String() string { func (*EndChangeSimpleResponse) ProtoMessage() {} func (x *EndChangeSimpleResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[90] + mi := &file_changes_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6229,7 +6323,7 @@ func (x *EndChangeSimpleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EndChangeSimpleResponse.ProtoReflect.Descriptor instead. func (*EndChangeSimpleResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{90} + return file_changes_proto_rawDescGZIP(), []int{92} } func (x *EndChangeSimpleResponse) GetQueued() bool { @@ -6259,7 +6353,7 @@ type Risk struct { func (x *Risk) Reset() { *x = Risk{} - mi := &file_changes_proto_msgTypes[91] + mi := &file_changes_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6271,7 +6365,7 @@ func (x *Risk) String() string { func (*Risk) ProtoMessage() {} func (x *Risk) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[91] + mi := &file_changes_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6284,7 +6378,7 @@ func (x *Risk) ProtoReflect() protoreflect.Message { // Deprecated: Use Risk.ProtoReflect.Descriptor instead. func (*Risk) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{91} + return file_changes_proto_rawDescGZIP(), []int{93} } func (x *Risk) GetUUID() []byte { @@ -6331,7 +6425,7 @@ type ChangeAnalysisStatus struct { func (x *ChangeAnalysisStatus) Reset() { *x = ChangeAnalysisStatus{} - mi := &file_changes_proto_msgTypes[92] + mi := &file_changes_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6343,7 +6437,7 @@ func (x *ChangeAnalysisStatus) String() string { func (*ChangeAnalysisStatus) ProtoMessage() {} func (x *ChangeAnalysisStatus) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[92] + mi := &file_changes_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6356,7 +6450,7 @@ func (x *ChangeAnalysisStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeAnalysisStatus.ProtoReflect.Descriptor instead. func (*ChangeAnalysisStatus) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{92} + return file_changes_proto_rawDescGZIP(), []int{94} } func (x *ChangeAnalysisStatus) GetStatus() ChangeAnalysisStatus_Status { @@ -6377,7 +6471,7 @@ type GenerateRiskFixRequest struct { func (x *GenerateRiskFixRequest) Reset() { *x = GenerateRiskFixRequest{} - mi := &file_changes_proto_msgTypes[93] + mi := &file_changes_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6389,7 +6483,7 @@ func (x *GenerateRiskFixRequest) String() string { func (*GenerateRiskFixRequest) ProtoMessage() {} func (x *GenerateRiskFixRequest) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[93] + mi := &file_changes_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6402,7 +6496,7 @@ func (x *GenerateRiskFixRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateRiskFixRequest.ProtoReflect.Descriptor instead. func (*GenerateRiskFixRequest) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{93} + return file_changes_proto_rawDescGZIP(), []int{95} } func (x *GenerateRiskFixRequest) GetRiskUUID() []byte { @@ -6422,7 +6516,7 @@ type GenerateRiskFixResponse struct { func (x *GenerateRiskFixResponse) Reset() { *x = GenerateRiskFixResponse{} - mi := &file_changes_proto_msgTypes[94] + mi := &file_changes_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6434,7 +6528,7 @@ func (x *GenerateRiskFixResponse) String() string { func (*GenerateRiskFixResponse) ProtoMessage() {} func (x *GenerateRiskFixResponse) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[94] + mi := &file_changes_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6447,7 +6541,7 @@ func (x *GenerateRiskFixResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateRiskFixResponse.ProtoReflect.Descriptor instead. func (*GenerateRiskFixResponse) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{94} + return file_changes_proto_rawDescGZIP(), []int{96} } func (x *GenerateRiskFixResponse) GetFixSuggestion() string { @@ -6477,7 +6571,7 @@ type ChangeMetadata_HealthChange struct { func (x *ChangeMetadata_HealthChange) Reset() { *x = ChangeMetadata_HealthChange{} - mi := &file_changes_proto_msgTypes[97] + mi := &file_changes_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6489,7 +6583,7 @@ func (x *ChangeMetadata_HealthChange) String() string { func (*ChangeMetadata_HealthChange) ProtoMessage() {} func (x *ChangeMetadata_HealthChange) ProtoReflect() protoreflect.Message { - mi := &file_changes_proto_msgTypes[97] + mi := &file_changes_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6502,7 +6596,7 @@ func (x *ChangeMetadata_HealthChange) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeMetadata_HealthChange.ProtoReflect.Descriptor instead. func (*ChangeMetadata_HealthChange) Descriptor() ([]byte, []int) { - return file_changes_proto_rawDescGZIP(), []int{58, 0} + return file_changes_proto_rawDescGZIP(), []int{60, 0} } func (x *ChangeMetadata_HealthChange) GetAdded() int32 { @@ -6719,7 +6813,13 @@ const file_changes_proto_rawDesc = "" + "\x1a_blastRadiusConfigOverrideB\x1f\n" + "\x1d_routineChangesConfigOverrideB$\n" + "\"_githubOrganisationProfileOverrideJ\x04\b\x04\x10\x05\"\x1d\n" + - "\x1bStartChangeAnalysisResponse\"\x96\x01\n" + + "\x1bStartChangeAnalysisResponse\"y\n" + + "\x18AddPlannedChangesRequest\x12\x1e\n" + + "\n" + + "changeUUID\x18\x01 \x01(\fR\n" + + "changeUUID\x12=\n" + + "\rchangingItems\x18\x02 \x03(\v2\x17.changes.MappedItemDiffR\rchangingItems\"\x1b\n" + + "\x19AddPlannedChangesResponse\"\x96\x01\n" + "\x16ListHomeChangesRequest\x122\n" + "\n" + "pagination\x18\x01 \x01(\v2\x12.PaginationRequestR\n" + @@ -7038,7 +7138,7 @@ const file_changes_proto_rawDesc = "" + "\x16CHANGE_STATUS_DEFINING\x10\x01\x12\x1b\n" + "\x17CHANGE_STATUS_HAPPENING\x10\x02\x12 \n" + "\x18CHANGE_STATUS_PROCESSING\x10\x03\x1a\x02\b\x01\x12\x16\n" + - "\x12CHANGE_STATUS_DONE\x10\x042\xad\x10\n" + + "\x12CHANGE_STATUS_DONE\x10\x042\x89\x11\n" + "\x0eChangesService\x12H\n" + "\vListChanges\x12\x1b.changes.ListChangesRequest\x1a\x1c.changes.ListChangesResponse\x12`\n" + "\x13ListChangesByStatus\x12#.changes.ListChangesByStatusRequest\x1a$.changes.ListChangesByStatusResponse\x12K\n" + @@ -7063,7 +7163,8 @@ const file_changes_proto_rawDesc = "" + "\x15PopulateChangeFilters\x12%.changes.PopulateChangeFiltersRequest\x1a&.changes.PopulateChangeFiltersResponse\x12T\n" + "\x0fGenerateRiskFix\x12\x1f.changes.GenerateRiskFixRequest\x1a .changes.GenerateRiskFixResponse\x12c\n" + "\x14GetHypothesesDetails\x12$.changes.GetHypothesesDetailsRequest\x1a%.changes.GetHypothesesDetailsResponse\x12W\n" + - "\x10GetChangeSignals\x12 .changes.GetChangeSignalsRequest\x1a!.changes.GetChangeSignalsResponse2\xfc\x04\n" + + "\x10GetChangeSignals\x12 .changes.GetChangeSignalsRequest\x1a!.changes.GetChangeSignalsResponse\x12Z\n" + + "\x11AddPlannedChanges\x12!.changes.AddPlannedChangesRequest\x1a\".changes.AddPlannedChangesResponse2\xfc\x04\n" + "\fLabelService\x12Q\n" + "\x0eListLabelRules\x12\x1e.changes.ListLabelRulesRequest\x1a\x1f.changes.ListLabelRulesResponse\x12T\n" + "\x0fCreateLabelRule\x12\x1f.changes.CreateLabelRuleRequest\x1a .changes.CreateLabelRuleResponse\x12K\n" + @@ -7086,7 +7187,7 @@ func file_changes_proto_rawDescGZIP() []byte { } var file_changes_proto_enumTypes = make([]protoimpl.EnumInfo, 12) -var file_changes_proto_msgTypes = make([]protoimpl.MessageInfo, 99) +var file_changes_proto_msgTypes = make([]protoimpl.MessageInfo, 101) var file_changes_proto_goTypes = []any{ (MappedItemTimelineStatus)(0), // 0: changes.MappedItemTimelineStatus (MappedItemMappingStatus)(0), // 1: changes.MappedItemMappingStatus @@ -7144,80 +7245,82 @@ var file_changes_proto_goTypes = []any{ (*MappedItemDiff)(nil), // 53: changes.MappedItemDiff (*StartChangeAnalysisRequest)(nil), // 54: changes.StartChangeAnalysisRequest (*StartChangeAnalysisResponse)(nil), // 55: changes.StartChangeAnalysisResponse - (*ListHomeChangesRequest)(nil), // 56: changes.ListHomeChangesRequest - (*ChangeFiltersRequest)(nil), // 57: changes.ChangeFiltersRequest - (*ListHomeChangesResponse)(nil), // 58: changes.ListHomeChangesResponse - (*PopulateChangeFiltersRequest)(nil), // 59: changes.PopulateChangeFiltersRequest - (*PopulateChangeFiltersResponse)(nil), // 60: changes.PopulateChangeFiltersResponse - (*ItemDiffSummary)(nil), // 61: changes.ItemDiffSummary - (*ItemDiff)(nil), // 62: changes.ItemDiff - (*EnrichedTags)(nil), // 63: changes.EnrichedTags - (*TagValue)(nil), // 64: changes.TagValue - (*UserTagValue)(nil), // 65: changes.UserTagValue - (*AutoTagValue)(nil), // 66: changes.AutoTagValue - (*Label)(nil), // 67: changes.Label - (*ChangeSummary)(nil), // 68: changes.ChangeSummary - (*Change)(nil), // 69: changes.Change - (*ChangeMetadata)(nil), // 70: changes.ChangeMetadata - (*ChangeProperties)(nil), // 71: changes.ChangeProperties - (*GithubChangeInfo)(nil), // 72: changes.GithubChangeInfo - (*ListChangesRequest)(nil), // 73: changes.ListChangesRequest - (*ListChangesResponse)(nil), // 74: changes.ListChangesResponse - (*ListChangesByStatusRequest)(nil), // 75: changes.ListChangesByStatusRequest - (*ListChangesByStatusResponse)(nil), // 76: changes.ListChangesByStatusResponse - (*CreateChangeRequest)(nil), // 77: changes.CreateChangeRequest - (*CreateChangeResponse)(nil), // 78: changes.CreateChangeResponse - (*GetChangeRequest)(nil), // 79: changes.GetChangeRequest - (*GetChangeByTicketLinkRequest)(nil), // 80: changes.GetChangeByTicketLinkRequest - (*GetChangeSummaryRequest)(nil), // 81: changes.GetChangeSummaryRequest - (*GetChangeSummaryResponse)(nil), // 82: changes.GetChangeSummaryResponse - (*GetChangeSignalsRequest)(nil), // 83: changes.GetChangeSignalsRequest - (*GetChangeSignalsResponse)(nil), // 84: changes.GetChangeSignalsResponse - (*GetChangeResponse)(nil), // 85: changes.GetChangeResponse - (*GetChangeRisksRequest)(nil), // 86: changes.GetChangeRisksRequest - (*ChangeRiskMetadata)(nil), // 87: changes.ChangeRiskMetadata - (*GetChangeRisksResponse)(nil), // 88: changes.GetChangeRisksResponse - (*UpdateChangeRequest)(nil), // 89: changes.UpdateChangeRequest - (*UpdateChangeResponse)(nil), // 90: changes.UpdateChangeResponse - (*DeleteChangeRequest)(nil), // 91: changes.DeleteChangeRequest - (*ListChangesBySnapshotUUIDRequest)(nil), // 92: changes.ListChangesBySnapshotUUIDRequest - (*ListChangesBySnapshotUUIDResponse)(nil), // 93: changes.ListChangesBySnapshotUUIDResponse - (*DeleteChangeResponse)(nil), // 94: changes.DeleteChangeResponse - (*RefreshStateRequest)(nil), // 95: changes.RefreshStateRequest - (*RefreshStateResponse)(nil), // 96: changes.RefreshStateResponse - (*StartChangeRequest)(nil), // 97: changes.StartChangeRequest - (*StartChangeResponse)(nil), // 98: changes.StartChangeResponse - (*EndChangeRequest)(nil), // 99: changes.EndChangeRequest - (*EndChangeResponse)(nil), // 100: changes.EndChangeResponse - (*StartChangeSimpleResponse)(nil), // 101: changes.StartChangeSimpleResponse - (*EndChangeSimpleResponse)(nil), // 102: changes.EndChangeSimpleResponse - (*Risk)(nil), // 103: changes.Risk - (*ChangeAnalysisStatus)(nil), // 104: changes.ChangeAnalysisStatus - (*GenerateRiskFixRequest)(nil), // 105: changes.GenerateRiskFixRequest - (*GenerateRiskFixResponse)(nil), // 106: changes.GenerateRiskFixResponse - nil, // 107: changes.EnrichedTags.TagValueEntry - nil, // 108: changes.ChangeSummary.TagsEntry - (*ChangeMetadata_HealthChange)(nil), // 109: changes.ChangeMetadata.HealthChange - nil, // 110: changes.ChangeProperties.TagsEntry - (*timestamppb.Timestamp)(nil), // 111: google.protobuf.Timestamp - (*Edge)(nil), // 112: Edge - (*Query)(nil), // 113: Query - (*QueryError)(nil), // 114: QueryError - (*BlastRadiusConfig)(nil), // 115: config.BlastRadiusConfig - (*RoutineChangesConfig)(nil), // 116: config.RoutineChangesConfig - (*GithubOrganisationProfile)(nil), // 117: config.GithubOrganisationProfile - (*PaginationRequest)(nil), // 118: PaginationRequest - (SortOrder)(0), // 119: SortOrder - (*PaginationResponse)(nil), // 120: PaginationResponse - (*Reference)(nil), // 121: Reference - (Health)(0), // 122: Health - (*Item)(nil), // 123: Item + (*AddPlannedChangesRequest)(nil), // 56: changes.AddPlannedChangesRequest + (*AddPlannedChangesResponse)(nil), // 57: changes.AddPlannedChangesResponse + (*ListHomeChangesRequest)(nil), // 58: changes.ListHomeChangesRequest + (*ChangeFiltersRequest)(nil), // 59: changes.ChangeFiltersRequest + (*ListHomeChangesResponse)(nil), // 60: changes.ListHomeChangesResponse + (*PopulateChangeFiltersRequest)(nil), // 61: changes.PopulateChangeFiltersRequest + (*PopulateChangeFiltersResponse)(nil), // 62: changes.PopulateChangeFiltersResponse + (*ItemDiffSummary)(nil), // 63: changes.ItemDiffSummary + (*ItemDiff)(nil), // 64: changes.ItemDiff + (*EnrichedTags)(nil), // 65: changes.EnrichedTags + (*TagValue)(nil), // 66: changes.TagValue + (*UserTagValue)(nil), // 67: changes.UserTagValue + (*AutoTagValue)(nil), // 68: changes.AutoTagValue + (*Label)(nil), // 69: changes.Label + (*ChangeSummary)(nil), // 70: changes.ChangeSummary + (*Change)(nil), // 71: changes.Change + (*ChangeMetadata)(nil), // 72: changes.ChangeMetadata + (*ChangeProperties)(nil), // 73: changes.ChangeProperties + (*GithubChangeInfo)(nil), // 74: changes.GithubChangeInfo + (*ListChangesRequest)(nil), // 75: changes.ListChangesRequest + (*ListChangesResponse)(nil), // 76: changes.ListChangesResponse + (*ListChangesByStatusRequest)(nil), // 77: changes.ListChangesByStatusRequest + (*ListChangesByStatusResponse)(nil), // 78: changes.ListChangesByStatusResponse + (*CreateChangeRequest)(nil), // 79: changes.CreateChangeRequest + (*CreateChangeResponse)(nil), // 80: changes.CreateChangeResponse + (*GetChangeRequest)(nil), // 81: changes.GetChangeRequest + (*GetChangeByTicketLinkRequest)(nil), // 82: changes.GetChangeByTicketLinkRequest + (*GetChangeSummaryRequest)(nil), // 83: changes.GetChangeSummaryRequest + (*GetChangeSummaryResponse)(nil), // 84: changes.GetChangeSummaryResponse + (*GetChangeSignalsRequest)(nil), // 85: changes.GetChangeSignalsRequest + (*GetChangeSignalsResponse)(nil), // 86: changes.GetChangeSignalsResponse + (*GetChangeResponse)(nil), // 87: changes.GetChangeResponse + (*GetChangeRisksRequest)(nil), // 88: changes.GetChangeRisksRequest + (*ChangeRiskMetadata)(nil), // 89: changes.ChangeRiskMetadata + (*GetChangeRisksResponse)(nil), // 90: changes.GetChangeRisksResponse + (*UpdateChangeRequest)(nil), // 91: changes.UpdateChangeRequest + (*UpdateChangeResponse)(nil), // 92: changes.UpdateChangeResponse + (*DeleteChangeRequest)(nil), // 93: changes.DeleteChangeRequest + (*ListChangesBySnapshotUUIDRequest)(nil), // 94: changes.ListChangesBySnapshotUUIDRequest + (*ListChangesBySnapshotUUIDResponse)(nil), // 95: changes.ListChangesBySnapshotUUIDResponse + (*DeleteChangeResponse)(nil), // 96: changes.DeleteChangeResponse + (*RefreshStateRequest)(nil), // 97: changes.RefreshStateRequest + (*RefreshStateResponse)(nil), // 98: changes.RefreshStateResponse + (*StartChangeRequest)(nil), // 99: changes.StartChangeRequest + (*StartChangeResponse)(nil), // 100: changes.StartChangeResponse + (*EndChangeRequest)(nil), // 101: changes.EndChangeRequest + (*EndChangeResponse)(nil), // 102: changes.EndChangeResponse + (*StartChangeSimpleResponse)(nil), // 103: changes.StartChangeSimpleResponse + (*EndChangeSimpleResponse)(nil), // 104: changes.EndChangeSimpleResponse + (*Risk)(nil), // 105: changes.Risk + (*ChangeAnalysisStatus)(nil), // 106: changes.ChangeAnalysisStatus + (*GenerateRiskFixRequest)(nil), // 107: changes.GenerateRiskFixRequest + (*GenerateRiskFixResponse)(nil), // 108: changes.GenerateRiskFixResponse + nil, // 109: changes.EnrichedTags.TagValueEntry + nil, // 110: changes.ChangeSummary.TagsEntry + (*ChangeMetadata_HealthChange)(nil), // 111: changes.ChangeMetadata.HealthChange + nil, // 112: changes.ChangeProperties.TagsEntry + (*timestamppb.Timestamp)(nil), // 113: google.protobuf.Timestamp + (*Edge)(nil), // 114: Edge + (*Query)(nil), // 115: Query + (*QueryError)(nil), // 116: QueryError + (*BlastRadiusConfig)(nil), // 117: config.BlastRadiusConfig + (*RoutineChangesConfig)(nil), // 118: config.RoutineChangesConfig + (*GithubOrganisationProfile)(nil), // 119: config.GithubOrganisationProfile + (*PaginationRequest)(nil), // 120: PaginationRequest + (SortOrder)(0), // 121: SortOrder + (*PaginationResponse)(nil), // 122: PaginationResponse + (*Reference)(nil), // 123: Reference + (Health)(0), // 124: Health + (*Item)(nil), // 125: Item } var file_changes_proto_depIdxs = []int32{ 13, // 0: changes.LabelRule.metadata:type_name -> changes.LabelRuleMetadata 14, // 1: changes.LabelRule.properties:type_name -> changes.LabelRuleProperties - 111, // 2: changes.LabelRuleMetadata.createdAt:type_name -> google.protobuf.Timestamp - 111, // 3: changes.LabelRuleMetadata.updatedAt:type_name -> google.protobuf.Timestamp + 113, // 2: changes.LabelRuleMetadata.createdAt:type_name -> google.protobuf.Timestamp + 113, // 3: changes.LabelRuleMetadata.updatedAt:type_name -> google.protobuf.Timestamp 12, // 4: changes.ListLabelRulesResponse.rules:type_name -> changes.LabelRule 14, // 5: changes.CreateLabelRuleRequest.properties:type_name -> changes.LabelRuleProperties 12, // 6: changes.CreateLabelRuleResponse.rule:type_name -> changes.LabelRule @@ -7225,16 +7328,16 @@ var file_changes_proto_depIdxs = []int32{ 14, // 8: changes.UpdateLabelRuleRequest.properties:type_name -> changes.LabelRuleProperties 12, // 9: changes.UpdateLabelRuleResponse.rule:type_name -> changes.LabelRule 14, // 10: changes.TestLabelRuleRequest.properties:type_name -> changes.LabelRuleProperties - 67, // 11: changes.TestLabelRuleResponse.label:type_name -> changes.Label - 111, // 12: changes.ReapplyLabelRuleInTimeRangeRequest.startAt:type_name -> google.protobuf.Timestamp - 111, // 13: changes.ReapplyLabelRuleInTimeRangeRequest.endAt:type_name -> google.protobuf.Timestamp + 69, // 11: changes.TestLabelRuleResponse.label:type_name -> changes.Label + 113, // 12: changes.ReapplyLabelRuleInTimeRangeRequest.startAt:type_name -> google.protobuf.Timestamp + 113, // 13: changes.ReapplyLabelRuleInTimeRangeRequest.endAt:type_name -> google.protobuf.Timestamp 33, // 14: changes.GetHypothesesDetailsResponse.hypotheses:type_name -> changes.HypothesesDetails 2, // 15: changes.HypothesesDetails.status:type_name -> changes.HypothesisStatus 29, // 16: changes.HypothesesDetails.knowledgeUsed:type_name -> changes.KnowledgeReference 36, // 17: changes.GetChangeTimelineV2Response.entries:type_name -> changes.ChangeTimelineEntryV2 3, // 18: changes.ChangeTimelineEntryV2.status:type_name -> changes.ChangeTimelineEntryStatus - 111, // 19: changes.ChangeTimelineEntryV2.startedAt:type_name -> google.protobuf.Timestamp - 111, // 20: changes.ChangeTimelineEntryV2.endedAt:type_name -> google.protobuf.Timestamp + 113, // 19: changes.ChangeTimelineEntryV2.startedAt:type_name -> google.protobuf.Timestamp + 113, // 20: changes.ChangeTimelineEntryV2.endedAt:type_name -> google.protobuf.Timestamp 39, // 21: changes.ChangeTimelineEntryV2.mappedItems:type_name -> changes.MappedItemsTimelineEntry 40, // 22: changes.ChangeTimelineEntryV2.calculatedBlastRadius:type_name -> changes.CalculatedBlastRadiusTimelineEntry 45, // 23: changes.ChangeTimelineEntryV2.calculatedRisks:type_name -> changes.CalculatedRisksTimelineEntry @@ -7250,152 +7353,155 @@ var file_changes_proto_depIdxs = []int32{ 44, // 33: changes.FormHypothesesTimelineEntry.hypotheses:type_name -> changes.HypothesisSummary 44, // 34: changes.InvestigateHypothesesTimelineEntry.hypotheses:type_name -> changes.HypothesisSummary 2, // 35: changes.HypothesisSummary.status:type_name -> changes.HypothesisStatus - 103, // 36: changes.CalculatedRisksTimelineEntry.risks:type_name -> changes.Risk - 67, // 37: changes.CalculatedLabelsTimelineEntry.labels:type_name -> changes.Label + 105, // 36: changes.CalculatedRisksTimelineEntry.risks:type_name -> changes.Risk + 69, // 37: changes.CalculatedLabelsTimelineEntry.labels:type_name -> changes.Label 48, // 38: changes.ChangeValidationTimelineEntry.validationChecklist:type_name -> changes.ChangeValidationCategory - 62, // 39: changes.GetDiffResponse.expectedItems:type_name -> changes.ItemDiff - 62, // 40: changes.GetDiffResponse.unexpectedItems:type_name -> changes.ItemDiff - 112, // 41: changes.GetDiffResponse.edges:type_name -> Edge - 62, // 42: changes.GetDiffResponse.missingItems:type_name -> changes.ItemDiff - 61, // 43: changes.ListChangingItemsSummaryResponse.items:type_name -> changes.ItemDiffSummary - 62, // 44: changes.MappedItemDiff.item:type_name -> changes.ItemDiff - 113, // 45: changes.MappedItemDiff.mappingQuery:type_name -> Query - 114, // 46: changes.MappedItemDiff.mappingError:type_name -> QueryError + 64, // 39: changes.GetDiffResponse.expectedItems:type_name -> changes.ItemDiff + 64, // 40: changes.GetDiffResponse.unexpectedItems:type_name -> changes.ItemDiff + 114, // 41: changes.GetDiffResponse.edges:type_name -> Edge + 64, // 42: changes.GetDiffResponse.missingItems:type_name -> changes.ItemDiff + 63, // 43: changes.ListChangingItemsSummaryResponse.items:type_name -> changes.ItemDiffSummary + 64, // 44: changes.MappedItemDiff.item:type_name -> changes.ItemDiff + 115, // 45: changes.MappedItemDiff.mappingQuery:type_name -> Query + 116, // 46: changes.MappedItemDiff.mappingError:type_name -> QueryError 1, // 47: changes.MappedItemDiff.mapping_status:type_name -> changes.MappedItemMappingStatus 53, // 48: changes.StartChangeAnalysisRequest.changingItems:type_name -> changes.MappedItemDiff - 115, // 49: changes.StartChangeAnalysisRequest.blastRadiusConfigOverride:type_name -> config.BlastRadiusConfig - 116, // 50: changes.StartChangeAnalysisRequest.routineChangesConfigOverride:type_name -> config.RoutineChangesConfig - 117, // 51: changes.StartChangeAnalysisRequest.githubOrganisationProfileOverride:type_name -> config.GithubOrganisationProfile + 117, // 49: changes.StartChangeAnalysisRequest.blastRadiusConfigOverride:type_name -> config.BlastRadiusConfig + 118, // 50: changes.StartChangeAnalysisRequest.routineChangesConfigOverride:type_name -> config.RoutineChangesConfig + 119, // 51: changes.StartChangeAnalysisRequest.githubOrganisationProfileOverride:type_name -> config.GithubOrganisationProfile 30, // 52: changes.StartChangeAnalysisRequest.knowledge:type_name -> changes.Knowledge - 118, // 53: changes.ListHomeChangesRequest.pagination:type_name -> PaginationRequest - 57, // 54: changes.ListHomeChangesRequest.filters:type_name -> changes.ChangeFiltersRequest - 10, // 55: changes.ChangeFiltersRequest.risks:type_name -> changes.Risk.Severity - 7, // 56: changes.ChangeFiltersRequest.statuses:type_name -> changes.ChangeStatus - 119, // 57: changes.ChangeFiltersRequest.sortOrder:type_name -> SortOrder - 68, // 58: changes.ListHomeChangesResponse.changes:type_name -> changes.ChangeSummary - 120, // 59: changes.ListHomeChangesResponse.pagination:type_name -> PaginationResponse - 121, // 60: changes.ItemDiffSummary.item:type_name -> Reference - 4, // 61: changes.ItemDiffSummary.status:type_name -> changes.ItemDiffStatus - 122, // 62: changes.ItemDiffSummary.healthAfter:type_name -> Health - 121, // 63: changes.ItemDiff.item:type_name -> Reference - 4, // 64: changes.ItemDiff.status:type_name -> changes.ItemDiffStatus - 123, // 65: changes.ItemDiff.before:type_name -> Item - 123, // 66: changes.ItemDiff.after:type_name -> Item - 121, // 67: changes.ItemDiff.mappedItemRef:type_name -> Reference - 107, // 68: changes.EnrichedTags.tagValue:type_name -> changes.EnrichedTags.TagValueEntry - 65, // 69: changes.TagValue.userTagValue:type_name -> changes.UserTagValue - 66, // 70: changes.TagValue.autoTagValue:type_name -> changes.AutoTagValue - 6, // 71: changes.Label.type:type_name -> changes.LabelType - 7, // 72: changes.ChangeSummary.status:type_name -> changes.ChangeStatus - 111, // 73: changes.ChangeSummary.createdAt:type_name -> google.protobuf.Timestamp - 108, // 74: changes.ChangeSummary.tags:type_name -> changes.ChangeSummary.TagsEntry - 63, // 75: changes.ChangeSummary.enrichedTags:type_name -> changes.EnrichedTags - 67, // 76: changes.ChangeSummary.labels:type_name -> changes.Label - 72, // 77: changes.ChangeSummary.githubChangeInfo:type_name -> changes.GithubChangeInfo - 70, // 78: changes.Change.metadata:type_name -> changes.ChangeMetadata - 71, // 79: changes.Change.properties:type_name -> changes.ChangeProperties - 111, // 80: changes.ChangeMetadata.createdAt:type_name -> google.protobuf.Timestamp - 111, // 81: changes.ChangeMetadata.updatedAt:type_name -> google.protobuf.Timestamp - 7, // 82: changes.ChangeMetadata.status:type_name -> changes.ChangeStatus - 109, // 83: changes.ChangeMetadata.UnknownHealthChange:type_name -> changes.ChangeMetadata.HealthChange - 109, // 84: changes.ChangeMetadata.OkHealthChange:type_name -> changes.ChangeMetadata.HealthChange - 109, // 85: changes.ChangeMetadata.WarningHealthChange:type_name -> changes.ChangeMetadata.HealthChange - 109, // 86: changes.ChangeMetadata.ErrorHealthChange:type_name -> changes.ChangeMetadata.HealthChange - 109, // 87: changes.ChangeMetadata.PendingHealthChange:type_name -> changes.ChangeMetadata.HealthChange - 72, // 88: changes.ChangeMetadata.githubChangeInfo:type_name -> changes.GithubChangeInfo - 104, // 89: changes.ChangeMetadata.changeAnalysisStatus:type_name -> changes.ChangeAnalysisStatus - 62, // 90: changes.ChangeProperties.plannedChanges:type_name -> changes.ItemDiff - 110, // 91: changes.ChangeProperties.tags:type_name -> changes.ChangeProperties.TagsEntry - 63, // 92: changes.ChangeProperties.enrichedTags:type_name -> changes.EnrichedTags - 67, // 93: changes.ChangeProperties.labels:type_name -> changes.Label - 69, // 94: changes.ListChangesResponse.changes:type_name -> changes.Change - 7, // 95: changes.ListChangesByStatusRequest.status:type_name -> changes.ChangeStatus - 69, // 96: changes.ListChangesByStatusResponse.changes:type_name -> changes.Change - 71, // 97: changes.CreateChangeRequest.properties:type_name -> changes.ChangeProperties - 69, // 98: changes.CreateChangeResponse.change:type_name -> changes.Change - 5, // 99: changes.GetChangeSummaryRequest.changeOutputFormat:type_name -> changes.ChangeOutputFormat - 10, // 100: changes.GetChangeSummaryRequest.riskSeverityFilter:type_name -> changes.Risk.Severity - 5, // 101: changes.GetChangeSignalsRequest.changeOutputFormat:type_name -> changes.ChangeOutputFormat - 69, // 102: changes.GetChangeResponse.change:type_name -> changes.Change - 104, // 103: changes.ChangeRiskMetadata.changeAnalysisStatus:type_name -> changes.ChangeAnalysisStatus - 103, // 104: changes.ChangeRiskMetadata.risks:type_name -> changes.Risk - 87, // 105: changes.GetChangeRisksResponse.changeRiskMetadata:type_name -> changes.ChangeRiskMetadata - 71, // 106: changes.UpdateChangeRequest.properties:type_name -> changes.ChangeProperties - 69, // 107: changes.UpdateChangeResponse.change:type_name -> changes.Change - 69, // 108: changes.ListChangesBySnapshotUUIDResponse.changes:type_name -> changes.Change - 8, // 109: changes.StartChangeResponse.state:type_name -> changes.StartChangeResponse.State - 9, // 110: changes.EndChangeResponse.state:type_name -> changes.EndChangeResponse.State - 10, // 111: changes.Risk.severity:type_name -> changes.Risk.Severity - 121, // 112: changes.Risk.relatedItems:type_name -> Reference - 11, // 113: changes.ChangeAnalysisStatus.status:type_name -> changes.ChangeAnalysisStatus.Status - 64, // 114: changes.EnrichedTags.TagValueEntry.value:type_name -> changes.TagValue - 73, // 115: changes.ChangesService.ListChanges:input_type -> changes.ListChangesRequest - 75, // 116: changes.ChangesService.ListChangesByStatus:input_type -> changes.ListChangesByStatusRequest - 77, // 117: changes.ChangesService.CreateChange:input_type -> changes.CreateChangeRequest - 79, // 118: changes.ChangesService.GetChange:input_type -> changes.GetChangeRequest - 80, // 119: changes.ChangesService.GetChangeByTicketLink:input_type -> changes.GetChangeByTicketLinkRequest - 81, // 120: changes.ChangesService.GetChangeSummary:input_type -> changes.GetChangeSummaryRequest - 34, // 121: changes.ChangesService.GetChangeTimelineV2:input_type -> changes.GetChangeTimelineV2Request - 86, // 122: changes.ChangesService.GetChangeRisks:input_type -> changes.GetChangeRisksRequest - 89, // 123: changes.ChangesService.UpdateChange:input_type -> changes.UpdateChangeRequest - 91, // 124: changes.ChangesService.DeleteChange:input_type -> changes.DeleteChangeRequest - 92, // 125: changes.ChangesService.ListChangesBySnapshotUUID:input_type -> changes.ListChangesBySnapshotUUIDRequest - 95, // 126: changes.ChangesService.RefreshState:input_type -> changes.RefreshStateRequest - 97, // 127: changes.ChangesService.StartChange:input_type -> changes.StartChangeRequest - 99, // 128: changes.ChangesService.EndChange:input_type -> changes.EndChangeRequest - 97, // 129: changes.ChangesService.StartChangeSimple:input_type -> changes.StartChangeRequest - 99, // 130: changes.ChangesService.EndChangeSimple:input_type -> changes.EndChangeRequest - 56, // 131: changes.ChangesService.ListHomeChanges:input_type -> changes.ListHomeChangesRequest - 54, // 132: changes.ChangesService.StartChangeAnalysis:input_type -> changes.StartChangeAnalysisRequest - 51, // 133: changes.ChangesService.ListChangingItemsSummary:input_type -> changes.ListChangingItemsSummaryRequest - 49, // 134: changes.ChangesService.GetDiff:input_type -> changes.GetDiffRequest - 59, // 135: changes.ChangesService.PopulateChangeFilters:input_type -> changes.PopulateChangeFiltersRequest - 105, // 136: changes.ChangesService.GenerateRiskFix:input_type -> changes.GenerateRiskFixRequest - 31, // 137: changes.ChangesService.GetHypothesesDetails:input_type -> changes.GetHypothesesDetailsRequest - 83, // 138: changes.ChangesService.GetChangeSignals:input_type -> changes.GetChangeSignalsRequest - 15, // 139: changes.LabelService.ListLabelRules:input_type -> changes.ListLabelRulesRequest - 17, // 140: changes.LabelService.CreateLabelRule:input_type -> changes.CreateLabelRuleRequest - 19, // 141: changes.LabelService.GetLabelRule:input_type -> changes.GetLabelRuleRequest - 21, // 142: changes.LabelService.UpdateLabelRule:input_type -> changes.UpdateLabelRuleRequest - 23, // 143: changes.LabelService.DeleteLabelRule:input_type -> changes.DeleteLabelRuleRequest - 25, // 144: changes.LabelService.TestLabelRule:input_type -> changes.TestLabelRuleRequest - 27, // 145: changes.LabelService.ReapplyLabelRuleInTimeRange:input_type -> changes.ReapplyLabelRuleInTimeRangeRequest - 74, // 146: changes.ChangesService.ListChanges:output_type -> changes.ListChangesResponse - 76, // 147: changes.ChangesService.ListChangesByStatus:output_type -> changes.ListChangesByStatusResponse - 78, // 148: changes.ChangesService.CreateChange:output_type -> changes.CreateChangeResponse - 85, // 149: changes.ChangesService.GetChange:output_type -> changes.GetChangeResponse - 85, // 150: changes.ChangesService.GetChangeByTicketLink:output_type -> changes.GetChangeResponse - 82, // 151: changes.ChangesService.GetChangeSummary:output_type -> changes.GetChangeSummaryResponse - 35, // 152: changes.ChangesService.GetChangeTimelineV2:output_type -> changes.GetChangeTimelineV2Response - 88, // 153: changes.ChangesService.GetChangeRisks:output_type -> changes.GetChangeRisksResponse - 90, // 154: changes.ChangesService.UpdateChange:output_type -> changes.UpdateChangeResponse - 94, // 155: changes.ChangesService.DeleteChange:output_type -> changes.DeleteChangeResponse - 93, // 156: changes.ChangesService.ListChangesBySnapshotUUID:output_type -> changes.ListChangesBySnapshotUUIDResponse - 96, // 157: changes.ChangesService.RefreshState:output_type -> changes.RefreshStateResponse - 98, // 158: changes.ChangesService.StartChange:output_type -> changes.StartChangeResponse - 100, // 159: changes.ChangesService.EndChange:output_type -> changes.EndChangeResponse - 101, // 160: changes.ChangesService.StartChangeSimple:output_type -> changes.StartChangeSimpleResponse - 102, // 161: changes.ChangesService.EndChangeSimple:output_type -> changes.EndChangeSimpleResponse - 58, // 162: changes.ChangesService.ListHomeChanges:output_type -> changes.ListHomeChangesResponse - 55, // 163: changes.ChangesService.StartChangeAnalysis:output_type -> changes.StartChangeAnalysisResponse - 52, // 164: changes.ChangesService.ListChangingItemsSummary:output_type -> changes.ListChangingItemsSummaryResponse - 50, // 165: changes.ChangesService.GetDiff:output_type -> changes.GetDiffResponse - 60, // 166: changes.ChangesService.PopulateChangeFilters:output_type -> changes.PopulateChangeFiltersResponse - 106, // 167: changes.ChangesService.GenerateRiskFix:output_type -> changes.GenerateRiskFixResponse - 32, // 168: changes.ChangesService.GetHypothesesDetails:output_type -> changes.GetHypothesesDetailsResponse - 84, // 169: changes.ChangesService.GetChangeSignals:output_type -> changes.GetChangeSignalsResponse - 16, // 170: changes.LabelService.ListLabelRules:output_type -> changes.ListLabelRulesResponse - 18, // 171: changes.LabelService.CreateLabelRule:output_type -> changes.CreateLabelRuleResponse - 20, // 172: changes.LabelService.GetLabelRule:output_type -> changes.GetLabelRuleResponse - 22, // 173: changes.LabelService.UpdateLabelRule:output_type -> changes.UpdateLabelRuleResponse - 24, // 174: changes.LabelService.DeleteLabelRule:output_type -> changes.DeleteLabelRuleResponse - 26, // 175: changes.LabelService.TestLabelRule:output_type -> changes.TestLabelRuleResponse - 28, // 176: changes.LabelService.ReapplyLabelRuleInTimeRange:output_type -> changes.ReapplyLabelRuleInTimeRangeResponse - 146, // [146:177] is the sub-list for method output_type - 115, // [115:146] is the sub-list for method input_type - 115, // [115:115] is the sub-list for extension type_name - 115, // [115:115] is the sub-list for extension extendee - 0, // [0:115] is the sub-list for field type_name + 53, // 53: changes.AddPlannedChangesRequest.changingItems:type_name -> changes.MappedItemDiff + 120, // 54: changes.ListHomeChangesRequest.pagination:type_name -> PaginationRequest + 59, // 55: changes.ListHomeChangesRequest.filters:type_name -> changes.ChangeFiltersRequest + 10, // 56: changes.ChangeFiltersRequest.risks:type_name -> changes.Risk.Severity + 7, // 57: changes.ChangeFiltersRequest.statuses:type_name -> changes.ChangeStatus + 121, // 58: changes.ChangeFiltersRequest.sortOrder:type_name -> SortOrder + 70, // 59: changes.ListHomeChangesResponse.changes:type_name -> changes.ChangeSummary + 122, // 60: changes.ListHomeChangesResponse.pagination:type_name -> PaginationResponse + 123, // 61: changes.ItemDiffSummary.item:type_name -> Reference + 4, // 62: changes.ItemDiffSummary.status:type_name -> changes.ItemDiffStatus + 124, // 63: changes.ItemDiffSummary.healthAfter:type_name -> Health + 123, // 64: changes.ItemDiff.item:type_name -> Reference + 4, // 65: changes.ItemDiff.status:type_name -> changes.ItemDiffStatus + 125, // 66: changes.ItemDiff.before:type_name -> Item + 125, // 67: changes.ItemDiff.after:type_name -> Item + 123, // 68: changes.ItemDiff.mappedItemRef:type_name -> Reference + 109, // 69: changes.EnrichedTags.tagValue:type_name -> changes.EnrichedTags.TagValueEntry + 67, // 70: changes.TagValue.userTagValue:type_name -> changes.UserTagValue + 68, // 71: changes.TagValue.autoTagValue:type_name -> changes.AutoTagValue + 6, // 72: changes.Label.type:type_name -> changes.LabelType + 7, // 73: changes.ChangeSummary.status:type_name -> changes.ChangeStatus + 113, // 74: changes.ChangeSummary.createdAt:type_name -> google.protobuf.Timestamp + 110, // 75: changes.ChangeSummary.tags:type_name -> changes.ChangeSummary.TagsEntry + 65, // 76: changes.ChangeSummary.enrichedTags:type_name -> changes.EnrichedTags + 69, // 77: changes.ChangeSummary.labels:type_name -> changes.Label + 74, // 78: changes.ChangeSummary.githubChangeInfo:type_name -> changes.GithubChangeInfo + 72, // 79: changes.Change.metadata:type_name -> changes.ChangeMetadata + 73, // 80: changes.Change.properties:type_name -> changes.ChangeProperties + 113, // 81: changes.ChangeMetadata.createdAt:type_name -> google.protobuf.Timestamp + 113, // 82: changes.ChangeMetadata.updatedAt:type_name -> google.protobuf.Timestamp + 7, // 83: changes.ChangeMetadata.status:type_name -> changes.ChangeStatus + 111, // 84: changes.ChangeMetadata.UnknownHealthChange:type_name -> changes.ChangeMetadata.HealthChange + 111, // 85: changes.ChangeMetadata.OkHealthChange:type_name -> changes.ChangeMetadata.HealthChange + 111, // 86: changes.ChangeMetadata.WarningHealthChange:type_name -> changes.ChangeMetadata.HealthChange + 111, // 87: changes.ChangeMetadata.ErrorHealthChange:type_name -> changes.ChangeMetadata.HealthChange + 111, // 88: changes.ChangeMetadata.PendingHealthChange:type_name -> changes.ChangeMetadata.HealthChange + 74, // 89: changes.ChangeMetadata.githubChangeInfo:type_name -> changes.GithubChangeInfo + 106, // 90: changes.ChangeMetadata.changeAnalysisStatus:type_name -> changes.ChangeAnalysisStatus + 64, // 91: changes.ChangeProperties.plannedChanges:type_name -> changes.ItemDiff + 112, // 92: changes.ChangeProperties.tags:type_name -> changes.ChangeProperties.TagsEntry + 65, // 93: changes.ChangeProperties.enrichedTags:type_name -> changes.EnrichedTags + 69, // 94: changes.ChangeProperties.labels:type_name -> changes.Label + 71, // 95: changes.ListChangesResponse.changes:type_name -> changes.Change + 7, // 96: changes.ListChangesByStatusRequest.status:type_name -> changes.ChangeStatus + 71, // 97: changes.ListChangesByStatusResponse.changes:type_name -> changes.Change + 73, // 98: changes.CreateChangeRequest.properties:type_name -> changes.ChangeProperties + 71, // 99: changes.CreateChangeResponse.change:type_name -> changes.Change + 5, // 100: changes.GetChangeSummaryRequest.changeOutputFormat:type_name -> changes.ChangeOutputFormat + 10, // 101: changes.GetChangeSummaryRequest.riskSeverityFilter:type_name -> changes.Risk.Severity + 5, // 102: changes.GetChangeSignalsRequest.changeOutputFormat:type_name -> changes.ChangeOutputFormat + 71, // 103: changes.GetChangeResponse.change:type_name -> changes.Change + 106, // 104: changes.ChangeRiskMetadata.changeAnalysisStatus:type_name -> changes.ChangeAnalysisStatus + 105, // 105: changes.ChangeRiskMetadata.risks:type_name -> changes.Risk + 89, // 106: changes.GetChangeRisksResponse.changeRiskMetadata:type_name -> changes.ChangeRiskMetadata + 73, // 107: changes.UpdateChangeRequest.properties:type_name -> changes.ChangeProperties + 71, // 108: changes.UpdateChangeResponse.change:type_name -> changes.Change + 71, // 109: changes.ListChangesBySnapshotUUIDResponse.changes:type_name -> changes.Change + 8, // 110: changes.StartChangeResponse.state:type_name -> changes.StartChangeResponse.State + 9, // 111: changes.EndChangeResponse.state:type_name -> changes.EndChangeResponse.State + 10, // 112: changes.Risk.severity:type_name -> changes.Risk.Severity + 123, // 113: changes.Risk.relatedItems:type_name -> Reference + 11, // 114: changes.ChangeAnalysisStatus.status:type_name -> changes.ChangeAnalysisStatus.Status + 66, // 115: changes.EnrichedTags.TagValueEntry.value:type_name -> changes.TagValue + 75, // 116: changes.ChangesService.ListChanges:input_type -> changes.ListChangesRequest + 77, // 117: changes.ChangesService.ListChangesByStatus:input_type -> changes.ListChangesByStatusRequest + 79, // 118: changes.ChangesService.CreateChange:input_type -> changes.CreateChangeRequest + 81, // 119: changes.ChangesService.GetChange:input_type -> changes.GetChangeRequest + 82, // 120: changes.ChangesService.GetChangeByTicketLink:input_type -> changes.GetChangeByTicketLinkRequest + 83, // 121: changes.ChangesService.GetChangeSummary:input_type -> changes.GetChangeSummaryRequest + 34, // 122: changes.ChangesService.GetChangeTimelineV2:input_type -> changes.GetChangeTimelineV2Request + 88, // 123: changes.ChangesService.GetChangeRisks:input_type -> changes.GetChangeRisksRequest + 91, // 124: changes.ChangesService.UpdateChange:input_type -> changes.UpdateChangeRequest + 93, // 125: changes.ChangesService.DeleteChange:input_type -> changes.DeleteChangeRequest + 94, // 126: changes.ChangesService.ListChangesBySnapshotUUID:input_type -> changes.ListChangesBySnapshotUUIDRequest + 97, // 127: changes.ChangesService.RefreshState:input_type -> changes.RefreshStateRequest + 99, // 128: changes.ChangesService.StartChange:input_type -> changes.StartChangeRequest + 101, // 129: changes.ChangesService.EndChange:input_type -> changes.EndChangeRequest + 99, // 130: changes.ChangesService.StartChangeSimple:input_type -> changes.StartChangeRequest + 101, // 131: changes.ChangesService.EndChangeSimple:input_type -> changes.EndChangeRequest + 58, // 132: changes.ChangesService.ListHomeChanges:input_type -> changes.ListHomeChangesRequest + 54, // 133: changes.ChangesService.StartChangeAnalysis:input_type -> changes.StartChangeAnalysisRequest + 51, // 134: changes.ChangesService.ListChangingItemsSummary:input_type -> changes.ListChangingItemsSummaryRequest + 49, // 135: changes.ChangesService.GetDiff:input_type -> changes.GetDiffRequest + 61, // 136: changes.ChangesService.PopulateChangeFilters:input_type -> changes.PopulateChangeFiltersRequest + 107, // 137: changes.ChangesService.GenerateRiskFix:input_type -> changes.GenerateRiskFixRequest + 31, // 138: changes.ChangesService.GetHypothesesDetails:input_type -> changes.GetHypothesesDetailsRequest + 85, // 139: changes.ChangesService.GetChangeSignals:input_type -> changes.GetChangeSignalsRequest + 56, // 140: changes.ChangesService.AddPlannedChanges:input_type -> changes.AddPlannedChangesRequest + 15, // 141: changes.LabelService.ListLabelRules:input_type -> changes.ListLabelRulesRequest + 17, // 142: changes.LabelService.CreateLabelRule:input_type -> changes.CreateLabelRuleRequest + 19, // 143: changes.LabelService.GetLabelRule:input_type -> changes.GetLabelRuleRequest + 21, // 144: changes.LabelService.UpdateLabelRule:input_type -> changes.UpdateLabelRuleRequest + 23, // 145: changes.LabelService.DeleteLabelRule:input_type -> changes.DeleteLabelRuleRequest + 25, // 146: changes.LabelService.TestLabelRule:input_type -> changes.TestLabelRuleRequest + 27, // 147: changes.LabelService.ReapplyLabelRuleInTimeRange:input_type -> changes.ReapplyLabelRuleInTimeRangeRequest + 76, // 148: changes.ChangesService.ListChanges:output_type -> changes.ListChangesResponse + 78, // 149: changes.ChangesService.ListChangesByStatus:output_type -> changes.ListChangesByStatusResponse + 80, // 150: changes.ChangesService.CreateChange:output_type -> changes.CreateChangeResponse + 87, // 151: changes.ChangesService.GetChange:output_type -> changes.GetChangeResponse + 87, // 152: changes.ChangesService.GetChangeByTicketLink:output_type -> changes.GetChangeResponse + 84, // 153: changes.ChangesService.GetChangeSummary:output_type -> changes.GetChangeSummaryResponse + 35, // 154: changes.ChangesService.GetChangeTimelineV2:output_type -> changes.GetChangeTimelineV2Response + 90, // 155: changes.ChangesService.GetChangeRisks:output_type -> changes.GetChangeRisksResponse + 92, // 156: changes.ChangesService.UpdateChange:output_type -> changes.UpdateChangeResponse + 96, // 157: changes.ChangesService.DeleteChange:output_type -> changes.DeleteChangeResponse + 95, // 158: changes.ChangesService.ListChangesBySnapshotUUID:output_type -> changes.ListChangesBySnapshotUUIDResponse + 98, // 159: changes.ChangesService.RefreshState:output_type -> changes.RefreshStateResponse + 100, // 160: changes.ChangesService.StartChange:output_type -> changes.StartChangeResponse + 102, // 161: changes.ChangesService.EndChange:output_type -> changes.EndChangeResponse + 103, // 162: changes.ChangesService.StartChangeSimple:output_type -> changes.StartChangeSimpleResponse + 104, // 163: changes.ChangesService.EndChangeSimple:output_type -> changes.EndChangeSimpleResponse + 60, // 164: changes.ChangesService.ListHomeChanges:output_type -> changes.ListHomeChangesResponse + 55, // 165: changes.ChangesService.StartChangeAnalysis:output_type -> changes.StartChangeAnalysisResponse + 52, // 166: changes.ChangesService.ListChangingItemsSummary:output_type -> changes.ListChangingItemsSummaryResponse + 50, // 167: changes.ChangesService.GetDiff:output_type -> changes.GetDiffResponse + 62, // 168: changes.ChangesService.PopulateChangeFilters:output_type -> changes.PopulateChangeFiltersResponse + 108, // 169: changes.ChangesService.GenerateRiskFix:output_type -> changes.GenerateRiskFixResponse + 32, // 170: changes.ChangesService.GetHypothesesDetails:output_type -> changes.GetHypothesesDetailsResponse + 86, // 171: changes.ChangesService.GetChangeSignals:output_type -> changes.GetChangeSignalsResponse + 57, // 172: changes.ChangesService.AddPlannedChanges:output_type -> changes.AddPlannedChangesResponse + 16, // 173: changes.LabelService.ListLabelRules:output_type -> changes.ListLabelRulesResponse + 18, // 174: changes.LabelService.CreateLabelRule:output_type -> changes.CreateLabelRuleResponse + 20, // 175: changes.LabelService.GetLabelRule:output_type -> changes.GetLabelRuleResponse + 22, // 176: changes.LabelService.UpdateLabelRule:output_type -> changes.UpdateLabelRuleResponse + 24, // 177: changes.LabelService.DeleteLabelRule:output_type -> changes.DeleteLabelRuleResponse + 26, // 178: changes.LabelService.TestLabelRule:output_type -> changes.TestLabelRuleResponse + 28, // 179: changes.LabelService.ReapplyLabelRuleInTimeRange:output_type -> changes.ReapplyLabelRuleInTimeRangeResponse + 148, // [148:180] is the sub-list for method output_type + 116, // [116:148] is the sub-list for method input_type + 116, // [116:116] is the sub-list for extension type_name + 116, // [116:116] is the sub-list for extension extendee + 0, // [0:116] is the sub-list for field type_name } func init() { file_changes_proto_init() } @@ -7422,21 +7528,21 @@ func file_changes_proto_init() { file_changes_proto_msgTypes[26].OneofWrappers = []any{} file_changes_proto_msgTypes[41].OneofWrappers = []any{} file_changes_proto_msgTypes[42].OneofWrappers = []any{} - file_changes_proto_msgTypes[44].OneofWrappers = []any{} - file_changes_proto_msgTypes[45].OneofWrappers = []any{} - file_changes_proto_msgTypes[50].OneofWrappers = []any{} - file_changes_proto_msgTypes[52].OneofWrappers = []any{ + file_changes_proto_msgTypes[46].OneofWrappers = []any{} + file_changes_proto_msgTypes[47].OneofWrappers = []any{} + file_changes_proto_msgTypes[52].OneofWrappers = []any{} + file_changes_proto_msgTypes[54].OneofWrappers = []any{ (*TagValue_UserTagValue)(nil), (*TagValue_AutoTagValue)(nil), } - file_changes_proto_msgTypes[58].OneofWrappers = []any{} + file_changes_proto_msgTypes[60].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_changes_proto_rawDesc), len(file_changes_proto_rawDesc)), NumEnums: 12, - NumMessages: 99, + NumMessages: 101, NumExtensions: 0, NumServices: 2, }, diff --git a/go/sdp-go/sdpconnect/changes.connect.go b/go/sdp-go/sdpconnect/changes.connect.go index 2988499a..e9c7978e 100644 --- a/go/sdp-go/sdpconnect/changes.connect.go +++ b/go/sdp-go/sdpconnect/changes.connect.go @@ -106,6 +106,9 @@ const ( // ChangesServiceGetChangeSignalsProcedure is the fully-qualified name of the ChangesService's // GetChangeSignals RPC. ChangesServiceGetChangeSignalsProcedure = "/changes.ChangesService/GetChangeSignals" + // ChangesServiceAddPlannedChangesProcedure is the fully-qualified name of the ChangesService's + // AddPlannedChanges RPC. + ChangesServiceAddPlannedChangesProcedure = "/changes.ChangesService/AddPlannedChanges" // LabelServiceListLabelRulesProcedure is the fully-qualified name of the LabelService's // ListLabelRules RPC. LabelServiceListLabelRulesProcedure = "/changes.LabelService/ListLabelRules" @@ -199,6 +202,11 @@ type ChangesServiceClient interface { // - Individual custom signals // This is similar to GetChangeSummary but focused on signals data GetChangeSignals(context.Context, *connect.Request[sdp_go.GetChangeSignalsRequest]) (*connect.Response[sdp_go.GetChangeSignalsResponse], error) + // Appends planned changes to an existing change without starting analysis. + // The change must be in CHANGE_STATUS_DEFINING. Each call inserts a new batch + // of items; call StartChangeAnalysis (with empty changingItems) to trigger + // analysis on all accumulated items. + AddPlannedChanges(context.Context, *connect.Request[sdp_go.AddPlannedChangesRequest]) (*connect.Response[sdp_go.AddPlannedChangesResponse], error) } // NewChangesServiceClient constructs a client for the changes.ChangesService service. By default, @@ -356,6 +364,12 @@ func NewChangesServiceClient(httpClient connect.HTTPClient, baseURL string, opts connect.WithSchema(changesServiceMethods.ByName("GetChangeSignals")), connect.WithClientOptions(opts...), ), + addPlannedChanges: connect.NewClient[sdp_go.AddPlannedChangesRequest, sdp_go.AddPlannedChangesResponse]( + httpClient, + baseURL+ChangesServiceAddPlannedChangesProcedure, + connect.WithSchema(changesServiceMethods.ByName("AddPlannedChanges")), + connect.WithClientOptions(opts...), + ), } } @@ -385,6 +399,7 @@ type changesServiceClient struct { generateRiskFix *connect.Client[sdp_go.GenerateRiskFixRequest, sdp_go.GenerateRiskFixResponse] getHypothesesDetails *connect.Client[sdp_go.GetHypothesesDetailsRequest, sdp_go.GetHypothesesDetailsResponse] getChangeSignals *connect.Client[sdp_go.GetChangeSignalsRequest, sdp_go.GetChangeSignalsResponse] + addPlannedChanges *connect.Client[sdp_go.AddPlannedChangesRequest, sdp_go.AddPlannedChangesResponse] } // ListChanges calls changes.ChangesService.ListChanges. @@ -507,6 +522,11 @@ func (c *changesServiceClient) GetChangeSignals(ctx context.Context, req *connec return c.getChangeSignals.CallUnary(ctx, req) } +// AddPlannedChanges calls changes.ChangesService.AddPlannedChanges. +func (c *changesServiceClient) AddPlannedChanges(ctx context.Context, req *connect.Request[sdp_go.AddPlannedChangesRequest]) (*connect.Response[sdp_go.AddPlannedChangesResponse], error) { + return c.addPlannedChanges.CallUnary(ctx, req) +} + // ChangesServiceHandler is an implementation of the changes.ChangesService service. type ChangesServiceHandler interface { // Lists all changes @@ -577,6 +597,11 @@ type ChangesServiceHandler interface { // - Individual custom signals // This is similar to GetChangeSummary but focused on signals data GetChangeSignals(context.Context, *connect.Request[sdp_go.GetChangeSignalsRequest]) (*connect.Response[sdp_go.GetChangeSignalsResponse], error) + // Appends planned changes to an existing change without starting analysis. + // The change must be in CHANGE_STATUS_DEFINING. Each call inserts a new batch + // of items; call StartChangeAnalysis (with empty changingItems) to trigger + // analysis on all accumulated items. + AddPlannedChanges(context.Context, *connect.Request[sdp_go.AddPlannedChangesRequest]) (*connect.Response[sdp_go.AddPlannedChangesResponse], error) } // NewChangesServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -730,6 +755,12 @@ func NewChangesServiceHandler(svc ChangesServiceHandler, opts ...connect.Handler connect.WithSchema(changesServiceMethods.ByName("GetChangeSignals")), connect.WithHandlerOptions(opts...), ) + changesServiceAddPlannedChangesHandler := connect.NewUnaryHandler( + ChangesServiceAddPlannedChangesProcedure, + svc.AddPlannedChanges, + connect.WithSchema(changesServiceMethods.ByName("AddPlannedChanges")), + connect.WithHandlerOptions(opts...), + ) return "/changes.ChangesService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case ChangesServiceListChangesProcedure: @@ -780,6 +811,8 @@ func NewChangesServiceHandler(svc ChangesServiceHandler, opts ...connect.Handler changesServiceGetHypothesesDetailsHandler.ServeHTTP(w, r) case ChangesServiceGetChangeSignalsProcedure: changesServiceGetChangeSignalsHandler.ServeHTTP(w, r) + case ChangesServiceAddPlannedChangesProcedure: + changesServiceAddPlannedChangesHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -885,6 +918,10 @@ func (UnimplementedChangesServiceHandler) GetChangeSignals(context.Context, *con return nil, connect.NewError(connect.CodeUnimplemented, errors.New("changes.ChangesService.GetChangeSignals is not implemented")) } +func (UnimplementedChangesServiceHandler) AddPlannedChanges(context.Context, *connect.Request[sdp_go.AddPlannedChangesRequest]) (*connect.Response[sdp_go.AddPlannedChangesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("changes.ChangesService.AddPlannedChanges is not implemented")) +} + // LabelServiceClient is a client for the changes.LabelService service. type LabelServiceClient interface { // Lists all label rules for an account From 0c3510887829939002f4a2d738d64664e6961433 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 12 Mar 2026 10:11:16 +0100 Subject: [PATCH 14/18] [ENG-3104] Add --no-start flag to submit-plan and new start-analysis command (#4229) ## Summary - Add `--no-start` flag to `submit-plan` so it stores planned changes via `AddPlannedChanges` without triggering analysis, enabling multi-plan workflows (e.g., Atlantis parallel planning) - Add new `start-analysis` subcommand that triggers analysis on a change with previously accumulated planned items, with optional `--wait` to block until completion - Extract shared analysis flags (`addAnalysisFlags`), config builder (`buildAnalysisConfig`), and analysis polling (`waitForChangeAnalysis`) into reusable helpers ## Linear Ticket - **Ticket**: [ENG-3104](https://linear.app/overmind/issue/ENG-3104/phase-2-cli-submit-plan-no-start-start-analysis) -- Phase 2: CLI -- submit-plan --no-start + start-analysis - **Purpose**: Enable CI systems that produce multiple Terraform plans in parallel to submit each plan independently and then trigger a single unified analysis - **Project**: Multi-Plan Submission & GitHub App PR Commenting ## Changes **Core feature** (reviewers should focus here): - `cli/cmd/changes_submit_plan.go` -- branches on `--no-start`: calls `AddPlannedChanges` RPC when set, `StartChangeAnalysis` when not. Refactored to use shared `buildAnalysisConfig`. - `cli/cmd/changes_start_analysis.go` -- new command: resolves change via `--ticket-link`/`--uuid`/`--change`, builds analysis config, calls `StartChangeAnalysis` with empty `changingItems` (backend loads pre-stored items). Supports `--wait`. - `cli/cmd/flags.go` -- new `addAnalysisFlags()`, `AnalysisConfig` struct, `buildAnalysisConfig()`, and `waitForChangeAnalysis()` shared helper. **Refactoring:** - `cli/cmd/changes_get_change.go`, `cli/cmd/changes_get_signals.go`, `cli/cmd/changes_start_change.go` -- replaced inline analysis-polling loops with shared `waitForChangeAnalysis()`. **Tests:** - `cli/cmd/changes_start_analysis_test.go` -- tests for `addAnalysisFlags` registration, `buildAnalysisConfig` with various flag combinations, `startAnalysisCmd` flag presence, and `submitPlanCmd` `--no-start` flag registration. **Unrelated:** - `.cursor/commands/create-project-plan.md` -- adds a model gate requiring MAX mode (separate from Phase 2 work). ## Deviations from Approved Plan - **`waitForChangeAnalysis` shared helper (addition)**: The plan did not mention extracting the analysis polling loop. The implementation extracted the duplicated poll-until-done loop from `get-change`, `get-signals`, and `start-change` into a shared `waitForChangeAnalysis()` in `flags.go`. This reduces ~120 lines of duplication across 3 files and is needed by `start-analysis --wait`. - **UTM tracking on change URLs**: `submit-plan` and `start-analysis` append `?utm_source=cli&cli_version=` to their change URL output. This follows the established pattern from ENG-3047 Phase 1 (UTM Attribution on External Links) and was applied to the new code paths rather than leaving them inconsistent with the rest of the CLI. --------- Co-authored-by: Cursor Agent Co-authored-by: David Schmitt GitOrigin-RevId: 1165783ff4d163d05efd654abe5cd6245657fe53 --- cmd/changes_get_change.go | 48 +------ cmd/changes_get_signals.go | 48 +------ cmd/changes_start_analysis.go | 99 +++++++++++++ cmd/changes_start_analysis_test.go | 220 +++++++++++++++++++++++++++++ cmd/changes_start_change.go | 47 +----- cmd/changes_submit_plan.go | 97 ++++++------- cmd/flags.go | 129 +++++++++++++++++ 7 files changed, 497 insertions(+), 191 deletions(-) create mode 100644 cmd/changes_start_analysis.go create mode 100644 cmd/changes_start_analysis_test.go diff --git a/cmd/changes_get_change.go b/cmd/changes_get_change.go index 7bf1a03d..fbbeff12 100644 --- a/cmd/changes_get_change.go +++ b/cmd/changes_get_change.go @@ -5,7 +5,6 @@ import ( "fmt" "slices" "strings" - "time" "connectrpc.com/connect" "github.com/overmindtech/cli/go/sdp-go" @@ -72,51 +71,10 @@ func GetChange(cmd *cobra.Command, args []string) error { } client := AuthenticatedChangesClient(ctx, oi) -fetch: - for { - changeRes, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ - Msg: &sdp.GetChangeRequest{ - UUID: changeUuid[:], - }, - }) - if err != nil || changeRes.Msg == nil || changeRes.Msg.GetChange() == nil { - return loggedError{ - err: err, - fields: lf, - message: "failed to get change", - } - } - ch := changeRes.Msg.GetChange() - md := ch.GetMetadata() - if md == nil || md.GetChangeAnalysisStatus() == nil { - return loggedError{ - err: fmt.Errorf("change metadata or change analysis status is nil"), - fields: lf, - message: "failed to get change", - } - } - status := md.GetChangeAnalysisStatus().GetStatus() - switch status { - case sdp.ChangeAnalysisStatus_STATUS_DONE, sdp.ChangeAnalysisStatus_STATUS_SKIPPED: - break fetch - case sdp.ChangeAnalysisStatus_STATUS_ERROR: - return loggedError{ - err: fmt.Errorf("change analysis completed with error status"), - fields: lf, - message: "change analysis failed", - } - case sdp.ChangeAnalysisStatus_STATUS_UNSPECIFIED, sdp.ChangeAnalysisStatus_STATUS_INPROGRESS: - log.WithContext(ctx).WithFields(lf).WithField("status", status.String()).Info("Waiting for change analysis to complete") - } - time.Sleep(3 * time.Second) - if ctx.Err() != nil { - return loggedError{ - err: ctx.Err(), - fields: lf, - message: "context cancelled", - } - } + if err := waitForChangeAnalysis(ctx, client, changeUuid, lf); err != nil { + return err } + app, _ = strings.CutSuffix(app, "/") // get the change var format sdp.ChangeOutputFormat diff --git a/cmd/changes_get_signals.go b/cmd/changes_get_signals.go index 03bf9ff3..2a84a139 100644 --- a/cmd/changes_get_signals.go +++ b/cmd/changes_get_signals.go @@ -3,7 +3,6 @@ package cmd import ( _ "embed" "fmt" - "time" "connectrpc.com/connect" "github.com/overmindtech/cli/go/sdp-go" @@ -55,51 +54,10 @@ func GetSignals(cmd *cobra.Command, args []string) error { } client := AuthenticatedChangesClient(ctx, oi) -fetch: - for { - changeRes, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ - Msg: &sdp.GetChangeRequest{ - UUID: changeUuid[:], - }, - }) - if err != nil || changeRes.Msg == nil || changeRes.Msg.GetChange() == nil { - return loggedError{ - err: err, - fields: lf, - message: "failed to get change", - } - } - ch := changeRes.Msg.GetChange() - md := ch.GetMetadata() - if md == nil || md.GetChangeAnalysisStatus() == nil { - return loggedError{ - err: fmt.Errorf("change metadata or change analysis status is nil"), - fields: lf, - message: "failed to get change", - } - } - status := md.GetChangeAnalysisStatus().GetStatus() - switch status { - case sdp.ChangeAnalysisStatus_STATUS_DONE, sdp.ChangeAnalysisStatus_STATUS_SKIPPED: - break fetch - case sdp.ChangeAnalysisStatus_STATUS_ERROR: - return loggedError{ - err: fmt.Errorf("change analysis completed with error status"), - fields: lf, - message: "change analysis failed", - } - case sdp.ChangeAnalysisStatus_STATUS_UNSPECIFIED, sdp.ChangeAnalysisStatus_STATUS_INPROGRESS: - log.WithContext(ctx).WithFields(lf).WithField("status", status.String()).Info("Waiting for change analysis to complete") - } - time.Sleep(3 * time.Second) - if ctx.Err() != nil { - return loggedError{ - err: ctx.Err(), - fields: lf, - message: "context cancelled", - } - } + if err := waitForChangeAnalysis(ctx, client, changeUuid, lf); err != nil { + return err } + // get the change signals var format sdp.ChangeOutputFormat switch viper.GetString("format") { diff --git a/cmd/changes_start_analysis.go b/cmd/changes_start_analysis.go new file mode 100644 index 00000000..db9d5731 --- /dev/null +++ b/cmd/changes_start_analysis.go @@ -0,0 +1,99 @@ +package cmd + +import ( + "fmt" + "strings" + + "connectrpc.com/connect" + "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/tracing" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// startAnalysisCmd represents the start-analysis command +var startAnalysisCmd = &cobra.Command{ + Use: "start-analysis {--ticket-link URL | --uuid ID | --change URL}", + Short: "Triggers analysis on a change with previously stored planned changes", + Long: `Triggers analysis on a change that has previously stored planned changes. + +This command is used in multi-plan workflows (e.g., Atlantis parallel planning) where +multiple terraform plans are submitted independently using 'submit-plan --no-start', +and then analysis is triggered once all plans are submitted. + +The change must be in DEFINING status and must have at least one planned change stored.`, + PreRun: PreRunSetup, + RunE: StartAnalysis, +} + +func StartAnalysis(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + + app := viper.GetString("app") + + ctx, oi, _, err := login(ctx, cmd, []string{"changes:write", "sources:read"}, nil) + if err != nil { + return err + } + + lf := log.Fields{} + + changeUUID, err := getChangeUUIDAndCheckStatus(ctx, oi, sdp.ChangeStatus_CHANGE_STATUS_DEFINING, viper.GetString("ticket-link"), true) + if err != nil { + return loggedError{ + err: err, + fields: lf, + message: "failed to identify change", + } + } + + lf["change"] = changeUUID.String() + + analysisConfig, err := buildAnalysisConfig(ctx, lf) + if err != nil { + return err + } + + client := AuthenticatedChangesClient(ctx, oi) + + _, err = client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ + Msg: &sdp.StartChangeAnalysisRequest{ + ChangeUUID: changeUUID[:], + ChangingItems: nil, // uses pre-stored items from AddPlannedChanges + BlastRadiusConfigOverride: analysisConfig.BlastRadiusConfig, + RoutineChangesConfigOverride: analysisConfig.RoutineChangesConfig, + GithubOrganisationProfileOverride: analysisConfig.GithubOrgProfile, + Knowledge: analysisConfig.KnowledgeFiles, + }, + }) + if err != nil { + return loggedError{ + err: err, + fields: lf, + message: "failed to start change analysis", + } + } + + app, _ = strings.CutSuffix(app, "/") + changeUrl := fmt.Sprintf("%v/changes/%v?utm_source=cli&cli_version=%v", app, changeUUID, tracing.Version()) + log.WithContext(ctx).WithFields(lf).WithField("change-url", changeUrl).Info("Change analysis started") + fmt.Println(changeUrl) + + if viper.GetBool("wait") { + log.WithContext(ctx).WithFields(lf).Info("Waiting for analysis to complete") + return waitForChangeAnalysis(ctx, client, changeUUID, lf) + } + + return nil +} + +func init() { + changesCmd.AddCommand(startAnalysisCmd) + + addAPIFlags(startAnalysisCmd) + addChangeUuidFlags(startAnalysisCmd) + addAnalysisFlags(startAnalysisCmd) + + startAnalysisCmd.PersistentFlags().Bool("wait", false, "Wait for analysis to complete before returning.") +} diff --git a/cmd/changes_start_analysis_test.go b/cmd/changes_start_analysis_test.go new file mode 100644 index 00000000..cb134645 --- /dev/null +++ b/cmd/changes_start_analysis_test.go @@ -0,0 +1,220 @@ +package cmd + +import ( + "context" + "os" + "path/filepath" + "testing" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func TestAddAnalysisFlags(t *testing.T) { + t.Parallel() + + cmd := &cobra.Command{Use: "test"} + addAnalysisFlags(cmd) + + tests := []struct { + name string + flagName string + flagType string + }{ + {"blast-radius-link-depth", "blast-radius-link-depth", "int32"}, + {"blast-radius-max-items", "blast-radius-max-items", "int32"}, + {"blast-radius-max-time", "blast-radius-max-time", "duration"}, + {"change-analysis-target-duration", "change-analysis-target-duration", "duration"}, + {"signal-config", "signal-config", "string"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + flag := cmd.PersistentFlags().Lookup(tt.flagName) + if flag == nil { + t.Errorf("Expected flag %q to be registered", tt.flagName) + return + } + if flag.Value.Type() != tt.flagType { + t.Errorf("Expected flag %q to have type %q, got %q", tt.flagName, tt.flagType, flag.Value.Type()) + } + }) + } + + // Verify blast-radius-max-time is deprecated + flag := cmd.PersistentFlags().Lookup("blast-radius-max-time") + if flag == nil { + t.Error("Expected blast-radius-max-time flag to be registered") + return + } + if flag.Deprecated == "" { + t.Error("Expected blast-radius-max-time flag to be deprecated") + } +} + +func TestBuildAnalysisConfigWithNoFlags(t *testing.T) { + // Reset viper to ensure clean state + viper.Reset() + + ctx := context.Background() + lf := log.Fields{} + + // When no flags are set, buildAnalysisConfig should succeed with nil/empty configs + config, err := buildAnalysisConfig(ctx, lf) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if config == nil { + t.Fatal("Expected config to be non-nil") + } + + // BlastRadiusConfig should be nil when no flags are set + if config.BlastRadiusConfig != nil { + t.Errorf("Expected BlastRadiusConfig to be nil when no flags are set") + } + + // RoutineChangesConfig should be nil when no signal config file exists + if config.RoutineChangesConfig != nil { + t.Errorf("Expected RoutineChangesConfig to be nil when no signal config exists") + } + + // GithubOrgProfile should be nil when no signal config file exists + if config.GithubOrgProfile != nil { + t.Errorf("Expected GithubOrgProfile to be nil when no signal config exists") + } +} + +func TestBuildAnalysisConfigWithBlastRadiusFlags(t *testing.T) { + // Reset viper to ensure clean state + viper.Reset() + + viper.Set("blast-radius-link-depth", int32(5)) + viper.Set("blast-radius-max-items", int32(1000)) + + ctx := context.Background() + lf := log.Fields{} + + config, err := buildAnalysisConfig(ctx, lf) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if config == nil { + t.Fatal("Expected config to be non-nil") + } + + if config.BlastRadiusConfig == nil { + t.Fatal("Expected BlastRadiusConfig to be non-nil") + } + + if config.BlastRadiusConfig.GetLinkDepth() != 5 { + t.Errorf("Expected LinkDepth to be 5, got %d", config.BlastRadiusConfig.GetLinkDepth()) + } + + if config.BlastRadiusConfig.GetMaxItems() != 1000 { + t.Errorf("Expected MaxItems to be 1000, got %d", config.BlastRadiusConfig.GetMaxItems()) + } +} + +func TestBuildAnalysisConfigWithInvalidSignalConfigPath(t *testing.T) { + // Reset viper to ensure clean state + viper.Reset() + + // Set a non-existent signal config path + viper.Set("signal-config", "/nonexistent/path/signal-config.yaml") + + ctx := context.Background() + lf := log.Fields{} + + _, err := buildAnalysisConfig(ctx, lf) + if err == nil { + t.Fatal("Expected error for invalid signal config path") + } +} + +func TestBuildAnalysisConfigWithValidSignalConfig(t *testing.T) { + // Reset viper to ensure clean state + viper.Reset() + + // Create a temporary signal config file with valid content + tempDir := t.TempDir() + signalConfigPath := filepath.Join(tempDir, "signal-config.yaml") + signalConfigContent := `routine_changes_config: + sensitivity: 0 + duration_in_days: 1 + events_per_day: 1 +` + err := os.WriteFile(signalConfigPath, []byte(signalConfigContent), 0644) + if err != nil { + t.Fatalf("Failed to create temp signal config: %v", err) + } + + viper.Set("signal-config", signalConfigPath) + + ctx := context.Background() + lf := log.Fields{} + + config, err := buildAnalysisConfig(ctx, lf) + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + + if config == nil { + t.Fatal("Expected config to be non-nil") + } + + // The signal config should be loaded + if config.RoutineChangesConfig == nil { + t.Error("Expected RoutineChangesConfig to be non-nil when signal config is loaded") + } +} + +func TestStartAnalysisCmdFlags(t *testing.T) { + t.Parallel() + + // Verify the command has the expected flags registered + tests := []struct { + name string + flagName string + }{ + {"wait flag", "wait"}, + {"ticket-link flag", "ticket-link"}, + {"uuid flag", "uuid"}, + {"change flag", "change"}, + {"app flag", "app"}, + {"timeout flag", "timeout"}, + // Analysis flags + {"blast-radius-link-depth", "blast-radius-link-depth"}, + {"blast-radius-max-items", "blast-radius-max-items"}, + {"signal-config", "signal-config"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + flag := startAnalysisCmd.PersistentFlags().Lookup(tt.flagName) + if flag == nil { + // Check the parent command's flags + flag = startAnalysisCmd.Flags().Lookup(tt.flagName) + } + if flag == nil { + t.Errorf("Expected flag %q to be registered on start-analysis command", tt.flagName) + } + }) + } +} + +func TestSubmitPlanCmdHasNoStartFlag(t *testing.T) { + t.Parallel() + + flag := submitPlanCmd.PersistentFlags().Lookup("no-start") + if flag == nil { + t.Error("Expected no-start flag to be registered on submit-plan command") + return + } + + if flag.DefValue != "false" { + t.Errorf("Expected no-start flag default value to be 'false', got %q", flag.DefValue) + } +} diff --git a/cmd/changes_start_change.go b/cmd/changes_start_change.go index 5d757aef..9877354d 100644 --- a/cmd/changes_start_change.go +++ b/cmd/changes_start_change.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "time" "connectrpc.com/connect" @@ -45,50 +44,8 @@ func StartChange(cmd *cobra.Command, args []string) error { // wait for change analysis to complete (poll GetChange by change_analysis_status) client := AuthenticatedChangesClient(ctx, oi) -fetch: - for { - changeRes, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ - Msg: &sdp.GetChangeRequest{ - UUID: changeUuid[:], - }, - }) - if err != nil || changeRes.Msg == nil || changeRes.Msg.GetChange() == nil { - return loggedError{ - err: err, - fields: lf, - message: "failed to get change", - } - } - ch := changeRes.Msg.GetChange() - md := ch.GetMetadata() - if md == nil || md.GetChangeAnalysisStatus() == nil { - return loggedError{ - err: fmt.Errorf("change metadata or change analysis status is nil"), - fields: lf, - message: "failed to get change", - } - } - status := md.GetChangeAnalysisStatus().GetStatus() - switch status { - case sdp.ChangeAnalysisStatus_STATUS_DONE, sdp.ChangeAnalysisStatus_STATUS_SKIPPED: - break fetch - case sdp.ChangeAnalysisStatus_STATUS_ERROR: - return loggedError{ - err: fmt.Errorf("change analysis completed with error status"), - fields: lf, - message: "change analysis failed", - } - case sdp.ChangeAnalysisStatus_STATUS_UNSPECIFIED, sdp.ChangeAnalysisStatus_STATUS_INPROGRESS: - log.WithContext(ctx).WithFields(lf).WithField("status", status.String()).Info("Waiting for change analysis to complete") - } - time.Sleep(3 * time.Second) - if ctx.Err() != nil { - return loggedError{ - err: ctx.Err(), - fields: lf, - message: "context cancelled", - } - } + if err := waitForChangeAnalysis(ctx, client, changeUuid, lf); err != nil { + return err } // Call the simple RPC (enqueues a background job and returns immediately) diff --git a/cmd/changes_submit_plan.go b/cmd/changes_submit_plan.go index 2eff689f..a716f074 100644 --- a/cmd/changes_submit_plan.go +++ b/cmd/changes_submit_plan.go @@ -11,7 +11,6 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/cli/knowledge" "github.com/overmindtech/cli/tfutils" "github.com/overmindtech/cli/go/sdp-go" "github.com/overmindtech/cli/go/tracing" @@ -23,7 +22,7 @@ import ( // submitPlanCmd represents the submit-plan command var submitPlanCmd = &cobra.Command{ - Use: "submit-plan [--title TITLE] [--description DESCRIPTION] [--ticket-link URL] FILE [FILE ...]", + Use: "submit-plan [--no-start] [--title TITLE] [--description DESCRIPTION] [--ticket-link URL] FILE [FILE ...]", Short: "Creates a new Change from a given terraform plan file", Args: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { @@ -259,55 +258,45 @@ func SubmitPlan(cmd *cobra.Command, args []string) error { log.WithContext(ctx).WithFields(lf).Info("Re-using change") } - // Set up the blast radius preset if specified - maxDepth := viper.GetInt32("blast-radius-link-depth") - maxItems := viper.GetInt32("blast-radius-max-items") - maxTime := viper.GetDuration("blast-radius-max-time") - changeAnalysisTargetDuration := viper.GetDuration("change-analysis-target-duration") - - blastRadiusConfigOverride, err := createBlastRadiusConfig(maxDepth, maxItems, maxTime, changeAnalysisTargetDuration) - if err != nil { - return err - } - - // setup the signal config if specified, or found in the default location - // order of precedence: flag > default config file - signalConfigPath := viper.GetString("signal-config") - signalConfigOverride, err := checkForAndLoadSignalConfigFile(ctx, lf, signalConfigPath) - if err != nil { - return loggedError{ - err: err, - fields: lf, - message: "Failed to load signal config", + if viper.GetBool("no-start") { + // Store planned changes without starting analysis (multi-plan workflow) + _, err = client.AddPlannedChanges(ctx, &connect.Request[sdp.AddPlannedChangesRequest]{ + Msg: &sdp.AddPlannedChangesRequest{ + ChangeUUID: changeUUID[:], + ChangingItems: plannedChanges, + }, + }) + if err != nil { + return loggedError{ + err: err, + fields: lf, + message: "Failed to store planned changes", + } + } + log.WithContext(ctx).WithFields(lf).Info("Stored planned changes without starting analysis") + } else { + // Build analysis config and start analysis (default behavior) + analysisConfig, err := buildAnalysisConfig(ctx, lf) + if err != nil { + return err } - } - - var githubOrganisationProfileOverride *sdp.GithubOrganisationProfile - var routineChangesConfigOverride *sdp.RoutineChangesConfig - if signalConfigOverride != nil { - githubOrganisationProfileOverride = signalConfigOverride.GithubOrganisationProfile - routineChangesConfigOverride = signalConfigOverride.RoutineChangesConfig - } - // Discover and convert knowledge files - knowledgeDir := knowledge.FindKnowledgeDir(".") - sdpKnowledge := knowledge.DiscoverAndConvert(ctx, knowledgeDir) - - _, err = client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ - Msg: &sdp.StartChangeAnalysisRequest{ - ChangeUUID: changeUUID[:], - ChangingItems: plannedChanges, - BlastRadiusConfigOverride: blastRadiusConfigOverride, - RoutineChangesConfigOverride: routineChangesConfigOverride, - GithubOrganisationProfileOverride: githubOrganisationProfileOverride, - Knowledge: sdpKnowledge, - }, - }) - if err != nil { - return loggedError{ - err: err, - fields: lf, - message: "Failed to start change analysis", + _, err = client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ + Msg: &sdp.StartChangeAnalysisRequest{ + ChangeUUID: changeUUID[:], + ChangingItems: plannedChanges, + BlastRadiusConfigOverride: analysisConfig.BlastRadiusConfig, + RoutineChangesConfigOverride: analysisConfig.RoutineChangesConfig, + GithubOrganisationProfileOverride: analysisConfig.GithubOrgProfile, + Knowledge: analysisConfig.KnowledgeFiles, + }, + }) + if err != nil { + return loggedError{ + err: err, + fields: lf, + message: "Failed to start change analysis", + } } } @@ -393,16 +382,12 @@ func init() { addAPIFlags(submitPlanCmd) addChangeCreationFlags(submitPlanCmd) + addAnalysisFlags(submitPlanCmd) submitPlanCmd.PersistentFlags().String("frontend", "", "The frontend base URL") _ = submitPlanCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.") // MarkDeprecated only errors if the flag doesn't exist, we fall back to using app - submitPlanCmd.PersistentFlags().Int32("blast-radius-link-depth", 0, "Used in combination with '--blast-radius-max-items' to customise how many levels are traversed when calculating the blast radius. Larger numbers will result in a more comprehensive blast radius, but may take longer to calculate. Defaults to the account level settings.") - submitPlanCmd.PersistentFlags().Int32("blast-radius-max-items", 0, "Used in combination with '--blast-radius-link-depth' to customise how many items are included in the blast radius. Larger numbers will result in a more comprehensive blast radius, but may take longer to calculate. Defaults to the account level settings.") - - submitPlanCmd.PersistentFlags().Duration("blast-radius-max-time", 0, "Maximum time duration for blast radius calculation (e.g., '5m', '15m', '30m'). When the time limit is reached, the analysis continues with risks identified up to that point. Defaults to the account level settings (QUICK: 10m, DETAILED: 15m, FULL: 30m). Valid range: 1m to 30m.") - _ = submitPlanCmd.PersistentFlags().MarkDeprecated("blast-radius-max-time", "This flag is no longer used and will be removed in a future release. Use the '--change-analysis-target-duration' flag instead.") - submitPlanCmd.PersistentFlags().Duration("change-analysis-target-duration", 0, "Target duration for change analysis planning (e.g., '5m', '15m', '30m'). This is NOT a hard deadline - the blast radius phase uses 67% of this target to stop gracefully. The job can run slightly past this target and is only hard-stopped at 30 minutes. Defaults to the account level settings (QUICK: 10m, DETAILED: 15m, FULL: 30m). Valid range: 1m to 30m.") submitPlanCmd.PersistentFlags().String("auto-tag-rules", "", "The path to the auto-tag rules file. If not provided, it will check the default location which is '.overmind/auto-tag-rules.yaml'. If no rules are found locally, the rules configured through the UI are used.") - submitPlanCmd.PersistentFlags().String("signal-config", "", "The path to the signal config file. If not provided, it will check the default location which is '.overmind/signal-config.yaml'. If no config is found locally, the config configured through the UI is used.") + + submitPlanCmd.PersistentFlags().Bool("no-start", false, "Store the planned changes without starting analysis. Use with 'start-analysis' to trigger analysis later.") } diff --git a/cmd/flags.go b/cmd/flags.go index 5a4f3b2d..102b69c5 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -1,11 +1,18 @@ package cmd import ( + "context" "fmt" "strconv" "strings" + "time" + "connectrpc.com/connect" + "github.com/google/uuid" + "github.com/overmindtech/cli/knowledge" "github.com/overmindtech/cli/go/sdp-go" + "github.com/overmindtech/cli/go/sdp-go/sdpconnect" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -116,3 +123,125 @@ func addTerraformBaseFlags(cmd *cobra.Command) { cobra.CheckErr(cmd.PersistentFlags().MarkHidden("aws-profile")) cmd.PersistentFlags().Bool("only-use-managed-sources", false, "Set this to skip local autoconfiguration and only use the managed sources as configured in Overmind.") } + +// Adds analysis-related flags (blast radius config, signal config) to a command. +// These flags are shared between submit-plan and start-analysis commands. +func addAnalysisFlags(cmd *cobra.Command) { + cmd.PersistentFlags().Int32("blast-radius-link-depth", 0, "Used in combination with '--blast-radius-max-items' to customise how many levels are traversed when calculating the blast radius. Larger numbers will result in a more comprehensive blast radius, but may take longer to calculate. Defaults to the account level settings.") + cmd.PersistentFlags().Int32("blast-radius-max-items", 0, "Used in combination with '--blast-radius-link-depth' to customise how many items are included in the blast radius. Larger numbers will result in a more comprehensive blast radius, but may take longer to calculate. Defaults to the account level settings.") + cmd.PersistentFlags().Duration("blast-radius-max-time", 0, "Maximum time duration for blast radius calculation (e.g., '5m', '15m', '30m'). When the time limit is reached, the analysis continues with risks identified up to that point. Defaults to the account level settings (QUICK: 10m, DETAILED: 15m, FULL: 30m). Valid range: 1m to 30m.") + _ = cmd.PersistentFlags().MarkDeprecated("blast-radius-max-time", "This flag is no longer used and will be removed in a future release. Use the '--change-analysis-target-duration' flag instead.") + cmd.PersistentFlags().Duration("change-analysis-target-duration", 0, "Target duration for change analysis planning (e.g., '5m', '15m', '30m'). This is NOT a hard deadline - the blast radius phase uses 67% of this target to stop gracefully. The job can run slightly past this target and is only hard-stopped at 30 minutes. Defaults to the account level settings (QUICK: 10m, DETAILED: 15m, FULL: 30m). Valid range: 1m to 30m.") + cmd.PersistentFlags().String("signal-config", "", "The path to the signal config file. If not provided, it will check the default location which is '.overmind/signal-config.yaml'. If no config is found locally, the config configured through the UI is used.") +} + +// AnalysisConfig holds all the configuration needed to start change analysis. +type AnalysisConfig struct { + BlastRadiusConfig *sdp.BlastRadiusConfig + RoutineChangesConfig *sdp.RoutineChangesConfig + GithubOrgProfile *sdp.GithubOrganisationProfile + KnowledgeFiles []*sdp.Knowledge +} + +// buildAnalysisConfig reads viper flags and builds the analysis configuration +// used by StartChangeAnalysis. This includes blast radius config, routine changes +// config, github org profile, and knowledge files. +func buildAnalysisConfig(ctx context.Context, lf log.Fields) (*AnalysisConfig, error) { + maxDepth := viper.GetInt32("blast-radius-link-depth") + maxItems := viper.GetInt32("blast-radius-max-items") + maxTime := viper.GetDuration("blast-radius-max-time") + changeAnalysisTargetDuration := viper.GetDuration("change-analysis-target-duration") + + blastRadiusConfig, err := createBlastRadiusConfig(maxDepth, maxItems, maxTime, changeAnalysisTargetDuration) + if err != nil { + return nil, err + } + + signalConfigPath := viper.GetString("signal-config") + signalConfigOverride, err := checkForAndLoadSignalConfigFile(ctx, lf, signalConfigPath) + if err != nil { + return nil, loggedError{ + err: err, + fields: lf, + message: "Failed to load signal config", + } + } + + var githubOrgProfile *sdp.GithubOrganisationProfile + var routineChangesConfig *sdp.RoutineChangesConfig + if signalConfigOverride != nil { + githubOrgProfile = signalConfigOverride.GithubOrganisationProfile + routineChangesConfig = signalConfigOverride.RoutineChangesConfig + } + + knowledgeDir := knowledge.FindKnowledgeDir(".") + knowledgeFiles := knowledge.DiscoverAndConvert(ctx, knowledgeDir) + + return &AnalysisConfig{ + BlastRadiusConfig: blastRadiusConfig, + RoutineChangesConfig: routineChangesConfig, + GithubOrgProfile: githubOrgProfile, + KnowledgeFiles: knowledgeFiles, + }, nil +} + +// waitForChangeAnalysis polls the change until analysis reaches a terminal status +// (STATUS_DONE, STATUS_SKIPPED, or STATUS_ERROR). It returns nil on successful +// completion, or an error if analysis failed or was cancelled. +func waitForChangeAnalysis(ctx context.Context, client sdpconnect.ChangesServiceClient, changeUUID uuid.UUID, lf log.Fields) error { + for { + changeRes, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ + Msg: &sdp.GetChangeRequest{ + UUID: changeUUID[:], + }, + }) + if err != nil { + return loggedError{ + err: err, + fields: lf, + message: "failed to get change", + } + } + if changeRes.Msg == nil || changeRes.Msg.GetChange() == nil { + return loggedError{ + err: fmt.Errorf("unexpected nil response from GetChange"), + fields: lf, + message: "failed to get change", + } + } + + ch := changeRes.Msg.GetChange() + md := ch.GetMetadata() + if md == nil || md.GetChangeAnalysisStatus() == nil { + return loggedError{ + err: fmt.Errorf("change metadata or change analysis status is nil"), + fields: lf, + message: "failed to get change analysis status", + } + } + + status := md.GetChangeAnalysisStatus().GetStatus() + switch status { + case sdp.ChangeAnalysisStatus_STATUS_DONE, sdp.ChangeAnalysisStatus_STATUS_SKIPPED: + log.WithContext(ctx).WithFields(lf).WithField("status", status.String()).Info("Change analysis complete") + return nil + case sdp.ChangeAnalysisStatus_STATUS_ERROR: + return loggedError{ + err: fmt.Errorf("change analysis completed with error status"), + fields: lf, + message: "change analysis failed", + } + case sdp.ChangeAnalysisStatus_STATUS_UNSPECIFIED, sdp.ChangeAnalysisStatus_STATUS_INPROGRESS: + log.WithContext(ctx).WithFields(lf).WithField("status", status.String()).Info("Waiting for change analysis to complete") + } + + time.Sleep(3 * time.Second) + if ctx.Err() != nil { + return loggedError{ + err: ctx.Err(), + fields: lf, + message: "context cancelled", + } + } + } +} From 06f88f3115ac7783f8e6c6248aaab6eda24e9e7a Mon Sep 17 00:00:00 2001 From: TP Honey Date: Thu, 12 Mar 2026 10:47:06 +0000 Subject: [PATCH 15/18] feat: add RFC 9728 resource_metadata to MCP 401 responses (#4234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce WithResourceMetadata middleware that sets a WWW-Authenticate header with a resource_metadata URL on 401 responses, enabling MCP clients (e.g. Cursor) to discover the authorization server automatically. Serve PRM at both path-based and root well-known URIs per RFC 9728. --- > [!NOTE] > **Medium Risk** > Touches authentication-adjacent HTTP middleware and changes routing/headers for `401` responses, which could affect client auth flows and caching/proxies if misconfigured. Scope is limited to MCP endpoints and well-known PRM routes with added tests. > > **Overview** > Enables MCP OAuth discovery per RFC 9728 by adding `auth.WithResourceMetadata`, which injects `WWW-Authenticate: Bearer resource_metadata="…"` on `401 Unauthorized` responses. > > Wires this into the api-server’s `/area51/mcp` route (when `MCPResourceMetadataURL` is configured) and serves Protected Resource Metadata from both `/.well-known/oauth-protected-resource/area51/mcp` (path-based) and the root `/.well-known/oauth-protected-resource` endpoint; adds unit tests covering the new header behavior. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2f65fb73d3efae8da6f553ff42614f481f2ca406. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: c8cc2f110b6f9e83a8663ffd4ee93ddc74ce63a0 --- go/auth/middleware.go | 42 ++++++++++++++++++ go/auth/middleware_test.go | 89 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/go/auth/middleware.go b/go/auth/middleware.go index 081f283e..f4509360 100644 --- a/go/auth/middleware.go +++ b/go/auth/middleware.go @@ -500,6 +500,48 @@ func ensureValidTokenHandler(config MiddlewareConfig, next http.Handler) http.Ha }) } +// WithResourceMetadata wraps a handler to include RFC 9728 resource_metadata +// in the WWW-Authenticate header on 401 responses, enabling MCP clients to +// discover the authorization server via Protected Resource Metadata. +func WithResourceMetadata(resourceMetadataURL string, next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + next.ServeHTTP(&resourceMetadataWriter{ + ResponseWriter: w, + resourceMetadataURL: resourceMetadataURL, + }, r) + }) +} + +type resourceMetadataWriter struct { + http.ResponseWriter + resourceMetadataURL string + wroteHeader bool +} + +func (w *resourceMetadataWriter) WriteHeader(statusCode int) { + if !w.wroteHeader { + w.wroteHeader = true + if statusCode == http.StatusUnauthorized { + w.ResponseWriter.Header().Set("WWW-Authenticate", + fmt.Sprintf(`Bearer resource_metadata=%q`, w.resourceMetadataURL)) + } + } + w.ResponseWriter.WriteHeader(statusCode) +} + +func (w *resourceMetadataWriter) Write(b []byte) (int, error) { + if !w.wroteHeader { + w.WriteHeader(http.StatusOK) + } + return w.ResponseWriter.Write(b) +} + +// Unwrap returns the underlying ResponseWriter, enabling http.ResponseController +// and middleware that check for optional interfaces (Flusher, Hijacker, etc.). +func (w *resourceMetadataWriter) Unwrap() http.ResponseWriter { + return w.ResponseWriter +} + // CustomClaims contains custom data we want from the token. type CustomClaims struct { Scope string `json:"scope"` diff --git a/go/auth/middleware_test.go b/go/auth/middleware_test.go index 412da45b..f0618753 100644 --- a/go/auth/middleware_test.go +++ b/go/auth/middleware_test.go @@ -691,6 +691,95 @@ func (s *TestJWTServer) Start(ctx context.Context) string { return s.server.URL } +func TestWithResourceMetadata(t *testing.T) { + t.Parallel() + + prmURL := "https://api.example.com/.well-known/oauth-protected-resource/area51/mcp" + + t.Run("adds WWW-Authenticate on 401", func(t *testing.T) { + t.Parallel() + inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"message":"JWT is missing."}`)) + }) + + handler := WithResourceMetadata(prmURL, inner) + rr := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodPost, "/area51/mcp", nil) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusUnauthorized { + t.Fatalf("expected 401, got %d", rr.Code) + } + + wwwAuth := rr.Header().Get("WWW-Authenticate") + expected := `Bearer resource_metadata="` + prmURL + `"` + if wwwAuth != expected { + t.Errorf("expected WWW-Authenticate %q, got %q", expected, wwwAuth) + } + }) + + t.Run("no WWW-Authenticate on 200", func(t *testing.T) { + t.Parallel() + inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + handler := WithResourceMetadata(prmURL, inner) + rr := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodPost, "/area51/mcp", nil) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Fatalf("expected 200, got %d", rr.Code) + } + + if wwwAuth := rr.Header().Get("WWW-Authenticate"); wwwAuth != "" { + t.Errorf("expected no WWW-Authenticate header, got %q", wwwAuth) + } + }) + + t.Run("no WWW-Authenticate on 403", func(t *testing.T) { + t.Parallel() + inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusForbidden) + }) + + handler := WithResourceMetadata(prmURL, inner) + rr := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodPost, "/area51/mcp", nil) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusForbidden { + t.Fatalf("expected 403, got %d", rr.Code) + } + + if wwwAuth := rr.Header().Get("WWW-Authenticate"); wwwAuth != "" { + t.Errorf("expected no WWW-Authenticate header on 403, got %q", wwwAuth) + } + }) + + t.Run("implicit 200 from Write without WriteHeader", func(t *testing.T) { + t.Parallel() + inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte("ok")) + }) + + handler := WithResourceMetadata(prmURL, inner) + rr := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, "/area51/mcp", nil) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Fatalf("expected 200, got %d", rr.Code) + } + + if wwwAuth := rr.Header().Get("WWW-Authenticate"); wwwAuth != "" { + t.Errorf("expected no WWW-Authenticate header, got %q", wwwAuth) + } + }) +} + func TestConnectErrorHandling(t *testing.T) { // Create a test JWT server server, err := NewTestJWTServer() From ebb631cebffc1477982b0da68de3b9ff55ad1ba5 Mon Sep 17 00:00:00 2001 From: TP Honey Date: Thu, 12 Mar 2026 12:29:54 +0000 Subject: [PATCH 16/18] [ENG-3113] GitHub App PR commenting for change analysis results (#4231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Implements Phase 3 of the Multi-Plan Submission + GitHub App PR Commenting project: the backend posts change analysis results as a comment on the linked GitHub PR using the installed GitHub App - Uses a static hidden HTML marker (``) for idempotent upserts — re-runs update the same comment instead of duplicating - All PR comment failures are non-fatal — logged and traced but never fail the analysis job ## Linear Ticket - **Ticket**: [ENG-3113](https://linear.app/overmind/issue/ENG-3113) — Phase 3: Backend — GitHub App PR Commenting - **Purpose**: Enable the backend to post analysis results directly to GitHub PRs, so CI/CLI can detect `github_app_active` and skip its own commenting - **Depends on**: Phase 1 (ENG-3098, merged) and Phase 2 (ENG-3104, PR #4229 rebased onto this branch) ## Changes ### Proto (`sdp/changes.proto`) - `StartChangeAnalysisRequest`: added `post_github_comment` (field 8) - `StartChangeAnalysisResponse`: added `github_app_active` (field 1) - `GetChangeSummaryResponse`: added `github_app_comment_posted` (field 2) ### Schema + SQLC - Migration adding nullable `github_comment_id bigint` to `changes` table - New `SetGithubCommentID` query ### GitHub App PR Commenting (`githubapp/githubapp.go`) - `ParseGitHubPRURL` — extracts owner/repo/number from PR URLs - `PostOrUpdatePRComment` — posts or updates a comment using static hidden HTML marker for dedup; handles 403 gracefully (returns 0, nil) - `CheckInstallationCanComment` — verifies `pull_requests:write` permission on the installation - `findExistingComment` documented with marker-vs-DB tradeoff rationale ### Shared Markdown & Signal Aggregation (`service/change_summary.go`) - `BuildChangeSummaryMarkdown` — gathers data from DB and renders the same markdown template used by `get-change --format markdown`. Takes `*config.LLMConfig` and performs LLM-based signal aggregation internally. - `AggregateChangeOverviewSignals` — shared signal aggregation function extracted from `signalservice.go`, called by both `GetChangeOverviewSignals` RPC and `BuildChangeSummaryMarkdown`. Ensures PR comments show identical signal values to the dashboard/CLI. - `computeBlastRadiusContext` — extracted from `GetChangeSummary` to remove duplication ### Signal Service Refactor (`service/signalservice.go`) - `GetChangeOverviewSignals` RPC handler now delegates to shared `AggregateChangeOverviewSignals`, keeping only auth checks and RPC wrapping (~90 lines of business logic removed) ### Worker Wiring (`changeanalysis/change_analysis.go`) - `PostGithubComment bool` added to `ChangeAnalysisCalculationArgs` - `FrontendDNS` and `BuildMarkdownFunc` callback added to worker struct (callback avoids circular import) - `postAnalysisGithubPRComment` runs after `STATUS_DONE` — non-fatal, logged + Sentry, with `cenkalti/backoff/v5` retries - `ovm.auth.accountName` set on the comment span for worker-context observability - OTEL attributes use `ovm.github.pr_comment.skipped_reason` for all early-exit paths ### RPC Wiring (`changesservice.go`) - `checkGithubAppCanComment` helper checks installation permissions - `StartChangeAnalysis` returns `github_app_active` and passes flag to worker args - `GetChangeSummary` returns `github_app_comment_posted` from `change.GithubCommentID.Valid` ### LLM: Fix web search `outputToParam` crash - **Root cause**: `outputToParam` crashed with `"no action present"` when OpenAI returned a `web_search_call` whose action type was unrecognized by the SDK's `AsAny()` (returns `nil` for types other than `search`, `open_page`, `find_in_page`). This happened non-deterministically, causing test flakes in `TestWebSearchTool`. - **Fix**: The `default` case now sets `skipped = true` instead of returning a fatal error, since web search items are purely informational and already ignored in the main processing loop. The caller emits a structured `Warn` log with `callId`, `status`, `actionType`, `actionRawJSON`, and `model` for Honeycomb analysis. The span event also now includes `actionTypeRaw` and `actionRawJSON`. - **Secondary fix**: The `search` action case was silently dropping `Queries` and `Sources` fields during the output-to-param conversion — these are now preserved. ### Tests - `githubapp_test.go`: URL parsing (9 cases), comment create/update/403, permissions check (httptest mocks), pinned marker format test to prevent silent duplicate-comment regressions - `changesservice_test.go`: `checkGithubAppCanComment`, `SetGithubCommentID` DB roundtrip - `change_summary_test.go`: `BuildChangeSummaryMarkdown`, `AggregateChangeOverviewSignals` (single-signal-per-category pass-through), `computeBlastRadiusContext` ## Deviations from Approved Plan - **BuildMarkdownFunc callback instead of direct import**: The plan suggested the worker call `BuildChangeSummaryMarkdown` directly. Due to a circular import (`changeanalysis` cannot import `service`), a `BuildMarkdownFunc` callback field was added to the worker struct, set at init time in `main.go`. Same behavior, different wiring. - **Retry with `cenkalti/backoff/v5`**: The plan did not specify retry logic for `PostOrUpdatePRComment`. Exponential backoff retries (3 attempts) were added in `postAnalysisGithubPRComment` to handle transient GitHub API failures, since the library was already available in the project. - **All PR comment code consolidated in `githubapp.go`**: The plan suggested a separate `pr_comment.go` file (and `changeanalysis/github_comment.go`). All PR comment functions (`ParseGitHubPRURL`, `PostOrUpdatePRComment`, `CheckInstallationCanComment`, `findExistingComment`) and their tests were consolidated into the existing `githubapp.go` / `githubapp_test.go` to combat file sprawl and keep all GitHub App logic grouped together. `postAnalysisGithubPRComment` remains in `change_analysis.go` alongside the existing worker methods. - **No `postAnalysisGithubPRComment` unit tests in `change_analysis_test.go`**: The plan called for direct tests of this method. Testing it requires mocking the full River worker context, GitHub API, and DB. The function is non-fatal by design and its components (`PostOrUpdatePRComment`, `BuildChangeSummaryMarkdown`, `AggregateChangeOverviewSignals`) are tested individually. --------- Co-authored-by: David Schmitt GitOrigin-RevId: ed78774f122809a4568368f44c21b677ebcb2107 --- go/sdp-go/changes.pb.go | 67 +++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/go/sdp-go/changes.pb.go b/go/sdp-go/changes.pb.go index 9de6b493..2d4c3d7f 100644 --- a/go/sdp-go/changes.pb.go +++ b/go/sdp-go/changes.pb.go @@ -3176,9 +3176,13 @@ type StartChangeAnalysisRequest struct { // github organisation profile to use for this change GithubOrganisationProfileOverride *GithubOrganisationProfile `protobuf:"bytes,6,opt,name=githubOrganisationProfileOverride,proto3,oneof" json:"githubOrganisationProfileOverride,omitempty"` // Knowledge to be used for change analysis - Knowledge []*Knowledge `protobuf:"bytes,7,rep,name=knowledge,proto3" json:"knowledge,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Knowledge []*Knowledge `protobuf:"bytes,7,rep,name=knowledge,proto3" json:"knowledge,omitempty"` + // When true, the backend will attempt to post analysis results as a GitHub + // PR comment via the installed GitHub App. Requires the account to have a + // GitHub App installation with pull_requests:write permission. + PostGithubComment bool `protobuf:"varint,8,opt,name=post_github_comment,json=postGithubComment,proto3" json:"post_github_comment,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StartChangeAnalysisRequest) Reset() { @@ -3253,12 +3257,23 @@ func (x *StartChangeAnalysisRequest) GetKnowledge() []*Knowledge { return nil } +func (x *StartChangeAnalysisRequest) GetPostGithubComment() bool { + if x != nil { + return x.PostGithubComment + } + return false +} + // StartChangeAnalysisResponse is used to signal that the change analysis has been successfully started // we use HTTP response codes to signal errors type StartChangeAnalysisResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // True when the account has a GitHub App installation with sufficient + // permissions to post PR comments. The CLI/Action can use this to decide + // whether it needs to post its own comment. + GithubAppActive bool `protobuf:"varint,1,opt,name=github_app_active,json=githubAppActive,proto3" json:"github_app_active,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StartChangeAnalysisResponse) Reset() { @@ -3291,6 +3306,13 @@ func (*StartChangeAnalysisResponse) Descriptor() ([]byte, []int) { return file_changes_proto_rawDescGZIP(), []int{43} } +func (x *StartChangeAnalysisResponse) GetGithubAppActive() bool { + if x != nil { + return x.GithubAppActive + } + return false +} + // AddPlannedChangesRequest appends a batch of planned changes to an existing // change without triggering analysis. Used by multi-plan workflows (e.g. // Atlantis parallel planning) where each plan step submits independently. @@ -5349,10 +5371,13 @@ func (x *GetChangeSummaryRequest) GetAppURL() string { } type GetChangeSummaryResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Change string `protobuf:"bytes,1,opt,name=change,proto3" json:"change,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Change string `protobuf:"bytes,1,opt,name=change,proto3" json:"change,omitempty"` + // True when the GitHub App has successfully posted (or updated) a PR + // comment for this change. Allows the CLI/Action to skip its own comment. + GithubAppCommentPosted bool `protobuf:"varint,2,opt,name=github_app_comment_posted,json=githubAppCommentPosted,proto3" json:"github_app_comment_posted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetChangeSummaryResponse) Reset() { @@ -5392,6 +5417,13 @@ func (x *GetChangeSummaryResponse) GetChange() string { return "" } +func (x *GetChangeSummaryResponse) GetGithubAppCommentPosted() bool { + if x != nil { + return x.GithubAppCommentPosted + } + return false +} + type GetChangeSignalsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` UUID []byte `protobuf:"bytes,1,opt,name=UUID,proto3" json:"UUID,omitempty"` @@ -6800,7 +6832,7 @@ const file_changes_proto_rawDesc = "" + "\x0emapping_status\x18\x04 \x01(\x0e2 .changes.MappedItemMappingStatusH\x02R\rmappingStatus\x88\x01\x01B\x0f\n" + "\r_mappingQueryB\x0f\n" + "\r_mappingErrorB\x11\n" + - "\x0f_mapping_status\"\xd3\x04\n" + + "\x0f_mapping_status\"\x83\x05\n" + "\x1aStartChangeAnalysisRequest\x12\x1e\n" + "\n" + "changeUUID\x18\x01 \x01(\fR\n" + @@ -6809,11 +6841,13 @@ const file_changes_proto_rawDesc = "" + "\x19blastRadiusConfigOverride\x18\x03 \x01(\v2\x19.config.BlastRadiusConfigH\x00R\x19blastRadiusConfigOverride\x88\x01\x01\x12e\n" + "\x1croutineChangesConfigOverride\x18\x05 \x01(\v2\x1c.config.RoutineChangesConfigH\x01R\x1croutineChangesConfigOverride\x88\x01\x01\x12t\n" + "!githubOrganisationProfileOverride\x18\x06 \x01(\v2!.config.GithubOrganisationProfileH\x02R!githubOrganisationProfileOverride\x88\x01\x01\x120\n" + - "\tknowledge\x18\a \x03(\v2\x12.changes.KnowledgeR\tknowledgeB\x1c\n" + + "\tknowledge\x18\a \x03(\v2\x12.changes.KnowledgeR\tknowledge\x12.\n" + + "\x13post_github_comment\x18\b \x01(\bR\x11postGithubCommentB\x1c\n" + "\x1a_blastRadiusConfigOverrideB\x1f\n" + "\x1d_routineChangesConfigOverrideB$\n" + - "\"_githubOrganisationProfileOverrideJ\x04\b\x04\x10\x05\"\x1d\n" + - "\x1bStartChangeAnalysisResponse\"y\n" + + "\"_githubOrganisationProfileOverrideJ\x04\b\x04\x10\x05\"I\n" + + "\x1bStartChangeAnalysisResponse\x12*\n" + + "\x11github_app_active\x18\x01 \x01(\bR\x0fgithubAppActive\"y\n" + "\x18AddPlannedChangesRequest\x12\x1e\n" + "\n" + "changeUUID\x18\x01 \x01(\fR\n" + @@ -6999,9 +7033,10 @@ const file_changes_proto_rawDesc = "" + "\x04slim\x18\x02 \x01(\bR\x04slim\x12K\n" + "\x12changeOutputFormat\x18\x03 \x01(\x0e2\x1b.changes.ChangeOutputFormatR\x12changeOutputFormat\x12F\n" + "\x12riskSeverityFilter\x18\x04 \x03(\x0e2\x16.changes.Risk.SeverityR\x12riskSeverityFilter\x12\x16\n" + - "\x06appURL\x18\x05 \x01(\tR\x06appURL\"2\n" + + "\x06appURL\x18\x05 \x01(\tR\x06appURL\"m\n" + "\x18GetChangeSummaryResponse\x12\x16\n" + - "\x06change\x18\x01 \x01(\tR\x06change\"z\n" + + "\x06change\x18\x01 \x01(\tR\x06change\x129\n" + + "\x19github_app_comment_posted\x18\x02 \x01(\bR\x16githubAppCommentPosted\"z\n" + "\x17GetChangeSignalsRequest\x12\x12\n" + "\x04UUID\x18\x01 \x01(\fR\x04UUID\x12K\n" + "\x12changeOutputFormat\x18\x02 \x01(\x0e2\x1b.changes.ChangeOutputFormatR\x12changeOutputFormat\"4\n" + From bd9a16a04de06c58fe5817b30162c1c00e925e3c Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 12 Mar 2026 16:17:52 +0100 Subject: [PATCH 17/18] Eng 3123 cli action comment wait (#4245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add `--comment` flag to CLI (`submit-plan`, `start-analysis`) and `--wait` flag to `get-change` to enable GitHub App PR commenting and control analysis polling - Add `comment` and `wait` inputs to the `submit-plan` composite action, with backward-compatible `fetch-change` deprecation - Migrate internal workflows (`terraform.yml`, `terraform-meta.yml`) to use the new inputs and disable legacy Slack plan notifications ## Linear Ticket - **Ticket**: [ENG-3123](https://linear.app/overmind/issue/ENG-3123/phase-4-cli-action-wire-comment-flag-auto-detect-and-skip-wait) — Phase 4: CLI + Action — Wire Comment Flag, Auto-Detect, and Skip Wait - **Project**: Multi-Plan Submission & GitHub App PR Commenting (Phase 4 of 5) ## Changes ### CLI (`cli/cmd/`) - `flags.go`: New `--comment` bool flag on `addAnalysisFlags`, requesting the GitHub App to post PR comments - `changes_submit_plan.go`: When `--comment` is set, outputs eval-able `CHANGE_URL` and `GITHUB_APP_ACTIVE` assignments instead of bare URL; passes `PostGithubComment` to `StartChangeAnalysis` RPC - `changes_start_analysis.go`: Same `--comment` behavior and `PostGithubComment` plumbing for the standalone `start-analysis` command - `changes_get_change.go`: Adds `--wait` flag (default `true`); skips `waitForChangeAnalysis` when `--wait=false`. Also fixes `MarkDeprecated` referencing wrong command (`submitPlanCmd` → `getChangeCmd`) - Housekeeping: replace `_ = MarkDeprecated`/`MarkHidden` with `cobra.CheckErr(...)` across 7 call sites ### Action (`actions/submit-plan/action.yml`) - New `comment` (default `"true"`) and `wait` (default `"false"`) inputs - `fetch-change` marked deprecated with backward-compatible shim - New `github-app-active` output; fixes `message` output (was incorrectly mapped to `change-url`) - When `comment=true`: tries `--comment` flag, falls back gracefully if CLI is older (`unknown flag` detection), and only fetches/posts sticky comment when the GitHub App is not active - Stderr isolation: redirects stderr to temp files (`submit-stderr.log`, `get-stderr.log`) instead of `2>&1` to prevent logrus output from polluting eval'd shell assignments or PR comment content ### Workflows (`.github/workflows/`) - `terraform.yml` and `terraform-meta.yml`: migrate from `fetch-change` to `comment`, add push-event guard, disable Slack plan notifications (GitHub App replaces them) ## Deviations from Approved Plan ### Additions not in the plan 1. **Stderr isolation in action shell logic** (`actions/submit-plan/action.yml`): The plan uses `eval "$(cli ...)"` directly. The implementation captures stdout to a variable with stderr redirected to temp files (`2>./overmindtech/submit-stderr.log`, `2>./overmindtech/get-stderr.log`), then evals the variable. This prevents logrus stderr lines (containing invalid bash identifiers like `change-url`) from breaking `eval`, and prevents log noise from leaking into PR comment content. 2. **Backward compatibility fallback for older CLIs** (`actions/submit-plan/action.yml`): The plan assumes the CLI supports `--comment` and `--wait`. The implementation adds fallback: if the CLI returns "unknown flag" (detected via the stderr temp file), it falls back to the legacy code path and logs a `::notice::`. This enables rolling out the action change before all CLI versions support the new flags. 3. **Push-event guard in workflows** (`.github/workflows/terraform.yml`, `terraform-meta.yml`): The plan removes `fetch-change` without adding an equivalent guard. The implementation passes `comment: ${{ github.event.number != '' }}` instead of unconditional `comment: true`, preventing comment logic from running on push events where there's no PR number. ### Minor approach changes 4. **Sticky comment condition**: The plan checks `inputs.comment != 'false'`. The implementation checks `steps.submit-plan.outputs.message != ''` — more robust since `message` is only populated when the change was actually fetched. 5. **`fetch-change` deprecation mapping**: The plan maps both `true` → `comment: true` and `false` → `comment: false`. The implementation only remaps the `false` case (setting `OVM_COMMENT='false'`), since `comment` already defaults to `"true"`. ### Omissions from the plan 6. **Part 8 — Linear issue for Slack notification feature**: The plan calls for creating a Linear issue titled "Investigate Slack notification feature for change analysis results". This was **not created** and should be filed separately. ## Test Plan - [x] Flag registration tests for `--comment` on `submit-plan` and `start-analysis` - [x] Flag registration test for `--wait` on `get-change` (default `true`) - [ ] Verify `submit-plan` action with `comment: true` on a PR event (GitHub App active path) - [ ] Verify `submit-plan` action with `comment: true` when GitHub App is not installed (sticky comment fallback) - [ ] Verify `submit-plan` action with older CLI that doesn't support `--comment` (graceful fallback) - [ ] Verify `comment: false` skips all PR commenting logic - [ ] Verify `wait: true` blocks until analysis completes and populates `message` output > [!NOTE] > **Medium Risk** > Changes GitHub Actions and CLI behavior around when to wait for Overmind analysis and where results are posted; misconfiguration could lead to missing plan feedback or altered CI timing. Touches deployment workflows but not Terraform execution logic itself. > > **Overview** > Routes Terraform plan reporting away from Slack and toward PR comments, wiring workflows to pass a new `comment` input to `actions/submit-plan` (and disabling the plan-to-Slack steps). > > Updates the `submit-plan` composite action and Overmind CLI to support `comment`/`wait` controls (deprecating `fetch-change`), including conditional fetching of analysis results, GitHub App vs sticky-comment handling, and new CLI flags/outputs (`--comment`, `get-change --wait`). Also tightens flag handling by checking errors when hiding/deprecating Cobra flags and adds targeted tests for the new flags. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1690417e01470b73fe9bd371b2eb1f878895d32d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: a0fb20e395e0f0ffb62e32a3970c48dff980e184 --- cmd/changes_get_change.go | 9 ++++++--- cmd/changes_get_change_test.go | 14 ++++++++++++++ cmd/changes_get_signals.go | 2 +- cmd/changes_start_analysis.go | 11 +++++++++-- cmd/changes_start_analysis_test.go | 16 ++++++++++++++++ cmd/changes_submit_plan.go | 19 ++++++++++++++++--- cmd/explore.go | 2 +- cmd/flags.go | 3 ++- cmd/knowledge_list.go | 2 +- cmd/terraform.go | 2 +- 10 files changed, 67 insertions(+), 13 deletions(-) diff --git a/cmd/changes_get_change.go b/cmd/changes_get_change.go index fbbeff12..30cded83 100644 --- a/cmd/changes_get_change.go +++ b/cmd/changes_get_change.go @@ -71,8 +71,10 @@ func GetChange(cmd *cobra.Command, args []string) error { } client := AuthenticatedChangesClient(ctx, oi) - if err := waitForChangeAnalysis(ctx, client, changeUuid, lf); err != nil { - return err + if viper.GetBool("wait") { + if err := waitForChangeAnalysis(ctx, client, changeUuid, lf); err != nil { + return err + } } app, _ = strings.CutSuffix(app, "/") @@ -142,7 +144,8 @@ func init() { getChangeCmd.PersistentFlags().String("status", "CHANGE_STATUS_DEFINING", "The expected status of the change. Use this with --ticket-link to get the first change with that status for a given ticket link. Allowed values: CHANGE_STATUS_DEFINING (ready for analysis/analysis in progress), CHANGE_STATUS_HAPPENING (deployment in progress), CHANGE_STATUS_DONE (deployment completed)") getChangeCmd.PersistentFlags().String("frontend", "", "The frontend base URL") - _ = submitPlanCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.") // MarkDeprecated only errors if the flag doesn't exist, we fall back to using app + cobra.CheckErr(getChangeCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.")) + getChangeCmd.PersistentFlags().Bool("wait", true, "Wait for analysis to complete before returning. Set to false to return immediately with the current status.") getChangeCmd.PersistentFlags().String("format", "json", "How to render the change. Possible values: json, markdown") getChangeCmd.PersistentFlags().StringSlice("risk-levels", []string{"high", "medium", "low"}, "Only show changes with the specified risk levels. Allowed values: high, medium, low") } diff --git a/cmd/changes_get_change_test.go b/cmd/changes_get_change_test.go index 55353e56..c014bf08 100644 --- a/cmd/changes_get_change_test.go +++ b/cmd/changes_get_change_test.go @@ -7,6 +7,20 @@ import ( "github.com/overmindtech/cli/go/sdp-go" ) +func TestGetChangeCmdHasWaitFlag(t *testing.T) { + t.Parallel() + + flag := getChangeCmd.PersistentFlags().Lookup("wait") + if flag == nil { + t.Error("Expected wait flag to be registered on get-change command") + return + } + + if flag.DefValue != "true" { + t.Errorf("Expected wait flag default value to be 'true', got %q", flag.DefValue) + } +} + func TestValidateChangeStatus(t *testing.T) { tests := []struct { name string diff --git a/cmd/changes_get_signals.go b/cmd/changes_get_signals.go index 2a84a139..0b0ac386 100644 --- a/cmd/changes_get_signals.go +++ b/cmd/changes_get_signals.go @@ -98,6 +98,6 @@ func init() { getSignalsCmd.PersistentFlags().String("status", "CHANGE_STATUS_DEFINING", "The expected status of the change. Use this with --ticket-link to get the first change with that status for a given ticket link. Allowed values: CHANGE_STATUS_DEFINING (ready for analysis/analysis in progress), CHANGE_STATUS_HAPPENING (deployment in progress), CHANGE_STATUS_DONE (deployment completed)") getSignalsCmd.PersistentFlags().String("frontend", "", "The frontend base URL") - _ = getSignalsCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.") // MarkDeprecated only errors if the flag doesn't exist, we fall back to using app + cobra.CheckErr(getSignalsCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.")) getSignalsCmd.PersistentFlags().String("format", "json", "How to render the signals. Possible values: json, markdown") } diff --git a/cmd/changes_start_analysis.go b/cmd/changes_start_analysis.go index db9d5731..73c7ac91 100644 --- a/cmd/changes_start_analysis.go +++ b/cmd/changes_start_analysis.go @@ -57,7 +57,7 @@ func StartAnalysis(cmd *cobra.Command, args []string) error { client := AuthenticatedChangesClient(ctx, oi) - _, err = client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ + resp, err := client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ Msg: &sdp.StartChangeAnalysisRequest{ ChangeUUID: changeUUID[:], ChangingItems: nil, // uses pre-stored items from AddPlannedChanges @@ -65,6 +65,7 @@ func StartAnalysis(cmd *cobra.Command, args []string) error { RoutineChangesConfigOverride: analysisConfig.RoutineChangesConfig, GithubOrganisationProfileOverride: analysisConfig.GithubOrgProfile, Knowledge: analysisConfig.KnowledgeFiles, + PostGithubComment: viper.GetBool("comment"), }, }) if err != nil { @@ -78,7 +79,13 @@ func StartAnalysis(cmd *cobra.Command, args []string) error { app, _ = strings.CutSuffix(app, "/") changeUrl := fmt.Sprintf("%v/changes/%v?utm_source=cli&cli_version=%v", app, changeUUID, tracing.Version()) log.WithContext(ctx).WithFields(lf).WithField("change-url", changeUrl).Info("Change analysis started") - fmt.Println(changeUrl) + + if viper.GetBool("comment") { + fmt.Printf("CHANGE_URL='%s'\n", changeUrl) + fmt.Printf("GITHUB_APP_ACTIVE='%v'\n", resp.Msg.GetGithubAppActive()) + } else { + fmt.Println(changeUrl) + } if viper.GetBool("wait") { log.WithContext(ctx).WithFields(lf).Info("Waiting for analysis to complete") diff --git a/cmd/changes_start_analysis_test.go b/cmd/changes_start_analysis_test.go index cb134645..9b80d3c0 100644 --- a/cmd/changes_start_analysis_test.go +++ b/cmd/changes_start_analysis_test.go @@ -27,6 +27,7 @@ func TestAddAnalysisFlags(t *testing.T) { {"blast-radius-max-time", "blast-radius-max-time", "duration"}, {"change-analysis-target-duration", "change-analysis-target-duration", "duration"}, {"signal-config", "signal-config", "string"}, + {"comment", "comment", "bool"}, } for _, tt := range tests { @@ -189,6 +190,7 @@ func TestStartAnalysisCmdFlags(t *testing.T) { {"blast-radius-link-depth", "blast-radius-link-depth"}, {"blast-radius-max-items", "blast-radius-max-items"}, {"signal-config", "signal-config"}, + {"comment flag", "comment"}, } for _, tt := range tests { @@ -205,6 +207,20 @@ func TestStartAnalysisCmdFlags(t *testing.T) { } } +func TestSubmitPlanCmdHasCommentFlag(t *testing.T) { + t.Parallel() + + flag := submitPlanCmd.PersistentFlags().Lookup("comment") + if flag == nil { + t.Error("Expected comment flag to be registered on submit-plan command") + return + } + + if flag.DefValue != "false" { + t.Errorf("Expected comment flag default value to be 'false', got %q", flag.DefValue) + } +} + func TestSubmitPlanCmdHasNoStartFlag(t *testing.T) { t.Parallel() diff --git a/cmd/changes_submit_plan.go b/cmd/changes_submit_plan.go index a716f074..a127a636 100644 --- a/cmd/changes_submit_plan.go +++ b/cmd/changes_submit_plan.go @@ -258,7 +258,12 @@ func SubmitPlan(cmd *cobra.Command, args []string) error { log.WithContext(ctx).WithFields(lf).Info("Re-using change") } + var githubAppActive bool + if viper.GetBool("no-start") { + if viper.GetBool("comment") { + log.WithContext(ctx).WithFields(lf).Info("--comment has no effect with --no-start; pass --comment to start-analysis instead") + } // Store planned changes without starting analysis (multi-plan workflow) _, err = client.AddPlannedChanges(ctx, &connect.Request[sdp.AddPlannedChangesRequest]{ Msg: &sdp.AddPlannedChangesRequest{ @@ -281,7 +286,7 @@ func SubmitPlan(cmd *cobra.Command, args []string) error { return err } - _, err = client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ + resp, err := client.StartChangeAnalysis(ctx, &connect.Request[sdp.StartChangeAnalysisRequest]{ Msg: &sdp.StartChangeAnalysisRequest{ ChangeUUID: changeUUID[:], ChangingItems: plannedChanges, @@ -289,6 +294,7 @@ func SubmitPlan(cmd *cobra.Command, args []string) error { RoutineChangesConfigOverride: analysisConfig.RoutineChangesConfig, GithubOrganisationProfileOverride: analysisConfig.GithubOrgProfile, Knowledge: analysisConfig.KnowledgeFiles, + PostGithubComment: viper.GetBool("comment"), }, }) if err != nil { @@ -298,12 +304,19 @@ func SubmitPlan(cmd *cobra.Command, args []string) error { message: "Failed to start change analysis", } } + githubAppActive = resp.Msg.GetGithubAppActive() } app, _ = strings.CutSuffix(app, "/") changeUrl := fmt.Sprintf("%v/changes/%v?utm_source=cli&cli_version=%v", app, changeUUID, tracing.Version()) log.WithContext(ctx).WithFields(lf).WithField("change-url", changeUrl).Info("Change ready") - fmt.Println(changeUrl) + + if viper.GetBool("comment") { + fmt.Printf("CHANGE_URL='%s'\n", changeUrl) + fmt.Printf("GITHUB_APP_ACTIVE='%v'\n", githubAppActive) + } else { + fmt.Println(changeUrl) + } return nil } @@ -385,7 +398,7 @@ func init() { addAnalysisFlags(submitPlanCmd) submitPlanCmd.PersistentFlags().String("frontend", "", "The frontend base URL") - _ = submitPlanCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.") // MarkDeprecated only errors if the flag doesn't exist, we fall back to using app + cobra.CheckErr(submitPlanCmd.PersistentFlags().MarkDeprecated("frontend", "This flag is no longer used and will be removed in a future release. Use the '--app' flag instead.")) submitPlanCmd.PersistentFlags().String("auto-tag-rules", "", "The path to the auto-tag rules file. If not provided, it will check the default location which is '.overmind/auto-tag-rules.yaml'. If no rules are found locally, the rules configured through the UI are used.") diff --git a/cmd/explore.go b/cmd/explore.go index 76711032..d3b671c8 100644 --- a/cmd/explore.go +++ b/cmd/explore.go @@ -666,7 +666,7 @@ func init() { // hidden flag to enable Azure preview support exploreCmd.PersistentFlags().Bool("enable-azure-preview", false, "Enable Azure source support (preview feature).") - exploreCmd.PersistentFlags().MarkHidden("enable-azure-preview") //nolint:errcheck // not possible to error + cobra.CheckErr(exploreCmd.PersistentFlags().MarkHidden("enable-azure-preview")) } // unifiedGCPConfigs collates the given GCP configs by project ID. diff --git a/cmd/flags.go b/cmd/flags.go index 102b69c5..19b426ec 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -130,9 +130,10 @@ func addAnalysisFlags(cmd *cobra.Command) { cmd.PersistentFlags().Int32("blast-radius-link-depth", 0, "Used in combination with '--blast-radius-max-items' to customise how many levels are traversed when calculating the blast radius. Larger numbers will result in a more comprehensive blast radius, but may take longer to calculate. Defaults to the account level settings.") cmd.PersistentFlags().Int32("blast-radius-max-items", 0, "Used in combination with '--blast-radius-link-depth' to customise how many items are included in the blast radius. Larger numbers will result in a more comprehensive blast radius, but may take longer to calculate. Defaults to the account level settings.") cmd.PersistentFlags().Duration("blast-radius-max-time", 0, "Maximum time duration for blast radius calculation (e.g., '5m', '15m', '30m'). When the time limit is reached, the analysis continues with risks identified up to that point. Defaults to the account level settings (QUICK: 10m, DETAILED: 15m, FULL: 30m). Valid range: 1m to 30m.") - _ = cmd.PersistentFlags().MarkDeprecated("blast-radius-max-time", "This flag is no longer used and will be removed in a future release. Use the '--change-analysis-target-duration' flag instead.") + cobra.CheckErr(cmd.PersistentFlags().MarkDeprecated("blast-radius-max-time", "This flag is no longer used and will be removed in a future release. Use the '--change-analysis-target-duration' flag instead.")) cmd.PersistentFlags().Duration("change-analysis-target-duration", 0, "Target duration for change analysis planning (e.g., '5m', '15m', '30m'). This is NOT a hard deadline - the blast radius phase uses 67% of this target to stop gracefully. The job can run slightly past this target and is only hard-stopped at 30 minutes. Defaults to the account level settings (QUICK: 10m, DETAILED: 15m, FULL: 30m). Valid range: 1m to 30m.") cmd.PersistentFlags().String("signal-config", "", "The path to the signal config file. If not provided, it will check the default location which is '.overmind/signal-config.yaml'. If no config is found locally, the config configured through the UI is used.") + cmd.PersistentFlags().Bool("comment", false, "Request the GitHub App to post analysis results as a PR comment. Requires the account to have the Overmind GitHub App installed with pull_requests:write.") } // AnalysisConfig holds all the configuration needed to start change analysis. diff --git a/cmd/knowledge_list.go b/cmd/knowledge_list.go index 44bdfc47..c6d041c9 100644 --- a/cmd/knowledge_list.go +++ b/cmd/knowledge_list.go @@ -107,5 +107,5 @@ func init() { knowledgeCmd.AddCommand(knowledgeListCmd) knowledgeListCmd.Flags().String("dir", ".", "Directory to start searching from") - knowledgeListCmd.Flags().MarkHidden("dir") //nolint:errcheck // not possible to error + cobra.CheckErr(knowledgeListCmd.Flags().MarkHidden("dir")) } diff --git a/cmd/terraform.go b/cmd/terraform.go index 0ea59a9e..f42b43a1 100644 --- a/cmd/terraform.go +++ b/cmd/terraform.go @@ -35,7 +35,7 @@ func init() { // hidden flag to enable Azure preview support terraformCmd.PersistentFlags().Bool("enable-azure-preview", false, "Enable Azure source support (preview feature).") - terraformCmd.PersistentFlags().MarkHidden("enable-azure-preview") //nolint:errcheck // not possible to error + cobra.CheckErr(terraformCmd.PersistentFlags().MarkHidden("enable-azure-preview")) } var applyOnlyArgs = []string{ From 7bf270b28de3aa9f73678bb251a439562baee165 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Thu, 12 Mar 2026 15:49:59 +0000 Subject: [PATCH 18/18] Run go mod tidy --- go.mod | 195 +-------------- go.sum | 731 --------------------------------------------------------- 2 files changed, 6 insertions(+), 920 deletions(-) diff --git a/go.mod b/go.mod index ed4ab614..0d293a59 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( cloud.google.com/go/bigtable v1.42.0 cloud.google.com/go/certificatemanager v1.9.6 cloud.google.com/go/compute v1.56.0 - cloud.google.com/go/compute/metadata v0.9.0 + cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/container v1.46.0 cloud.google.com/go/dataplex v1.28.0 cloud.google.com/go/dataproc/v2 v2.16.0 @@ -41,8 +41,6 @@ require ( cloud.google.com/go/storage v1.60.0 cloud.google.com/go/storagetransfer v1.13.1 connectrpc.com/connect v1.18.1 // v1.19.0 was faulty, wait until it is above this version - connectrpc.com/otelconnect v0.9.0 - github.com/1password/onepassword-sdk-go v0.4.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3 v3.0.0-beta.2 @@ -61,12 +59,6 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v3 v3.0.0 github.com/Masterminds/semver/v3 v3.4.0 github.com/MrAlias/otel-schema-utils v0.4.0-alpha - github.com/a-h/templ v0.3.1001 - github.com/adrg/strutil v0.3.1 - github.com/akedrou/textdiff v0.1.0 - github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 - github.com/antihax/optional v1.0.0 - github.com/auth0/go-auth0/v2 v2.6.0 github.com/auth0/go-jwt-middleware/v3 v3.0.0 github.com/aws/aws-sdk-go-v2 v1.41.3 github.com/aws/aws-sdk-go-v2/config v1.32.11 @@ -92,86 +84,50 @@ require ( github.com/aws/aws-sdk-go-v2/service/rds v1.116.2 github.com/aws/aws-sdk-go-v2/service/route53 v1.62.3 github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 - github.com/aws/aws-sdk-go-v2/service/sesv2 v1.59.4 github.com/aws/aws-sdk-go-v2/service/sns v1.39.13 github.com/aws/aws-sdk-go-v2/service/sqs v1.42.23 github.com/aws/aws-sdk-go-v2/service/ssm v1.68.2 github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 github.com/aws/smithy-go v1.24.2 - github.com/bombsimon/logrusr/v4 v4.1.0 - github.com/bradleyfalzon/ghinstallation/v2 v2.17.0 - github.com/brianvoe/gofakeit/v7 v7.14.1 github.com/cenkalti/backoff/v5 v5.0.3 github.com/charmbracelet/glamour v0.10.0 github.com/coder/websocket v1.8.14 - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/getsentry/sentry-go v0.43.0 github.com/go-jose/go-jose/v4 v4.1.3 - github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/google/btree v1.1.3 - github.com/google/go-github/v84 v84.0.0 github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.17.0 github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e - github.com/gorilla/mux v1.8.1 - github.com/harness/harness-go-sdk v0.7.13 github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/hcl/v2 v2.24.0 github.com/hashicorp/terraform-config-inspect v0.0.0-20260224005459-813a97530220 github.com/hashicorp/terraform-plugin-framework v1.18.0 github.com/hashicorp/terraform-plugin-go v0.30.0 github.com/hashicorp/terraform-plugin-testing v1.14.0 - github.com/invopop/jsonschema v0.13.0 - github.com/jackc/pgx/v5 v5.8.0 github.com/jedib0t/go-pretty/v6 v6.7.8 - github.com/jxskiss/base62 v1.1.0 - github.com/kaptinlin/jsonrepair v0.2.17 - github.com/lithammer/fuzzysearch v1.1.8 - github.com/manifoldco/promptui v0.9.0 - github.com/mavolin/go-htmx v1.0.0 - github.com/mergestat/timediff v0.0.4 + github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/micahhausler/aws-iam-policy v0.4.4 github.com/miekg/dns v1.1.72 github.com/mitchellh/go-homedir v1.1.0 - github.com/mitchellh/go-ps v1.0.0 - github.com/modelcontextprotocol/go-sdk v1.4.0 github.com/muesli/reflow v0.3.0 github.com/nats-io/jwt/v2 v2.8.0 github.com/nats-io/nats-server/v2 v2.12.4 github.com/nats-io/nats.go v1.49.0 github.com/nats-io/nkeys v0.4.15 - github.com/neo4j/neo4j-go-driver/v6 v6.0.0 - github.com/onsi/ginkgo/v2 v2.28.1 - github.com/onsi/gomega v1.39.1 - github.com/openai/openai-go/v3 v3.26.0 + github.com/onsi/ginkgo/v2 v2.28.1 // indirect + github.com/onsi/gomega v1.39.1 // indirect github.com/openrdap/rdap v0.9.2-0.20240517203139-eb57b3a8dedd - github.com/overmindtech/otelpgx v0.10.1-0.20260303210427-65bf1016045e github.com/overmindtech/pterm v0.0.0-20240919144758-04d94ccb2297 - github.com/pborman/ansi v1.0.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c - github.com/posthog/posthog-go v1.10.0 - github.com/projectdiscovery/subfinder/v2 v2.12.0 - github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf - github.com/resend/resend-go/v3 v3.1.1 - github.com/riverqueue/river v0.31.0 - github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0 - github.com/riverqueue/river/rivertype v0.31.0 - github.com/riverqueue/rivercontrib/otelriver v0.7.0 - github.com/rs/cors v1.11.1 - github.com/samber/slog-logrus/v2 v2.5.3 - github.com/sashabaranov/go-openai v1.41.2 - github.com/serpapi/serpapi-golang v0.0.0-20260126142127-0e41c7993cda github.com/sirupsen/logrus v1.9.4 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 - github.com/stripe/stripe-go/v84 v84.4.0 - github.com/tiktoken-go/tokenizer v0.7.0 github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2 - github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/xiam/dig v0.0.0-20191116195832-893b5fb5093b github.com/zclconf/go-cty v1.18.0 go.etcd.io/bbolt v1.4.3 @@ -200,16 +156,11 @@ require ( k8s.io/api v0.35.2 k8s.io/apimachinery v0.35.2 k8s.io/client-go v0.35.2 - k8s.io/component-base v0.35.2 - modernc.org/sqlite v1.46.1 - riverqueue.com/riverui v0.15.0 - sigs.k8s.io/controller-runtime v0.23.3 sigs.k8s.io/kind v0.31.0 - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect ) require ( - aead.dev/minisign v0.2.0 // indirect al.essio.dev/pkg/shellescape v1.5.1 // indirect atomicgo.dev/cursor v0.2.0 // indirect atomicgo.dev/schedule v0.1.0 // indirect @@ -224,23 +175,15 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect - github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect - github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect github.com/ProtonMail/go-crypto v1.1.6 // indirect - github.com/PuerkitoBio/rehttp v1.4.0 // indirect - github.com/STARRY-S/zip v0.2.1 // indirect - github.com/VividCortex/ewma v1.2.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect - github.com/akrylysov/pogreb v0.10.1 // indirect github.com/alecthomas/chroma/v2 v2.16.0 // indirect github.com/alecthomas/kingpin/v2 v2.4.0 // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect - github.com/andybalholm/brotli v1.1.1 // indirect github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/apache/arrow/go/v15 v15.0.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect @@ -256,14 +199,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/bodgit/plumbing v1.3.0 // indirect - github.com/bodgit/sevenzip v1.6.0 // indirect - github.com/bodgit/windows v1.0.1 // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.4.2 // indirect github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect; being pulled by glamour, this will be resolved in https://github.com/charmbracelet/glamour/pull/408 @@ -274,69 +209,40 @@ require ( github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect - github.com/cheggaaa/pb/v3 v3.1.4 // indirect - github.com/chzyer/readline v1.5.1 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/cloudflare/circl v1.6.3 // indirect github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect - github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect github.com/containerd/console v1.0.4 // indirect - github.com/corpix/uarand v0.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/docker/go-units v0.5.0 // indirect - github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect - github.com/extism/go-sdk v1.7.1 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect - github.com/gaissmai/bart v0.20.4 // indirect - github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.1 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.1 // indirect - github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/google/cel-go v0.27.0 // indirect github.com/google/flatbuffers v23.5.26+incompatible // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/go-github/v30 v30.1.0 // indirect - github.com/google/go-github/v75 v75.0.0 // indirect - github.com/google/go-querystring v1.2.0 // indirect github.com/google/go-tpm v0.9.8 // indirect - github.com/google/jsonschema-go v0.4.2 // indirect - github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.12 // indirect github.com/gookit/color v1.5.4 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect - github.com/hako/durafmt v0.0.0-20210316092057-3a2c319c1acd // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -346,7 +252,6 @@ require ( github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hc-install v0.9.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect @@ -357,42 +262,26 @@ require ( github.com/hashicorp/terraform-registry-address v0.4.0 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.2 // indirect - github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.3 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/klauspost/pgzip v1.2.6 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/leodido/go-urn v1.4.0 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect github.com/lestrrat-go/dsig v1.0.0 // indirect github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/httprc v1.0.6 // indirect github.com/lestrrat-go/httprc/v3 v3.0.3 // indirect - github.com/lestrrat-go/iter v1.0.2 // indirect - github.com/lestrrat-go/jwx/v2 v2.1.6 // indirect github.com/lestrrat-go/jwx/v3 v3.0.12 // indirect - github.com/lestrrat-go/option v1.0.1 // indirect github.com/lestrrat-go/option/v2 v2.0.0 // indirect - github.com/lib/pq v1.10.9 // indirect - github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect - github.com/mholt/archives v0.1.0 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect - github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -404,107 +293,43 @@ require ( github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/ncruces/go-strftime v1.0.0 // indirect - github.com/nwaples/rardecode/v2 v2.2.0 // indirect github.com/oklog/run v1.1.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pkoukk/tiktoken-go v0.1.7 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/projectdiscovery/blackrock v0.0.1 // indirect - github.com/projectdiscovery/cdncheck v1.1.24 // indirect - github.com/projectdiscovery/chaos-client v0.5.2 // indirect - github.com/projectdiscovery/dnsx v1.2.2 // indirect - github.com/projectdiscovery/fastdialer v0.4.1 // indirect - github.com/projectdiscovery/goflags v0.1.74 // indirect - github.com/projectdiscovery/gologger v1.1.54 // indirect - github.com/projectdiscovery/hmap v0.0.90 // indirect - github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect - github.com/projectdiscovery/networkpolicy v0.1.16 // indirect - github.com/projectdiscovery/ratelimit v0.0.81 // indirect - github.com/projectdiscovery/retryabledns v1.0.102 // indirect - github.com/projectdiscovery/retryablehttp-go v1.0.115 // indirect - github.com/projectdiscovery/utils v0.4.21 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - github.com/refraction-networking/utls v1.8.2 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/riverqueue/apiframe v0.0.0-20251229202423-2b52ce1c482e // indirect - github.com/riverqueue/river/riverdriver v0.31.0 // indirect - github.com/riverqueue/river/rivershared v0.31.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rs/xid v1.5.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect - github.com/samber/lo v1.52.0 // indirect - github.com/samber/slog-common v0.20.0 // indirect github.com/segmentio/asm v1.2.1 // indirect - github.com/segmentio/encoding v0.5.3 // indirect - github.com/shirou/gopsutil/v3 v3.23.7 // indirect - github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/sorairolake/lzip-go v0.3.5 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/syndtr/goleveldb v1.0.0 // indirect - github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 // indirect - github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 // indirect - github.com/tetratelabs/wazero v1.11.0 // indirect - github.com/therootcompany/xz v1.0.1 // indirect - github.com/tidwall/btree v1.6.0 // indirect - github.com/tidwall/buntdb v1.3.0 // indirect - github.com/tidwall/gjson v1.18.0 // indirect - github.com/tidwall/grect v0.1.4 // indirect - github.com/tidwall/match v1.2.0 // indirect - github.com/tidwall/pretty v1.2.1 // indirect - github.com/tidwall/rtred v0.1.2 // indirect - github.com/tidwall/sjson v1.2.5 // indirect - github.com/tidwall/tinyqueue v0.1.1 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect - github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect - github.com/ulikunitz/xz v0.5.15 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect github.com/valyala/fastjson v1.6.7 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/weppos/publicsuffix-go v0.30.1 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/xiam/to v0.0.0-20191116183551-8328998fc0ed // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yuin/goldmark v1.7.10 // indirect github.com/yuin/goldmark-emoji v1.0.5 // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zcalusic/sysinfo v1.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect - github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect - go.devnw.com/structs v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect go.opentelemetry.io/otel/log v0.11.0 // indirect go.opentelemetry.io/otel/metric v1.41.0 // indirect go.opentelemetry.io/otel/schema v0.0.12 // indirect go.opentelemetry.io/otel/sdk/metric v1.41.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/mod v0.33.0 // indirect @@ -514,22 +339,14 @@ require ( golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.41.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect - gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/apiextensions-apiserver v0.35.0 // indirect - k8s.io/apiserver v0.35.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect - modernc.org/libc v1.67.6 // indirect - modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.11.0 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/go.sum b/go.sum index 073d217e..e7c3971c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk= -aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho= al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= @@ -18,15 +16,6 @@ cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo= charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/aiplatform v1.119.0 h1:Fum1ighlxsmwbmaf0nhuMDebcKJkpx2mgmd1YcyXaYY= @@ -35,8 +24,6 @@ cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.74.0 h1:Q6bAMv+eyvufOpIrfrYxhM46qq1D3ZQTdgUDQqKS+n8= cloud.google.com/go/bigquery v1.74.0/go.mod h1:iViO7Cx3A/cRKcHNRsHB3yqGAMInFBswrE9Pxazsc90= cloud.google.com/go/bigtable v1.42.0 h1:SREvT4jLhJQZXUjsLmFs/1SMQJ+rKEj1cJuPE9liQs8= @@ -45,7 +32,6 @@ cloud.google.com/go/certificatemanager v1.9.6 h1:v5X8X+THKrS9OFZb6k0GRDP1WQxLXTd cloud.google.com/go/certificatemanager v1.9.6/go.mod h1:vWogV874jKZkSRDFCMM3r7wqybv8WXs3XhyNff6o/Zo= cloud.google.com/go/compute v1.56.0 h1:e8xch/mR0tJoUBj3nhNb96+MOQ1JGVGB+rBfVzWEU5I= cloud.google.com/go/compute v1.56.0/go.mod h1:fMFC0mRv+fW2ISg7M3tpDfpZ+kkrHpC/ImNFRCYiNK0= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/container v1.46.0 h1:xX94Lo3xrS5OkdMWKvpEVAbBwjN9uleVv6vOi02fL4s= @@ -56,7 +42,6 @@ cloud.google.com/go/dataplex v1.28.0 h1:rROI3iqMVI9nXT701ULoFRETQVAOAPC3mPSWFDxX cloud.google.com/go/dataplex v1.28.0/go.mod h1:VB+xlYJiJ5kreonXsa2cHPj0A3CfPh/mgiHG4JFhbUA= cloud.google.com/go/dataproc/v2 v2.16.0 h1:0g2hnjlQ8SQTnNeu+Bqqa61QPssfSZF3t+9ldRmx+VQ= cloud.google.com/go/dataproc/v2 v2.16.0/go.mod h1:HlzFg8k1SK+bJN3Zsy2z5g6OZS1D4DYiDUgJtF0gJnE= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/filestore v1.10.3 h1:3KZifUVTqGhNNv6MLeONYth1HjlVM4vDhaH+xrdPljU= cloud.google.com/go/filestore v1.10.3/go.mod h1:94ZGyLTx9j+aWKozPQ6Wbq1DuImie/L/HIdGMshtwac= cloud.google.com/go/functions v1.19.7 h1:7LcOD18euIVGRUPaeCmgO6vfWSLNIsi6STWRQcdANG8= @@ -75,8 +60,6 @@ cloud.google.com/go/networksecurity v0.11.0 h1:+ahtCqEqwHw3a3UIeG21vT817xt9kkDDA cloud.google.com/go/networksecurity v0.11.0/go.mod h1:JLgDsg4tOyJ3eMO8lypjqMftbfd60SJ+P7T+DUmWBsM= cloud.google.com/go/orgpolicy v1.15.1 h1:0hq12wxNwcfUMojr5j3EjWECSInIuyYDhkAWXTomRhc= cloud.google.com/go/orgpolicy v1.15.1/go.mod h1:bpvi9YIyU7wCW9WiXL/ZKT7pd2Ovegyr2xENIeRX5q0= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/redis v1.18.3 h1:6LI8zSt+vmE3WQ7hE5GsJ13CbJBLV1qUw6B7CY31Wcw= cloud.google.com/go/redis v1.18.3/go.mod h1:x8HtXZbvMBDNT6hMHaQ022Pos5d7SP7YsUH8fCJ2Wm4= cloud.google.com/go/resourcemanager v1.10.7 h1:oPZKIdjyVTuag+D4HF7HO0mnSqcqgjcuA18xblwA0V0= @@ -89,8 +72,6 @@ cloud.google.com/go/securitycentermanagement v1.1.6 h1:XFqjKq4ZpKTj8xCXWs/mTmh/U cloud.google.com/go/securitycentermanagement v1.1.6/go.mod h1:nt5Z6rU4s2/j8R/EQxG5K7OfVAfAfwo89j0Nx2Srzaw= cloud.google.com/go/spanner v1.88.0 h1:HS+5TuEYZOVOXj9K+0EtrbTw7bKBLrMe3vgGsbnehmU= cloud.google.com/go/spanner v1.88.0/go.mod h1:MzulBwuuYwQUVdkZXBBFapmXee3N+sQrj2T/yup6uEE= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.60.0 h1:oBfZrSOCimggVNz9Y/bXY35uUcts7OViubeddTTVzQ8= cloud.google.com/go/storage v1.60.0/go.mod h1:q+5196hXfejkctrnx+VYU8RKQr/L3c0cBIlrjmiAKE0= cloud.google.com/go/storagetransfer v1.13.1 h1:Sjukr1LtUt7vLTHNvGc2gaAqlXNFeDFRIRmWGrFaJlY= @@ -99,13 +80,8 @@ cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= -connectrpc.com/otelconnect v0.9.0 h1:NggB3pzRC3pukQWaYbRHJulxuXvmCKCKkQ9hbrHAWoA= -connectrpc.com/otelconnect v0.9.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/1password/onepassword-sdk-go v0.4.0 h1:Nou39yuC6Q0om03irkh5UurfPdX3wx26qZZhQeC9TBU= -github.com/1password/onepassword-sdk-go v0.4.0/go.mod h1:j/CbzhucTywjlYrd6SE6k0LcQaFZ2l8OLBsAsOYtvD0= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= @@ -156,10 +132,8 @@ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= @@ -183,29 +157,10 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/MrAlias/otel-schema-utils v0.4.0-alpha h1:6ZG9rw4NvxKwRp2Bmnfr8WJZVWLhK4e5n3+ezXE6Z2g= github.com/MrAlias/otel-schema-utils v0.4.0-alpha/go.mod h1:baehOhES9qiLv9xMcsY6ZQlKLBRR89XVJEvU7Yz3qJk= -github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub47e7kd2PLZeACxc1LkiiNoDOFRClE= -github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4= -github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8= -github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/PuerkitoBio/rehttp v1.4.0 h1:rIN7A2s+O9fmHUM1vUcInvlHj9Ysql4hE+Y0wcl/xk8= -github.com/PuerkitoBio/rehttp v1.4.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= -github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg= -github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4= -github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= -github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= -github.com/a-h/templ v0.3.1001 h1:yHDTgexACdJttyiyamcTHXr2QkIeVF1MukLy44EAhMY= -github.com/a-h/templ v0.3.1001/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo= -github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4= -github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/akedrou/textdiff v0.1.0 h1:K7nbOVQju7/coCXnJRJ2fsltTwbSvC+M4hKBUJRBRGY= -github.com/akedrou/textdiff v0.1.0/go.mod h1:a9CCC49AKtFTmVDNFHDlCg7V/M7C7QExDAhb2SkL6DQ= -github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w= -github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.16.0 h1:QC5ZMizk67+HzxFDjQ4ASjni5kWBTGiigRG1u23IGvA= @@ -216,12 +171,6 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= -github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 h1:TdGQS+RoR4AUO6gqUL74yK1dz/Arrt/WG+dxOj6Yo6A= -github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4/go.mod h1:GJxtdOs9K4neo8Gg65CjJ7jNautmldGli5/OFNabOoo= -github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= @@ -231,11 +180,7 @@ github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+ye github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= -github.com/auth0/go-auth0/v2 v2.6.0 h1:KCoLxTcH8qXPYbwKZxxFrL/6P+P+Zc58BQPL6w0Kt30= -github.com/auth0/go-auth0/v2 v2.6.0/go.mod h1:XVRck9fw1EIw1z4guYcbKFGmElnexb+xOvQ/0U1hHd0= github.com/auth0/go-jwt-middleware/v3 v3.0.0 h1:+rvUPCT+VbAuK4tpS13fWfZrMyqTwLopt3VoY0Y7kvA= github.com/auth0/go-jwt-middleware/v3 v3.0.0/go.mod h1:iU42jqjRyeKbf9YYSnRnolr836gk6Ty/jnUNuVq2b0o= github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA= @@ -306,8 +251,6 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.62.3 h1:JRPXnIr0WwFsSHBmuCvT/uh0 github.com/aws/aws-sdk-go-v2/service/route53 v1.62.3/go.mod h1:DHddp7OO4bY467WVCqWBzk5+aEWn7vqYkap7UigJzGk= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA= -github.com/aws/aws-sdk-go-v2/service/sesv2 v1.59.4 h1:PEz6RPI6hG3GHiaMPmrh4iM684GOdIrEc9L30FaSC2k= -github.com/aws/aws-sdk-go-v2/service/sesv2 v1.59.4/go.mod h1:4dOflh7HfqHcjF1OIlt9Tr1T0rDsh906Yc75lAa2CJI= github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row= github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU= github.com/aws/aws-sdk-go-v2/service/sns v1.39.13 h1:8xP94tDzFpgwIOsusGiEFHPaqrpckDojoErk/ZFZTio= @@ -324,50 +267,18 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 h1:XQTQTF75vnug2TXS8m7CVJfC2nni github.com/aws/aws-sdk-go-v2/service/sts v1.41.8/go.mod h1:Xgx+PR1NUOjNmQY+tRMnouRp83JRM8pRMw/vCaVhPkI= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= -github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= -github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM= github.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoGXLwLQOZE= -github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY= -github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= -github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= -github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A= -github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= -github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= -github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= -github.com/bombsimon/logrusr/v4 v4.1.0 h1:uZNPbwusB0eUXlO8hIUwStE6Lr5bLN6IgYgG+75kuh4= -github.com/bombsimon/logrusr/v4 v4.1.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhOR03TRc6im0l8= -github.com/bradleyfalzon/ghinstallation/v2 v2.17.0 h1:SmbUK/GxpAspRjSQbB6ARvH+ArzlNzTtHydNyXUQ6zg= -github.com/bradleyfalzon/ghinstallation/v2 v2.17.0/go.mod h1:vuD/xvJT9Y+ZVZRv4HQ42cMyPFIYqpc7AbB4Gvt/DlY= github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= -github.com/brianvoe/gofakeit/v7 v7.14.1 h1:a7fe3fonbj0cW3wgl5VwIKfZtiH9C3cLnwcIXWT7sow= -github.com/brianvoe/gofakeit/v7 v7.14.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY= @@ -392,36 +303,19 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8 github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= -github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo= -github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= -github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= -github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= -github.com/corpix/uarand v0.2.0 h1:U98xXwud/AVuCpkpgfPF7J5TQgr7R5tqT8VZP5KWbzE= -github.com/corpix/uarand v0.2.0/go.mod h1:/3Z1QIqWkDIhf6XWn/08/uMHoQ8JUoTIKc2iPchBOmM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= @@ -431,40 +325,22 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= -github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= -github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= -github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -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/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1 h1:idfl8M8rPW93NehFw5H1qqH8yG158t5POr+LX9avbJY= -github.com/dylibso/observe-sdk/go v0.0.0-20240828172851-9145d8ad07e1/go.mod h1:C8DzXehI4zAbrdlbtOByKX6pfivJTBiV9Jjqv56Yd9Q= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= -github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw= -github.com/extism/go-sdk v1.7.1/go.mod h1:IT+Xdg5AZM9hVtpFUA+uZCJMge/hbvshl8bwzLtFyKA= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -472,23 +348,12 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= -github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= -github.com/gaissmai/bart v0.20.4 h1:Ik47r1fy3jRVU+1eYzKSW3ho2UgBVTVnUS8O993584U= -github.com/gaissmai/bart v0.20.4/go.mod h1:cEed+ge8dalcbpi8wtS9x9m2hn/fNJH5suhdGQOHnYk= github.com/getsentry/sentry-go v0.43.0 h1:XbXLpFicpo8HmBDaInk7dum18G9KSLcjZiyUKS+hLW4= github.com/getsentry/sentry-go v0.43.0/go.mod h1:XDotiNZbgf5U8bPDUAfvcFmOnMQQceESxyKaObSssW0= -github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= -github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= -github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= -github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= -github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= -github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -497,77 +362,36 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= -github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e h1:Lf/gRkoycfOBPa42vU2bbgPurFong6zXeFtPoxholzU= -github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= -github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= -github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= -github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= -github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= -github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= @@ -576,47 +400,17 @@ github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8i github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= -github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= -github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= -github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= -github.com/google/go-github/v75 v75.0.0 h1:k7q8Bvg+W5KxRl9Tjq16a9XEgVY1pwuiG5sIL7435Ic= -github.com/google/go-github/v75 v75.0.0/go.mod h1:H3LUJEA1TCrzuUqtdAQniBNwuKiQIqdGKgBo1/M/uqI= -github.com/google/go-github/v84 v84.0.0 h1:I/0Xn5IuChMe8TdmI2bbim5nyhaRFJ7DEdzmD2w+yVA= -github.com/google/go-github/v84 v84.0.0/go.mod h1:WwYL1z1ajRdlaPszjVu/47x1L0PXukJBn73xsiYrRRQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -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/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= -github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -625,8 +419,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.12 h1:Fg+zsqzYEs1ZnvmcztTYxhgCBsx3eEhEwQ1W/lHq/sQ= github.com/googleapis/enterprise-certificate-proxy v0.3.12/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= @@ -637,14 +429,8 @@ github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IP github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= -github.com/hako/durafmt v0.0.0-20210316092057-3a2c319c1acd h1:FsX+T6wA8spPe4c1K9vi7T0LvNCO1TTqiL8u7Wok2hw= -github.com/hako/durafmt v0.0.0-20210316092057-3a2c319c1acd/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= -github.com/harness/harness-go-sdk v0.7.13 h1:lLiliIivyXW/8L7n244q45hdVKNCYprnfztyes4ew7k= -github.com/harness/harness-go-sdk v0.7.13/go.mod h1:iEAGFfIm0MOFJxN6tqMQSPZiEO/Dz1joLDHrkEU3lps= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -668,10 +454,6 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -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/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -704,24 +486,8 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8 github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f h1:Fnl4pzx8SR7k7JuzyW8lEtSFH6EQ8xgcypgIn8pcGIE= -github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= -github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= -github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 h1:D/V0gu4zQ3cL2WKeVNVM4r2gLxGGf6McLwgXzRTo2RQ= -github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= -github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= -github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= -github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -730,39 +496,21 @@ github.com/jedib0t/go-pretty/v6 v6.7.8 h1:BVYrDy5DPBA3Qn9ICT+PokP9cvCv1KaHv2i+Hc github.com/jedib0t/go-pretty/v6 v6.7.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= -github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= -github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= -github.com/kaptinlin/jsonrepair v0.2.17 h1:fkEom1MBG98QeN7uaJpKBRA9st3bPdS32RK+im/IjCU= -github.com/kaptinlin/jsonrepair v0.2.17/go.mod h1:Hbq/F0frQBVClHW/oQXixaCPysZ6gdzpeUBZPpWQtAQ= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= -github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -772,8 +520,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= @@ -782,36 +528,18 @@ github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7 github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= -github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k= -github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/httprc/v3 v3.0.3 h1:WjLHWkDkgWXeIUrKi/7lS/sGq2DjkSAwdTbH5RHXAKs= github.com/lestrrat-go/httprc/v3 v3.0.3/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= -github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= -github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx/v2 v2.1.6 h1:hxM1gfDILk/l5ylers6BX/Eq1m/pnxe9NBwW6lVfecA= -github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU= github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg= github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8= -github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= -github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= -github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= -github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= -github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= -github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= -github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= @@ -824,14 +552,6 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/mavolin/go-htmx v1.0.0 h1:43rZuemWd23zrMcTU939EsflXjOPxtHy9VraT1CZ6qQ= -github.com/mavolin/go-htmx v1.0.0/go.mod h1:r6O09gzKou9kutq3UiDPZ//Q7IeBCMcs8US5/sHFbvg= -github.com/mergestat/timediff v0.0.4 h1:NZ3sqG/6K9flhTubdltmRx3RBfIiYv6LsGP+4FlXMM8= -github.com/mergestat/timediff v0.0.4/go.mod h1:yvMUaRu2oetc+9IbPLYBJviz6sA7xz8OXMDfhBl7YSI= -github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= -github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= -github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q= -github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I= github.com/micahhausler/aws-iam-policy v0.4.4 h1:1aMhJ+0CkvUJ8HGN1chX+noXHs8uvGLkD7xIBeYd31c= github.com/micahhausler/aws-iam-policy v0.4.4/go.mod h1:H+yWljTu4XWJjNJJYgrPUai0AUTGNHc8pumkN57/foI= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= @@ -840,14 +560,10 @@ github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= -github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc= -github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= -github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -856,16 +572,12 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modelcontextprotocol/go-sdk v1.4.0 h1:u0kr8lbJc1oBcawK7Df+/ajNMpIDFE41OEPxdeTLOn8= -github.com/modelcontextprotocol/go-sdk v1.4.0/go.mod h1:Nxc2n+n/GdCebUaqCOhTetptS17SXXNu9IfNTaLDi1E= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= -github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= @@ -884,36 +596,16 @@ github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= -github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/neo4j/neo4j-go-driver/v6 v6.0.0 h1:xVAi6YLOfzXUx+1Lc/F2dUhpbN76BfKleZbAlnDFRiA= -github.com/neo4j/neo4j-go-driver/v6 v6.0.0/go.mod h1:hzSTfNfM31p1uRSzL1F/BAYOgaiTarE6OAQBajfsm+I= -github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= -github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= 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.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE= -github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= github.com/openrdap/rdap v0.9.2-0.20240517203139-eb57b3a8dedd h1:UuQycBx6K0lB0/IfHePshOYjlrptkF4FoApFP2Y4s3k= github.com/openrdap/rdap v0.9.2-0.20240517203139-eb57b3a8dedd/go.mod h1:391Ww1JbjG4FHOlvQqCd6n25CCCPE64JzC5cCYPxhyM= -github.com/overmindtech/otelpgx v0.10.1-0.20260303210427-65bf1016045e h1:vP/Zs8Nbd902stVf7hBOd3VP/lIECgAjWR8pNBwcOu4= -github.com/overmindtech/otelpgx v0.10.1-0.20260303210427-65bf1016045e/go.mod h1:GtSjAg9Irz03mc8tPIh9/bKOx63sqyO752SABZhBdj0= github.com/overmindtech/pterm v0.0.0-20240919144758-04d94ccb2297 h1:ih4bqBMHTCtg3lMwJszNkMGO9n7Uoe0WX5be1/x+s+g= github.com/overmindtech/pterm v0.0.0-20240919144758-04d94ccb2297/go.mod h1:bRQZYnvLrW1S5wYT6tbQnun8NpO5X6zP5cY3VKuDc4U= -github.com/pborman/ansi v1.0.0 h1:OqjHMhvlSuCCV5JT07yqPuJPQzQl+WXsiZ14gZsqOrQ= -github.com/pborman/ansi v1.0.0/go.mod h1:SgWzwMAx1X/Ez7i90VqF8LRiQtx52pWDiQP+x3iGnzw= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -928,58 +620,13 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmd github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkoukk/tiktoken-go v0.1.7 h1:qOBHXX4PHtvIvmOtyg1EeKlwFRiMKAcoMp4Q+bLQDmw= -github.com/pkoukk/tiktoken-go v0.1.7/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posthog/posthog-go v1.10.0 h1:wfoy7Jfb4LigCoHYyMZoiJmmEoCLOkSaYfDxM/NtCqY= -github.com/posthog/posthog-go v1.10.0/go.mod h1:wB3/9Q7d9gGb1P/yf/Wri9VBlbP8oA8z++prRzL5OcY= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= -github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= -github.com/projectdiscovery/cdncheck v1.1.24 h1:6pJ4XnovIrTWzlCJs5/QD1tv6wvK0wiICmmdY0/8WAs= -github.com/projectdiscovery/cdncheck v1.1.24/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U= -github.com/projectdiscovery/chaos-client v0.5.2 h1:dN+7GXEypsJAbCD//dBcUxzAEAEH1fjc/7Rf4F/RiNU= -github.com/projectdiscovery/chaos-client v0.5.2/go.mod h1:KnoJ/NJPhll42uaqlDga6oafFfNw5l2XI2ajRijtDuU= -github.com/projectdiscovery/dnsx v1.2.2 h1:ZjUov0GOyrS8ERlKAAhk+AOkqzaYHBzCP0qZfO+6Ihg= -github.com/projectdiscovery/dnsx v1.2.2/go.mod h1:3iYm86OEqo0WxeGDkVl5WZNmG0qYE5TYNx8fBg6wX1I= -github.com/projectdiscovery/fastdialer v0.4.1 h1:kp6Q0odo0VZ0vZIGOn+q9aLgBSk6uYoD1MsjCAH8+h4= -github.com/projectdiscovery/fastdialer v0.4.1/go.mod h1:875Wlggf0JAz+fDIPwUQeeBqEF6nJA71XVrjuTZCV7I= -github.com/projectdiscovery/goflags v0.1.74 h1:n85uTRj5qMosm0PFBfsvOL24I7TdWRcWq/1GynhXS7c= -github.com/projectdiscovery/goflags v0.1.74/go.mod h1:UMc9/7dFz2oln+10tv6cy+7WZKTHf9UGhaNkF95emh4= -github.com/projectdiscovery/gologger v1.1.54 h1:WMzvJ8j/4gGfPKpCttSTaYCVDU1MWQSJnk3wU8/U6Ws= -github.com/projectdiscovery/gologger v1.1.54/go.mod h1:vza/8pe2OKOt+ujFWncngknad1XWr8EnLKlbcejOyUE= -github.com/projectdiscovery/hmap v0.0.90 h1:p8HWGvPI88hgJoAb4ayR1Oo5VzqPrOCdFG7mASUhQI4= -github.com/projectdiscovery/hmap v0.0.90/go.mod h1:dcjd9P82mkBpFGEy0wBU/3qql5Bx14kmJZvVg7o7vXY= -github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE= -github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI= -github.com/projectdiscovery/networkpolicy v0.1.16 h1:H2VnLmMD7SvxF+rao+639nn8KX/kbPFY+mc8FxeltsI= -github.com/projectdiscovery/networkpolicy v0.1.16/go.mod h1:Vs/IRcJq4QUicjd/tl9gkhQWy7d/LssOwWbaz4buJ0U= -github.com/projectdiscovery/ratelimit v0.0.81 h1:u6lW+rAhS/UO0amHTYmYLipPK8NEotA9521hdojBtgI= -github.com/projectdiscovery/ratelimit v0.0.81/go.mod h1:tK04WXHuC4i6AsFkByInODSNf45gd9sfaMHzmy2bAsA= -github.com/projectdiscovery/retryabledns v1.0.102 h1:R8PzFCVofqLX3Bn4kdjOsE9wZ83FQjXZMDNs4/bHxzI= -github.com/projectdiscovery/retryabledns v1.0.102/go.mod h1:3+GL+YuHpV0Fp6UG7MbIG8mVxXHjfPO5ioQdwlnV08E= -github.com/projectdiscovery/retryablehttp-go v1.0.115 h1:ubIaVyHNj0/qxNv4gar+8/+L3G2Fhpfk54iMDctC7+E= -github.com/projectdiscovery/retryablehttp-go v1.0.115/go.mod h1:XlxLSMBVM7fTXeLVOLjVn1FLuRgQtD49NMFs9sQygfA= -github.com/projectdiscovery/subfinder/v2 v2.12.0 h1:MgEYn0F2qLvr63BWpV9jNjFiD8i9oXI3dp02tAGRft0= -github.com/projectdiscovery/subfinder/v2 v2.12.0/go.mod h1:FNy+bkJwZjUUWLte6T91IRBISqWDZ/q+ygUmoe8eb/w= -github.com/projectdiscovery/utils v0.4.21 h1:yAothTUSF6NwZ9yoC4iGe5gSBrovqKR9JwwW3msxk3Q= -github.com/projectdiscovery/utils v0.4.21/go.mod h1:HJuJFqjB6EmVaDl0ilFPKvLoMaX2GyE6Il2TqKXNs8I= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= @@ -989,82 +636,26 @@ github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5b github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/pterm/pterm v0.12.53 h1:8ERV5eXyvXlAIY8LRrhapPS34j7IKKDAnb7o1Ih3T0w= github.com/pterm/pterm v0.12.53/go.mod h1:BY2H3GtX2BX0ULqLY11C2CusIqnxsYerbkil3XvXIBg= -github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf h1:NxGxgo0KmC8w9fdn8jLCyG1SDrR/Vxbfa1nWErS3pmw= -github.com/qhenkart/anthropic-tokenizer-go v0.0.0-20231011194518-5519949e0faf/go.mod h1:q6RK8Iv6obzk6i0rnLyYPtppwZ5uXJLloL3oxmfrwm8= -github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo= -github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/resend/resend-go/v3 v3.1.1 h1:Uwpf/tZU+O/r/3nMWE6zUAMIG9dX/vTBS3wlQzYJKSw= -github.com/resend/resend-go/v3 v3.1.1/go.mod h1:iI7VA0NoGjWvsNii5iNC5Dy0llsI3HncXPejhniYzwE= -github.com/riverqueue/apiframe v0.0.0-20251229202423-2b52ce1c482e h1:OwOgxT3MRpOj5Mp6DhFdZP43FOQOf2hhywAuT5XZCR4= -github.com/riverqueue/apiframe v0.0.0-20251229202423-2b52ce1c482e/go.mod h1:O7UmsAMjpMYuToN4au5GNXdmN1gli+5FTldgXqAfaD0= -github.com/riverqueue/river v0.31.0 h1:BERwce/WS4Guter0/A3GyTDP+1rxl6vFHyBQv+U/5tM= -github.com/riverqueue/river v0.31.0/go.mod h1:Aqbb/jBrFMvh6rbe6SDC6XVZnS0v1W+QQPjejRvyHzk= -github.com/riverqueue/river/riverdriver v0.31.0 h1:XwDa8DqkRxkqMqfdLOYTgSykiTHNSRcWG1LcCg/g0ys= -github.com/riverqueue/river/riverdriver v0.31.0/go.mod h1:Vl6XPbWtjqP+rqEa/HxcEeXeZL/KPCwqjRlqj+wWsq8= -github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0 h1:Zii6/VNqasBuPvFIA98xgjz3MRy2EvMm6lMyh1RtWBw= -github.com/riverqueue/river/riverdriver/riverpgxv5 v0.31.0/go.mod h1:z859lpsOraO3IYWjY9w8RZec5I0BAcas9rjZkwxAijU= -github.com/riverqueue/river/rivershared v0.31.0 h1:KVEp+13jnK9YOlMUKnR0eUyJaK+P/APcheoSGMfZArA= -github.com/riverqueue/river/rivershared v0.31.0/go.mod h1:Wvf489bvAiZsJm7mln8YAPZbK7pVfuK7bYfsBt5Nzbw= -github.com/riverqueue/river/rivertype v0.31.0 h1:O6vaJ72SffgF1nxzCrDKd4M+eMZFRlJpycnOcUIGLD8= -github.com/riverqueue/river/rivertype v0.31.0/go.mod h1:D1Ad+EaZiaXbQbJcJcfeicXJMBKno0n6UcfKI5Q7DIQ= -github.com/riverqueue/rivercontrib/otelriver v0.7.0 h1:zLjPf674dcGrz7OPG2JF5xea0fyitFax6Cc6q370Xzo= -github.com/riverqueue/rivercontrib/otelriver v0.7.0/go.mod h1:MuyMZmYBz3JXC8ZLP0dH9IqXK95qRY6gCQSoJGh9h7E= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= -github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= -github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= -github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= -github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= -github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= -github.com/samber/slog-common v0.20.0 h1:WaLnm/aCvBJSk5nR5aXZTFBaV0B47A+AEaEOiZDeUnc= -github.com/samber/slog-common v0.20.0/go.mod h1:+Ozat1jgnnE59UAlmNX1IF3IByHsODnnwf9jUcBZ+m8= -github.com/samber/slog-logrus/v2 v2.5.3 h1:N6YGgQ9CQjUQXe75/iWKtE55EENjG67HYUsJQbPn/dE= -github.com/samber/slog-logrus/v2 v2.5.3/go.mod h1:W3njRsspuMRCd33S0ibPyK1ohRaMhuXKZ1BK8pNiM+c= -github.com/sashabaranov/go-openai v1.41.2 h1:vfPRBZNMpnqu8ELsclWcAvF19lDNgh1t6TVfFFOPiSM= -github.com/sashabaranov/go-openai v1.41.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= -github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/serpapi/serpapi-golang v0.0.0-20260126142127-0e41c7993cda h1:w3JksZEWJDI7x+No5yh2/8S86hq1dmJy7n5btakG30U= -github.com/serpapi/serpapi-golang v0.0.0-20260126142127-0e41c7993cda/go.mod h1:xVL4PnCuCPwkXhVVQysVrX3hEv7nWnIbfnDj2B+hsPw= -github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= -github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= -github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= -github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg= -github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -1083,12 +674,10 @@ github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xI github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -1101,61 +690,10 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/stripe/stripe-go/v84 v84.4.0 h1:JMQMqb+mhW6tns+eYA3G5SZiaoD2ULwN0lZ+kNjWAsY= -github.com/stripe/stripe-go/v84 v84.4.0/go.mod h1:Z4gcKw1zl4geDG2+cjpSaJES9jaohGX6n7FP8/kHIqw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk= -github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA= -github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 h1:ZF+QBjOI+tILZjBaFj3HgFonKXUcwgJ4djLb6i42S3Q= -github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834/go.mod h1:m9ymHTgNSEjuxvw8E7WWe4Pl4hZQHXONY8wE6dMLaRk= -github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA= -github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU= -github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= -github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= -github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI= -github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8= -github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= -github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= -github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA= -github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU= -github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= -github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg= -github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q= -github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= -github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= -github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8= -github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ= -github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= -github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE= -github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw= -github.com/tiktoken-go/tokenizer v0.7.0 h1:VMu6MPT0bXFDHr7UPh9uii7CNItVt3X9K90omxL54vw= -github.com/tiktoken-go/tokenizer v0.7.0/go.mod h1:6UCYI/DtOallbmL7sSy30p6YQv60qNyU/4aVigPOx6w= -github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= -github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= -github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= -github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2 h1:H8wwQwTe5sL6x30z71lUgNiwBdeCHQjrphCfLwqIHGo= github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2/go.mod h1:/kR4beFhlz2g+V5ik8jW+3PMiMQAPt29y6K64NNY53c= github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 h1:3/aHKUq7qaFMWxyQV0W2ryNgg8x8rVeKVA20KJUkfS0= @@ -1169,12 +707,6 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= -github.com/weppos/publicsuffix-go v0.30.1 h1:8q+QwBS1MY56Zjfk/50ycu33NN8aa1iCCEQwo/71Oos= -github.com/weppos/publicsuffix-go v0.30.1/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -1188,23 +720,12 @@ github.com/xiam/to v0.0.0-20191116183551-8328998fc0ed/go.mod h1:cqbG7phSzrbdg3aj github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= -github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= -github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= -github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= -github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI= github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yuin/goldmark-emoji v1.0.5 h1:EMVWyCGPlXJfUXBXpuMu+ii3TIaxbVBnEX9uaDC4cIk= github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc= -github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30= github.com/zclconf/go-cty v1.18.0 h1:pJ8+HNI4gFoyRNqVE37wWbJWVw43BZczFo7KUoRczaA= github.com/zclconf/go-cty v1.18.0/go.mod h1:qpnV6EDNgC1sns/AleL1fvatHw72j+S+nS+MJ+T2CSg= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= @@ -1213,24 +734,8 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= -github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30= -github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= -github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= -github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk= -github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= -github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= -github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 h1:YOQ1vXEwE4Rnj+uQ/3oCuJk5wgVsvUyW+glsndwYuyA= -github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21S5Z9bK1BMrertTGX/F8hgAPw7ERJRNS0= -github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= -go.devnw.com/structs v1.0.0 h1:FFkBoBOkapCdxFEIkpOZRmMOMr9b9hxjKTD3bJYl9lk= -go.devnw.com/structs v1.0.0/go.mod h1:wHBkdQpNeazdQHszJ2sxwVEpd8zGTEsKkeywDLGbrmg= go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/detectors/aws/ec2/v2 v2.0.0-20250901115419-474a7992e57c h1:YSqSR1Fil5Ip0N6AlNBFbNv7cvIHZ2j4+wqbVafAGmQ= @@ -1245,8 +750,6 @@ go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8= @@ -1273,278 +776,101 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= -go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo= golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= -gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.269.0 h1:qDrTOxKUQ/P0MveH6a7vZ+DNHxJQjtGm/uvdbdGXCQg= google.golang.org/api v0.269.0/go.mod h1:N8Wpcu23Tlccl0zSHEkcAZQKDLdquxK+l9r2LkwAauE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1552,89 +878,32 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= -gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= -gopkg.in/dnaeon/go-vcr.v3 v3.2.0 h1:Rltp0Vf+Aq0u4rQXgmXgtgoRDStTnFN83cWgSGSoRzM= -gopkg.in/dnaeon/go-vcr.v3 v3.2.0/go.mod h1:2IMOnnlx9I6u9x+YBsM3tAMx6AlOxnJ0pWxQAzZ79Ag= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw= k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60= -k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4= -k8s.io/apiextensions-apiserver v0.35.0/go.mod h1:E1Ahk9SADaLQ4qtzYFkwUqusXTcaV2uw3l14aqpL2LU= k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8= k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= -k8s.io/apiserver v0.35.0 h1:CUGo5o+7hW9GcAEF3x3usT3fX4f9r8xmgQeCBDaOgX4= -k8s.io/apiserver v0.35.0/go.mod h1:QUy1U4+PrzbJaM3XGu2tQ7U9A4udRRo5cyxkFX0GEds= k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o= k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g= -k8s.io/component-base v0.35.2 h1:btgR+qNrpWuRSuvWSnQYsZy88yf5gVwemvz0yw79pGc= -k8s.io/component-base v0.35.2/go.mod h1:B1iBJjooe6xIJYUucAxb26RwhAjzx0gHnqO9htWIX+0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= -modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= -modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= -modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= -modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= -modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= -modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= -modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= -modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= -modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= -modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= -modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= -modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= -modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= -modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= -modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= -modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= -modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU= -modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= -modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= -modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -riverqueue.com/riverui v0.15.0 h1:7Xm/tqv63jZrGSv4X2u4zpAvbtXSs835Qk4RFonBDdk= -riverqueue.com/riverui v0.15.0/go.mod h1:J4fH8+zPe1cqmYWuMWVJdDdMmq1U2UPVofyOczGZNnw= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0 h1:XotDXzqvJ8Nx5eiZZueLpTuafJz8SiodgOemI+w87QU= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80= -sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/kind v0.31.0 h1:UcT4nzm+YM7YEbqiAKECk+b6dsvc/HRZZu9U0FolL1g=