diff --git a/README.md b/README.md index 17dc854..91bc7c1 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,21 @@ go run ./cmd/bsky-webhook/ -bskyHandle me.example.com -watchWord "pangolin" ## Configuration These configuration options are available as command-line flags and -environment variables. Those without defaults are required. +environment variables. Those without defaults are required, unless +explicitly marked as optional. Here's the complete table based on the provided Go code: -| Command-line flag | Environment variable | Default value | Description | -| ------------------ | -------------------- | --------------------------------------- | ------------------------------------------------------------------------------------ | -| `-addr` | `JETSTREAM_ADDRESS` | Rotation of all public jetsream servers | The [jetstream](https://github.com/bluesky-social/jetstream) hostname to connect to. | -| `-bsky-handle` | `BSKY_HANDLE` | none | The Bluesky handle of the account that will make API requests. | -| `-bsky-app-password` | `BSKY_APP_PASSWORD` | none | The Bluesky app password for authentication. | -| `-slack-webhook-url` | `SLACK_WEBHOOK_URL` | none | The Slack webhook URL for sending notifications. | -| `-bsky-server-url` | `BSKY_SERVER_URL` | "https://bsky.network" | The Bluesky PDS server to send API requests to URL. | -| `-watch-word` | `WATCH_WORD` | "tailscale" | The word to watch out for; may support multiple words in the future. | - +| Command-line flag | Environment variable | Default value | Description | +|----------------------|----------------------|-----------------------------------------|-------------------------------------------------------------------------| +| `-addr` | `JETSTREAM_ADDRESS` | Rotation of all public jetsream servers | The [jetstream][jetstream] hostname to connect to. | +| `-bsky-handle` | `BSKY_HANDLE` | none | The Bluesky handle of the account that will make API requests. | +| `-bsky-app-password` | `BSKY_APP_PASSWORD` | none | The Bluesky app password for authentication. | +| `-slack-webhook-url` | `SLACK_WEBHOOK_URL` | none | The Slack webhook URL for sending notifications. | +| `-bsky-server-url` | `BSKY_SERVER_URL` | "https://bsky.network" | The Bluesky PDS server to send API requests to URL. | +| `-watch-word` | `WATCH_WORD` | "tailscale" | The word to watch out for; may support multiple words in the future. | +| `-secrets-url` | `SECRETS_URL` | none | The address of a [setec][setec] server to fetch secrets from (optional) | +| `-secrets-prefix` | `SECRETS_PREFIX` | "" | A prefix to prepend to secret names fetched from setec (optional) | + +[jetstream]: https://github.com/bluesky-social/jetstream +[setec]: https://github.com/tailscale/setec diff --git a/cmd/bsky-webhook/main.go b/cmd/bsky-webhook/main.go index 52a2531..19fb209 100644 --- a/cmd/bsky-webhook/main.go +++ b/cmd/bsky-webhook/main.go @@ -14,13 +14,17 @@ import ( "net/http" "net/url" "os" + "os/signal" + "path" "strings" + "syscall" "time" "github.com/bluesky-social/jetstream/pkg/models" "github.com/gorilla/websocket" - "github.com/karalabe/go-bluesky" + bluesky "github.com/karalabe/go-bluesky" "github.com/klauspost/compress/zstd" + "github.com/tailscale/setec/client/setec" ) var ( @@ -36,6 +40,11 @@ var ( "https://bsky.network"), "bluesky PDS server URL") watchWord = flag.String("watch-word", envOr("WATCH_WORD", "tailscale"), "the word to watch out for. may be multiple words in future (required)") + + secretsURL = flag.String("secrets-url", envOr("SECRETS_URL", ""), + "the URL of a secrets server (if empty, no server is used)") + secretsPrefix = flag.String("secrets-prefix", envOr("SECRETS_PREFIX", ""), + "the prefix to prepend to secret names fetched from --secrets-url") ) // Public addresses of jetstream websocket services. @@ -51,6 +60,10 @@ var jetstreams = []string{ // Only the DecodeAll method may be used. var zstdDecoder *zstd.Decoder +// httpClient must be used for all HTTP requests. It is a variable so that it +// can be replaced with a proxy. +var httpClient = http.DefaultClient + func init() { // Jetstream uses a custom zstd dictionary, so make sure we do the same. var err error @@ -65,20 +78,38 @@ func main() { // TODO(creachadair): Usage text. switch { - case *webhookURL == "": + case *webhookURL == "" && *secretsURL == "": log.Fatal("missing slack webhook URL (SLACK_WEBHOOK_URL)") case *bskyServerURL == "": log.Fatal("missing Bluesky server URL (BSKY_SERVER_URL)") case *bskyHandle == "": log.Fatal("Missing Bluesky account handle (BSKY_HANDLE)") - case *bskyAppKey == "": + case *bskyAppKey == "" && *secretsURL == "": log.Fatal("missing Bluesky app secret (BSKY_APP_PASSWORD)") case *watchWord == "": log.Fatal("missing watchword") } + ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer cancel() + + if *secretsURL != "" { + webhookSecret := path.Join(*secretsPrefix, "slack-webhook-url") + appKeySecret := path.Join(*secretsPrefix, "bluesky-app-key") + st, err := setec.NewStore(ctx, setec.StoreConfig{ + Client: setec.Client{Server: *secretsURL, DoHTTP: httpClient.Do}, + Secrets: []string{webhookSecret, appKeySecret}, + }) + if err != nil { + log.Fatalf("initialize secrets store: %v", err) + } + *webhookURL = st.Secret(webhookSecret).GetString() + *bskyAppKey = st.Secret(appKeySecret).GetString() + log.Printf("Fetched client secrets from %q", *secretsURL) + } + nextAddr := nextWSAddress() - for { + for ctx.Err() == nil { wsURL := url.URL{ Scheme: "wss", Host: nextAddr(), @@ -87,7 +118,7 @@ func main() { } slog.Info("ws connecting", "url", wsURL.String()) - err := websocketConnection(wsURL) + err := websocketConnection(ctx, wsURL) slog.Error("ws connection", "url", wsURL, "err", err) // TODO(erisa): exponential backoff @@ -119,13 +150,12 @@ func nextWSAddress() func() string { } } -func websocketConnection(wsUrl url.URL) error { +func websocketConnection(ctx context.Context, wsUrl url.URL) error { // add compression headers headers := http.Header{} headers.Add("Socket-Encoding", "zstd") c, _, err := websocket.DefaultDialer.Dial(wsUrl.String(), headers) - if err != nil { return fmt.Errorf("dial jetstream: %v", err) } @@ -135,9 +165,7 @@ func websocketConnection(wsUrl url.URL) error { return nil }) - ctx := context.Background() - - bsky, err := bluesky.Dial(ctx, *bskyServerURL) + bsky, err := bluesky.DialWithClient(ctx, *bskyServerURL, httpClient) if err != nil { log.Fatal("dial bsky: ", err) } @@ -148,7 +176,7 @@ func websocketConnection(wsUrl url.URL) error { log.Fatal("login bsky: ", err) } - for { + for ctx.Err() == nil { // bail if we take too long for a read c.SetReadDeadline(time.Now().Add(time.Second * 5)) @@ -157,15 +185,16 @@ func websocketConnection(wsUrl url.URL) error { return err } - err = readJetstreamMessage(jetstreamMessage, bsky) + err = readJetstreamMessage(ctx, jetstreamMessage, bsky) if err != nil { log.Println("error reading jetstream message: ", jetstreamMessage, err) continue } } + return ctx.Err() } -func readJetstreamMessage(jetstreamMessageEncoded []byte, bsky *bluesky.Client) error { +func readJetstreamMessage(ctx context.Context, jetstreamMessageEncoded []byte, bsky *bluesky.Client) error { // Decompress the message m, err := zstdDecoder.DecodeAll(jetstreamMessageEncoded, nil) if err != nil { @@ -189,7 +218,7 @@ func readJetstreamMessage(jetstreamMessageEncoded []byte, bsky *bluesky.Client) jetstreamMessageStr := string(jetstreamMessage) go func() { - profile, err := getBskyProfile(bskyMessage, bsky) + profile, err := getBskyProfile(ctx, bskyMessage, bsky) if err != nil { slog.Error("fetch profile", "err", err, "msg", jetstreamMessageStr) return @@ -201,7 +230,7 @@ func readJetstreamMessage(jetstreamMessageEncoded []byte, bsky *bluesky.Client) imageURL = fmt.Sprintf("https://cdn.bsky.app/img/feed_fullsize/plain/%s/%s", bskyMessage.Did, bskyMessage.Commit.Record.Embed.Images[0].Image.Ref.Link) } - err = sendToSlack(jetstreamMessageStr, bskyMessage, imageURL, *profile) + err = sendToSlack(ctx, jetstreamMessageStr, bskyMessage, imageURL, *profile) if err != nil { slog.Error("slack error", "err", err) } @@ -211,8 +240,8 @@ func readJetstreamMessage(jetstreamMessageEncoded []byte, bsky *bluesky.Client) return nil } -func getBskyProfile(bskyMessage BskyMessage, bsky *bluesky.Client) (*bluesky.Profile, error) { - profile, err := bsky.FetchProfile(context.Background(), bskyMessage.Did) +func getBskyProfile(ctx context.Context, bskyMessage BskyMessage, bsky *bluesky.Client) (*bluesky.Profile, error) { + profile, err := bsky.FetchProfile(ctx, bskyMessage.Did) if err != nil { return nil, err } @@ -225,7 +254,7 @@ func getBskyProfile(bskyMessage BskyMessage, bsky *bluesky.Client) (*bluesky.Pro return profile, nil } -func sendToSlack(jetstreamMessageStr string, bskyMessage BskyMessage, imageURL string, profile bluesky.Profile) error { +func sendToSlack(ctx context.Context, jetstreamMessageStr string, bskyMessage BskyMessage, imageURL string, profile bluesky.Profile) error { attachments := []SlackAttachment{ { AuthorName: fmt.Sprintf("%s (@%s)", profile.Name, profile.Handle), @@ -246,11 +275,17 @@ func sendToSlack(jetstreamMessageStr string, bskyMessage BskyMessage, imageURL s log.Printf("failed to marshal text: %v", err) } - res, err := http.Post(*webhookURL, "application/json", bytes.NewBuffer(body)) + req, err := http.NewRequestWithContext(ctx, "POST", *webhookURL, bytes.NewReader(body)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + res, err := httpClient.Do(req) if err != nil { slog.Error("failed to post to slack", "msg", jetstreamMessageStr) return err } + defer res.Body.Close() if res.StatusCode != http.StatusOK { body, err := io.ReadAll(res.Body) @@ -258,8 +293,6 @@ func sendToSlack(jetstreamMessageStr string, bskyMessage BskyMessage, imageURL s slog.Error("bad error code from slack and fail to read body", "statusCode", res.StatusCode, "msg", jetstreamMessageStr) return err } - defer res.Body.Close() - slog.Error("error code response from slack", "statusCode", res.StatusCode, "responseBody", string(body), "msg", jetstreamMessageStr) return fmt.Errorf("slack: %s %s", res.Status, string(body)) } diff --git a/go.mod b/go.mod index 036981b..1d73ec0 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,20 @@ module github.com/tailscale/bsky-webhook -go 1.22.6 +go 1.23 require ( github.com/bluesky-social/jetstream v0.0.0-20241031234625-0ab10bd041fe github.com/gorilla/websocket v1.5.3 github.com/karalabe/go-bluesky v0.0.0-20230506152134-dd72fcf127a8 github.com/klauspost/compress v1.17.9 + github.com/tailscale/setec v0.0.0-20241107175935-3954dc4aade5 ) require ( github.com/bluesky-social/indigo v0.0.0-20241008040750-06bacb465af7 // indirect github.com/carlmjohnson/versioninfo v0.22.5 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -55,9 +57,13 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect + go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect + golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect lukechampine.com/blake3 v1.3.0 // indirect + tailscale.com v1.73.0-pre.0.20240822193108-696711cc17c4 // indirect ) diff --git a/go.sum b/go.sum index 76969c0..254ed8a 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,40 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= +github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= +github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= +github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 h1:81KE7vaZzrl7yHBYHVEzYB8sypz11NMOZ40YlWvPxsU= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5/go.mod h1:LIt2rg7Mcgn09Ygbdh/RdIm0rQ+3BNkbP1gyVMFtRK0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 h1:ZMeFZ5yk+Ek+jNr1+uwCd2tG89t6oTS5yVWpa6yy2es= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7/go.mod h1:mxV05U+4JiHqIpGqqYXOHLPKUC6bDXC44bsUhNjOEwY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 h1:f9RyWNtS8oH7cZlbn+/JNPpjUk5+5fLd5lM9M0i49Ys= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5/go.mod h1:h5CoMZV2VF297/VLhRhO1WF+XYWOzXo+4HsObA4HjBQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 h1:6cnno47Me9bRykw9AEv9zkXE+5or7jz8TsskTTccbgc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1/go.mod h1:qmdkIIAC+GCLASF7R2whgNrJADz0QZPX+Seiw/i4S3o= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bluesky-social/indigo v0.0.0-20241008040750-06bacb465af7 h1:bD+X6ms6OOrrkBGWla/tsnWJRKNfSsqvXxbLYlWZuOs= github.com/bluesky-social/indigo v0.0.0-20241008040750-06bacb465af7/go.mod h1:Zx9nSWgd/FxMenkJW07VKnzspxpHBdPrPmS+Fspl2I0= @@ -7,13 +43,20 @@ github.com/bluesky-social/jetstream v0.0.0-20241031234625-0ab10bd041fe/go.mod h1 github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc= github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creachadair/mds v0.17.1 h1:lXQbTGKmb3nE3aK6OEp29L1gCx6B5ynzlQ6c1KOBurc= +github.com/creachadair/mds v0.17.1/go.mod h1:4b//mUiL8YldH6TImXjmW45myzTLNS1LLjOmrk888eg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +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/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 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/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -113,8 +156,9 @@ github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOEL github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0= github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -134,6 +178,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tailscale/setec v0.0.0-20241107175935-3954dc4aade5 h1:5Y9zlHoo9mLaGXOunjz+y60+8cu33kCV2kFZrm0peO4= +github.com/tailscale/setec v0.0.0-20241107175935-3954dc4aade5/go.mod h1:nexjfRM8veJVJ5PTbqYI2YrUj/jbk3deffEHO3DH9Q4= +github.com/tink-crypto/tink-go/v2 v2.1.0 h1:QXFBguwMwTIaU17EgZpEJWsUSc60b1BAGTzBIoMdmok= +github.com/tink-crypto/tink-go/v2 v2.1.0/go.mod h1:y1TnYFt1i2eZVfx4OGc+C+EMp4CoKWAw2VSEuoicHHI= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -166,17 +214,23 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= +go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= 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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= +golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -187,6 +241,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -217,6 +273,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -231,3 +289,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +tailscale.com v1.73.0-pre.0.20240822193108-696711cc17c4 h1:nk7LzcAeBG4WSLpWJI4JYSIh4jUGpmgo0NwR+aANqUU= +tailscale.com v1.73.0-pre.0.20240822193108-696711cc17c4/go.mod h1:NCKbGDxDo2qEls/5VC4OPCZuZH+stUJPYcTLZaKBaBo=