From 0b904f2135dfc5c84501ac1789584dd18dc3ec06 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 8 Oct 2025 23:41:25 +0200 Subject: [PATCH 1/6] cmd/chantools+lnd: fix triggerforceclose command This commit fixes two issues: 1. Some new peer related config values weren't set, leading to an error. 2. Triggering the force close with a CLN node can be timing-sensitive. It appears that trying both methods independently directly after connecting yields the most reliable result. --- cmd/chantools/triggerforceclose.go | 45 ++++++++++++++++++++++++++++-- lnd/brontide.go | 3 +- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/cmd/chantools/triggerforceclose.go b/cmd/chantools/triggerforceclose.go index e7a23ab..74d9c36 100644 --- a/cmd/chantools/triggerforceclose.go +++ b/cmd/chantools/triggerforceclose.go @@ -259,7 +259,11 @@ func closeChannel(identityPriv *btcec.PrivateKey, api *btc.ExplorerAPI, return nil, fmt.Errorf("error parsing channel point: %w", err) } - err = requestForceClose(peer, torProxy, *outPoint, identityECDH) + err = requestForceCloseLnd(peer, torProxy, *outPoint, identityECDH) + if err != nil { + return nil, fmt.Errorf("error requesting force close: %w", err) + } + err = requestForceCloseCln(peer, torProxy, *outPoint, identityECDH) if err != nil { return nil, fmt.Errorf("error requesting force close: %w", err) } @@ -287,6 +291,17 @@ func closeChannel(identityPriv *btcec.PrivateKey, api *btc.ExplorerAPI, } counter++ + if counter >= 6 { + log.Info("Waited 30 seconds, still no spends found, " + + "re-triggering CLN request") + err = requestForceCloseCln( + peer, torProxy, *outPoint, identityECDH, + ) + if err != nil { + return nil, fmt.Errorf("error requesting "+ + "force close: %w", err) + } + } if counter >= 12 { return nil, errors.New("no spends found after 60 " + "seconds, aborting re-try loop") @@ -385,7 +400,7 @@ func connectPeer(peerHost, torProxy string, identity keychain.SingleKeyECDH, return p, cleanup, nil } -func requestForceClose(peerHost, torProxy string, channelPoint wire.OutPoint, +func requestForceCloseLnd(peerHost, torProxy string, channelPoint wire.OutPoint, identity keychain.SingleKeyECDH) error { p, cleanup, err := connectPeer( @@ -415,6 +430,32 @@ func requestForceClose(peerHost, torProxy string, channelPoint wire.OutPoint, return err } + // Wait a few seconds to give the peer time to process the message. + time.Sleep(5 * time.Second) + + return nil +} + +func requestForceCloseCln(peerHost, torProxy string, channelPoint wire.OutPoint, + identity keychain.SingleKeyECDH) error { + + p, cleanup, err := connectPeer( + peerHost, torProxy, identity, dialTimeout, + ) + defer func() { + _ = cleanup() + }() + + if err != nil { + return fmt.Errorf("error connecting to peer: %w", err) + } + + channelID := lnwire.NewChanIDFromOutPoint(channelPoint) + + // Channel ID (32 byte) + u16 for the data length (which will be 0). + data := make([]byte, 34) + copy(data[:32], channelID[:]) + log.Infof("Sending channel error message to peer to trigger force "+ "close of channel %v", channelPoint) diff --git a/lnd/brontide.go b/lnd/brontide.go index 0b4b1a2..ce0b825 100644 --- a/lnd/brontide.go +++ b/lnd/brontide.go @@ -217,7 +217,8 @@ func ConnectPeer(conn *brontide.Conn, connReq *connmgr.ConnReq, return nil }, - }) + }, + ) if err != nil { _ = channelDB.Close() return nil, nil, fmt.Errorf("unable to create channel status "+ From 3402af3a42e651d17c8deb5c63a8185a480cdb86 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 8 Oct 2025 23:41:26 +0200 Subject: [PATCH 2/6] cmd/chantools: make results dir configurable --- cmd/chantools/fakechanbackup.go | 2 +- cmd/chantools/filterbackup.go | 2 +- cmd/chantools/fixoldbackup.go | 2 +- cmd/chantools/forceclose.go | 2 +- cmd/chantools/genimportscript.go | 2 +- cmd/chantools/rescueclosed.go | 2 +- cmd/chantools/root.go | 16 +++++++++++----- cmd/chantools/summary.go | 4 ++-- cmd/chantools/triggerforceclose.go | 8 ++++---- cmd/chantools/zombierecovery_findmatches.go | 2 +- cmd/chantools/zombierecovery_preparekeys.go | 2 +- 11 files changed, 25 insertions(+), 19 deletions(-) diff --git a/cmd/chantools/fakechanbackup.go b/cmd/chantools/fakechanbackup.go index cd00d78..1e94b9b 100644 --- a/cmd/chantools/fakechanbackup.go +++ b/cmd/chantools/fakechanbackup.go @@ -108,7 +108,7 @@ chantools fakechanbackup --from_channel_graph lncli_describegraph.json \ "LN channel graph in the JSON format that the "+ "'lncli describegraph' returns", ) - multiFileName := fmt.Sprintf("results/fake-%s.backup", + multiFileName := fmt.Sprintf("%s/fake-%s.backup", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) cc.cmd.Flags().StringVar( &cc.MultiFile, "multi_file", multiFileName, "the fake channel "+ diff --git a/cmd/chantools/filterbackup.go b/cmd/chantools/filterbackup.go index 36ad340..33e7b94 100644 --- a/cmd/chantools/filterbackup.go +++ b/cmd/chantools/filterbackup.go @@ -93,7 +93,7 @@ func filterChannelBackup(multiFile *chanbackup.MultiFile, ring keychain.KeyRing, } multi.StaticBackups = keep - fileName := fmt.Sprintf("results/backup-filtered-%s.backup", + fileName := fmt.Sprintf("%s/backup-filtered-%s.backup", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing result to %s", fileName) f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) diff --git a/cmd/chantools/fixoldbackup.go b/cmd/chantools/fixoldbackup.go index a3a6d7d..1d2b017 100644 --- a/cmd/chantools/fixoldbackup.go +++ b/cmd/chantools/fixoldbackup.go @@ -108,7 +108,7 @@ func fixOldChannelBackup(multiFile *chanbackup.MultiFile, } log.Infof("Fixed shachain root of %d channels.", fixedChannels) - fileName := fmt.Sprintf("results/backup-fixed-%s.backup", + fileName := fmt.Sprintf("%s/backup-fixed-%s.backup", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing result to %s", fileName) f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) diff --git a/cmd/chantools/forceclose.go b/cmd/chantools/forceclose.go index 0742819..a002b5c 100644 --- a/cmd/chantools/forceclose.go +++ b/cmd/chantools/forceclose.go @@ -230,7 +230,7 @@ func forceCloseChannels(apiURL string, extendedKey *hdkeychain.ExtendedKey, if err != nil { return err } - fileName := fmt.Sprintf("results/forceclose-%s.json", + fileName := fmt.Sprintf("%s/forceclose-%s.json", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing result to %s", fileName) return os.WriteFile(fileName, summaryBytes, 0644) diff --git a/cmd/chantools/genimportscript.go b/cmd/chantools/genimportscript.go index 8db3215..b2eaee8 100644 --- a/cmd/chantools/genimportscript.go +++ b/cmd/chantools/genimportscript.go @@ -158,7 +158,7 @@ func (c *genImportScriptCommand) Execute(_ *cobra.Command, _ []string) error { writer := os.Stdout if !c.Stdout { - fileName := fmt.Sprintf("results/genimportscript-%s.txt", + fileName := fmt.Sprintf("%s/genimportscript-%s.txt", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing import script with format '%s' to %s", c.Format, fileName) diff --git a/cmd/chantools/rescueclosed.go b/cmd/chantools/rescueclosed.go index c0e3b56..f4ae827 100644 --- a/cmd/chantools/rescueclosed.go +++ b/cmd/chantools/rescueclosed.go @@ -322,7 +322,7 @@ outer: if err != nil { return err } - fileName := fmt.Sprintf("results/rescueclosed-%s.json", + fileName := fmt.Sprintf("%s/rescueclosed-%s.json", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing result to %s", fileName) return os.WriteFile(fileName, summaryBytes, 0644) diff --git a/cmd/chantools/root.go b/cmd/chantools/root.go index 8f4d739..a0cc83d 100644 --- a/cmd/chantools/root.go +++ b/cmd/chantools/root.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "path/filepath" "strings" "time" @@ -47,10 +48,11 @@ const ( ) var ( - Testnet bool - Regtest bool - Signet bool - NoLogFile bool + Testnet bool + Regtest bool + Signet bool + NoLogFile bool + ResultsDir string log btclog.Logger @@ -106,6 +108,10 @@ func main() { "will be created. This is useful for testing purposes "+ "where we don't want to create a log file.", ) + rootCmd.PersistentFlags().StringVar( + &ResultsDir, "resultsdir", "./results", "Directory where "+ + "results should be stored", + ) rootCmd.AddCommand( newChanBackupCommand(), @@ -351,7 +357,7 @@ func setupLogging() { MaxLogFiles: 3, MaxLogFileSize: 10, }, - "./results/chantools.log", + filepath.Join(ResultsDir, "chantools.log"), ) if err != nil { panic(err) diff --git a/cmd/chantools/summary.go b/cmd/chantools/summary.go index d631fd3..5d131e7 100644 --- a/cmd/chantools/summary.go +++ b/cmd/chantools/summary.go @@ -109,7 +109,7 @@ func summarizeChannels(apiURL string, if err != nil { return err } - fileName := fmt.Sprintf("results/summary-%s.json", + fileName := fmt.Sprintf("%s/summary-%s.json", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing result to %s", fileName) return os.WriteFile(fileName, summaryBytes, 0644) @@ -129,7 +129,7 @@ func summarizeAncientChannels(apiURL string, if err != nil { return err } - fileName := fmt.Sprintf("results/summary-ancient-%s.json", + fileName := fmt.Sprintf("%s/summary-ancient-%s.json", ResultsDir, time.Now().Format("2006-01-02-15-04-05")) log.Infof("Writing result to %s", fileName) return os.WriteFile(fileName, summaryBytes, 0644) diff --git a/cmd/chantools/triggerforceclose.go b/cmd/chantools/triggerforceclose.go index 74d9c36..c7dacb4 100644 --- a/cmd/chantools/triggerforceclose.go +++ b/cmd/chantools/triggerforceclose.go @@ -206,8 +206,8 @@ func (c *triggerForceCloseCommand) Execute(_ *cobra.Command, _ []string) error { peersBytes := []byte(strings.Join(pubKeys, "\n")) outputsBytes := []byte(strings.Join(outputs, "\n")) - fileName := fmt.Sprintf("results/forceclose-peers-%s.txt", - time.Now().Format("2006-01-02")) + fileName := fmt.Sprintf("%s/forceclose-peers-%s.txt", + ResultsDir, time.Now().Format("2006-01-02")) log.Infof("Writing peers to %s", fileName) err = os.WriteFile(fileName, peersBytes, 0644) if err != nil { @@ -215,8 +215,8 @@ func (c *triggerForceCloseCommand) Execute(_ *cobra.Command, _ []string) error { err) } - fileName = fmt.Sprintf("results/forceclose-addresses-%s.txt", - time.Now().Format("2006-01-02")) + fileName = fmt.Sprintf("%s/forceclose-addresses-%s.txt", + ResultsDir, time.Now().Format("2006-01-02")) log.Infof("Writing addresses to %s", fileName) return os.WriteFile(fileName, outputsBytes, 0644) diff --git a/cmd/chantools/zombierecovery_findmatches.go b/cmd/chantools/zombierecovery_findmatches.go index 0256873..03f0ee6 100644 --- a/cmd/chantools/zombierecovery_findmatches.go +++ b/cmd/chantools/zombierecovery_findmatches.go @@ -316,7 +316,7 @@ func (c *zombieRecoveryFindMatchesCommand) Execute(_ *cobra.Command, Node1: node1, } - folder := "results/match-" + node1 + folder := fmt.Sprintf("%s/match-%s", ResultsDir, node1) today := time.Now().Format("2006-01-02") for node2, match := range node1map { err = os.MkdirAll(folder, 0755) diff --git a/cmd/chantools/zombierecovery_preparekeys.go b/cmd/chantools/zombierecovery_preparekeys.go index 191448a..9c73e24 100644 --- a/cmd/chantools/zombierecovery_preparekeys.go +++ b/cmd/chantools/zombierecovery_preparekeys.go @@ -247,7 +247,7 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command, return err } - fileName := fmt.Sprintf("results/preparedkeys-%s-%s.json", + fileName := fmt.Sprintf("%s/preparedkeys-%s-%s.json", ResultsDir, time.Now().Format("2006-01-02"), pubKeyStr) log.Infof("Writing result to %s", fileName) return os.WriteFile(fileName, matchBytes, 0644) From a2b184edd4870bc3df83e4929c1310916edaa079 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 8 Oct 2025 23:41:27 +0200 Subject: [PATCH 3/6] make+itest: add docker-based itest setup script --- Makefile | 8 +- itest/README.md | 76 +++++++ itest/docker/.env | 11 + itest/docker/.gitignore | 1 + itest/docker/compose.sh | 66 ++++++ itest/docker/docker-compose.yaml | 303 +++++++++++++++++++++++++++ itest/docker/network.sh | 323 +++++++++++++++++++++++++++++ itest/docker/run-cmd.sh | 17 ++ itest/docker/setup-test-network.sh | 144 +++++++++++++ itest/itest.sh | 41 ++++ 10 files changed, 989 insertions(+), 1 deletion(-) create mode 100644 itest/README.md create mode 100644 itest/docker/.env create mode 100644 itest/docker/.gitignore create mode 100755 itest/docker/compose.sh create mode 100644 itest/docker/docker-compose.yaml create mode 100644 itest/docker/network.sh create mode 100755 itest/docker/run-cmd.sh create mode 100755 itest/docker/setup-test-network.sh create mode 100755 itest/itest.sh diff --git a/Makefile b/Makefile index 44855b5..414039c 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ DOCKER_TOOLS = docker run \ TEST_FLAGS = -test.timeout=20m -UNIT := $(GOLIST) | $(XARGS) env $(GOTEST) $(TEST_FLAGS) +UNIT := $(GOLIST) | grep -v "/itest" | $(XARGS) env $(GOTEST) $(TEST_FLAGS) LDFLAGS := -X main.Commit=$(shell git describe --tags) RELEASE_LDFLAGS := -s -w -buildid= $(LDFLAGS) @@ -64,6 +64,10 @@ unit: @$(call print, "Running unit tests.") $(UNIT) +itest: install + @$(call print, "Running integration tests.") + cd itest; ./itest.sh + build: @$(call print, "Building chantools.") $(GOBUILD) -ldflags "$(LDFLAGS)" ./... @@ -94,3 +98,5 @@ lint: docker-tools docs: install @$(call print, "Rendering docs.") chantools doc + +.PHONY: unit itest build install release fmt lint docs docker-tools diff --git a/itest/README.md b/itest/README.md new file mode 100644 index 0000000..31fbe4c --- /dev/null +++ b/itest/README.md @@ -0,0 +1,76 @@ +# Chantools Integration Test (itest) + +This directory contains the integration test (itest) setup and test cases for +chantools. The test network is created using Docker Compose scripts and consists +of multiple Lightning Network nodes connected in a specific topology to create +multiple channels with non-zero channel update indexes (by sending some payments +around the network). + +## Test Network Topology + +The network is set up as follows: + +``` +Alice ◄──► Bob ◄──► Charlie ◄──► Dave + └───────►└──► Rusty ◄──┘ + | └► Nifty + └► Snyke +``` + +- Channel **Alice** - **Bob**: Remains open, used by `runZombieRecoveryLndLnd`. +- Channel **Alice** - **Rusty**: Is force closed by Alice, used by + `runSweepRemoteClosedCln`. +- Channel **Alice** - **Snyke**: Remains open, used by + `runTriggerForceCloseCln`. +- Channel **Bob** - **Charlie**: Is force closed by Bob, used by + `runSweepRemoteClosedLnd`. +- Channel **Charlie** - **Dave**: Remains open, used by + `runTriggerForceCloseLnd`. +- Channel **Bob** - **Rusty**: Remains open, used by `runZombieRecoveryLndCln`. +- Channel **Rusty** - **Charlie**: Remains open, used by + `runZombieRecoveryClnLnd`. +- Channel **Rusty** - **Nifty**: Remains open, used by + `runZombieRecoveryClnCln`. + +All nodes except for Dave and Snyke are stopped before the integration tests +are run. + +Multiple channels are opened between the nodes, and several multi-hop payments +are executed to ensure the network is fully operational and synchronized. After +the setup, each node's channel information is exported to a JSON file in the +`node-data/chantools/` directory. + +## Running the Integration Tests + +To start the integration tests, run the following command from the project root: + +```sh +make itest +``` + +Which executes the script `itest/itest.sh`. + +This script will: +- Build and start the Docker-based test network. +- Set up the channels and perform payments between nodes. +- Export channel data for each node. +- Run the Go integration tests against the prepared network. + +## Debugging the Test Network + +By default, the test network is torn down automatically after the tests finish +or if an error occurs. If you want to keep the Docker containers running for +debugging purposes, set the `DEBUG` environment variable before running the +script: + +```sh +make itest DEBUG=1 +``` + +With `DEBUG` set, the containers will not be stopped automatically, allowing you +to inspect the state of the network and containers for troubleshooting and +run the Golang based integration tests manually several times. + +--- + +For more details on the network setup, see `docker/setup-test-network.sh`. diff --git a/itest/docker/.env b/itest/docker/.env new file mode 100644 index 0000000..ca3f74e --- /dev/null +++ b/itest/docker/.env @@ -0,0 +1,11 @@ +BITCOIND_VERSION=29 +LND_LATEST_VERSION=v0.19.3-beta +CLN_LATEST_VERSION=v25.09 +TIMEOUT=15 + +CLN_NODES="rusty|nifty|snyke" + +# Change the values in /itest/helpers.go as well when changing these! +ELECTRS_EXPORTED_PORT=3004 +DAVE_EXPORTED_PORT=9700 +SNYKE_EXPORTED_PORT=9701 diff --git a/itest/docker/.gitignore b/itest/docker/.gitignore new file mode 100644 index 0000000..4bbec48 --- /dev/null +++ b/itest/docker/.gitignore @@ -0,0 +1 @@ +node-data diff --git a/itest/docker/compose.sh b/itest/docker/compose.sh new file mode 100755 index 0000000..4c44a77 --- /dev/null +++ b/itest/docker/compose.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# This file contains all the common docker-compose related functions. + +# DIR is set to the directory of this script. +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +export LOCAL_USER_ID=$(id -u) +export LOCAL_GROUP_ID=$(id -g) + +# The way we call docker-compose depends on the installation. +if which docker-compose > /dev/null; then + COMPOSE_CMD="docker-compose" +else + COMPOSE_CMD="docker compose" +fi + +# Common arguments that we want to pass to docker-compose. +# By default, this only includes the main docker-compose file +# and not the override file. Use the `compose_upgrade` method +# to load both docker compose files. +COMPOSE_ARGS="-f $DIR/docker-compose.yaml -p regtest" +COMPOSE="$COMPOSE_CMD $COMPOSE_ARGS" + +# compose_upgrade sets COMPOSE_ARGS and COMPOSE such that +# both the main docker-compose file and the override file +# are loaded. +function compose_upgrade() { + export COMPOSE_ARGS="-p regtest" + export COMPOSE="$COMPOSE_CMD $COMPOSE_ARGS" +} + +# compose_up starts the docker-compose cluster. +function compose_up() { + echo "🐳 Starting the cluster" + $COMPOSE up -d --quiet-pull +} + +# compose_down tears down the docker-compose cluster +# and removes all volumes and orphans. +function compose_down() { + echo "🐳 Tearing down the cluster" + $COMPOSE down --volumes --remove-orphans +} + +# compose_stop stops a specific service in the cluster. +function compose_stop() { + local service="$1" + echo "🐳 Stopping $service" + $COMPOSE stop "$service" +} + +# compose_start starts a specific service in the cluster. +function compose_start() { + local service="$1" + echo "🐳 Starting $service" + $COMPOSE up -d $service +} + +# compose_rebuild forces the rebuild of the image for a +# specific service in the cluster. +function compose_rebuild() { + local service="$1" + echo "🐳 Rebuilding $service" + $COMPOSE build --no-cache $service +} diff --git a/itest/docker/docker-compose.yaml b/itest/docker/docker-compose.yaml new file mode 100644 index 0000000..2362077 --- /dev/null +++ b/itest/docker/docker-compose.yaml @@ -0,0 +1,303 @@ +services: + bitcoind: + image: lightninglabs/bitcoin-core:${BITCOIND_VERSION} + container_name: bitcoind + restart: unless-stopped + ports: + - "18443:18443" + - "18444:18444" + - "28332:28332" + - "28333:28333" + networks: + regtest: + aliases: + - bitcoind + command: + - "-txindex" + - "-regtest" + - "-rest" + - "-printtoconsole" + - "-zmqpubrawblock=tcp://0.0.0.0:28332" + - "-zmqpubrawtx=tcp://0.0.0.0:28333" + - "-rpcport=18443" + - "-rpcbind=0.0.0.0" + - "-rpcauth=lightning:8492220e715bbfdf5f165102bfd7ed4$$88090545821ed5e9db614588c0afbad575ccc14681fb77f3cae6899bc419af67" + - "-rpcallowip=0.0.0.0/0" + - "-fallbackfee=0.0002" + - "-peerblockfilters=1" + - "-blockfilterindex=1" + - "-wallet=/home/bitcoin/.bitcoin/regtest/wallets/miner" + environment: + - HOME=/home/bitcoin + volumes: + - bitcoind:/home/bitcoin/.bitcoin + + electrs: + image: mempool/electrs + container_name: electrs + restart: unless-stopped + ports: + - "${ELECTRS_EXPORTED_PORT}:3000" + networks: + - regtest + environment: + - RUST_BACKTRACE=1 + volumes: + - bitcoind:/home/user/.bitcoin + user: "0:0" + depends_on: + - bitcoind + command: + - "-vvv" + - "--timestamp" + - "--network=regtest" + - "--cookie=lightning:lightning" + - "--daemon-rpc-addr=bitcoind:18443" + - "--http-addr=0.0.0.0:3000" + - "--cors=http://localhost:3002" + - "--daemon-dir=/home/user/.bitcoin" + - "--db-dir=/home/user/.bitcoin/db" + + alice: + image: lightninglabs/lnd:${LND_LATEST_VERSION} + container_name: alice + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + networks: + regtest: + aliases: + - alice + environment: + - HOME=/home/user + volumes: + - "./node-data/alice:/home/user/.lnd" + depends_on: + - bitcoind + command: + - "--logdir=/home/user/.lnd" + - "--alias=alice" + - "--rpclisten=0.0.0.0:10009" + - "--restlisten=0.0.0.0:8080" + - "--color=#cccccc" + - "--noseedbackup" + - "--bitcoin.active" + - "--bitcoin.regtest" + - "--bitcoin.node=bitcoind" + - "--bitcoind.rpchost=bitcoind" + - "--bitcoind.rpcuser=lightning" + - "--bitcoind.rpcpass=lightning" + - "--bitcoind.zmqpubrawblock=tcp://bitcoind:28332" + - "--bitcoind.zmqpubrawtx=tcp://bitcoind:28333" + - "--debuglevel=debug" + - "--externalip=alice" + - "--tlsextradomain=alice" + - "--accept-keysend" + - "--protocol.option-scid-alias" + - "--protocol.zero-conf" + - "--protocol.simple-taproot-chans" + - "--trickledelay=50" + + bob: + image: lightninglabs/lnd:${LND_LATEST_VERSION} + container_name: bob + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + networks: + regtest: + aliases: + - bob + environment: + - HOME=/home/user + volumes: + - "./node-data/bob:/home/user/.lnd" + depends_on: + - bitcoind + command: + - "--logdir=/home/user/.lnd" + - "--alias=bob" + - "--rpclisten=0.0.0.0:10009" + - "--restlisten=0.0.0.0:8080" + - "--color=#cccccc" + - "--noseedbackup" + - "--bitcoin.active" + - "--bitcoin.regtest" + - "--bitcoin.node=bitcoind" + - "--bitcoind.rpchost=bitcoind" + - "--bitcoind.rpcuser=lightning" + - "--bitcoind.rpcpass=lightning" + - "--bitcoind.zmqpubrawblock=tcp://bitcoind:28332" + - "--bitcoind.zmqpubrawtx=tcp://bitcoind:28333" + - "--debuglevel=debug" + - "--externalip=bob" + - "--tlsextradomain=bob" + - "--accept-keysend" + - "--protocol.option-scid-alias" + - "--protocol.zero-conf" + - "--protocol.simple-taproot-chans" + - "--trickledelay=50" + + charlie: + image: lightninglabs/lnd:${LND_LATEST_VERSION} + container_name: charlie + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + networks: + regtest: + aliases: + - charlie + environment: + - HOME=/home/user + volumes: + - "./node-data/charlie:/home/user/.lnd" + depends_on: + - bitcoind + command: + - "--logdir=/home/user/.lnd" + - "--alias=charlie" + - "--rpclisten=0.0.0.0:10009" + - "--restlisten=0.0.0.0:8080" + - "--color=#cccccc" + - "--noseedbackup" + - "--bitcoin.active" + - "--bitcoin.regtest" + - "--bitcoin.node=bitcoind" + - "--bitcoind.rpchost=bitcoind" + - "--bitcoind.rpcuser=lightning" + - "--bitcoind.rpcpass=lightning" + - "--bitcoind.zmqpubrawblock=tcp://bitcoind:28332" + - "--bitcoind.zmqpubrawtx=tcp://bitcoind:28333" + - "--debuglevel=debug" + - "--externalip=charlie" + - "--tlsextradomain=charlie" + - "--accept-keysend" + - "--protocol.option-scid-alias" + - "--protocol.zero-conf" + - "--protocol.simple-taproot-chans" + - "--trickledelay=50" + + dave: + image: lightninglabs/lnd:${LND_LATEST_VERSION} + container_name: dave + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + ports: + - "${DAVE_EXPORTED_PORT}:9735" + networks: + regtest: + aliases: + - dave + environment: + - HOME=/home/user + volumes: + - "./node-data/dave:/home/user/.lnd" + depends_on: + - bitcoind + command: + - "--logdir=/home/user/.lnd" + - "--alias=dave" + - "--rpclisten=0.0.0.0:10009" + - "--restlisten=0.0.0.0:8080" + - "--color=#cccccc" + - "--noseedbackup" + - "--bitcoin.active" + - "--bitcoin.regtest" + - "--bitcoin.node=bitcoind" + - "--bitcoind.rpchost=bitcoind" + - "--bitcoind.rpcuser=lightning" + - "--bitcoind.rpcpass=lightning" + - "--bitcoind.zmqpubrawblock=tcp://bitcoind:28332" + - "--bitcoind.zmqpubrawtx=tcp://bitcoind:28333" + - "--debuglevel=debug" + - "--externalip=dave" + - "--tlsextradomain=dave" + - "--accept-keysend" + - "--protocol.option-scid-alias" + - "--protocol.zero-conf" + - "--protocol.simple-taproot-chans" + - "--trickledelay=50" + + rusty: + image: elementsproject/lightningd:${CLN_LATEST_VERSION} + container_name: rusty + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + networks: + - regtest + environment: + - HOME=/home/user + volumes: + - "./node-data/rusty:/home/user/.lightning" + depends_on: + - bitcoind + command: + - "--bitcoin-rpcconnect=bitcoind" + - "--bitcoin-rpcuser=lightning" + - "--bitcoin-rpcpassword=lightning" + - "--network=regtest" + - "--plugin-dir=/usr/libexec/c-lightning/plugins" + - "--alias=rusty" + - "--developer" + - "--dev-bitcoind-poll=1" + - "--dev-fast-gossip" + - "--log-level=debug" + - "--bind-addr=0.0.0.0:9735" + + nifty: + image: elementsproject/lightningd:${CLN_LATEST_VERSION} + container_name: nifty + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + networks: + - regtest + environment: + - HOME=/home/user + volumes: + - "./node-data/nifty:/home/user/.lightning" + depends_on: + - bitcoind + command: + - "--bitcoin-rpcconnect=bitcoind" + - "--bitcoin-rpcuser=lightning" + - "--bitcoin-rpcpassword=lightning" + - "--network=regtest" + - "--plugin-dir=/usr/libexec/c-lightning/plugins" + - "--alias=nifty" + - "--developer" + - "--dev-bitcoind-poll=1" + - "--dev-fast-gossip" + - "--log-level=debug" + - "--bind-addr=0.0.0.0:9735" + + snyke: + image: elementsproject/lightningd:${CLN_LATEST_VERSION} + container_name: snyke + restart: unless-stopped + user: ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} + ports: + - "${SNYKE_EXPORTED_PORT}:9735" + networks: + - regtest + environment: + - HOME=/home/user + volumes: + - "./node-data/snyke:/home/user/.lightning" + depends_on: + - bitcoind + command: + - "--bitcoin-rpcconnect=bitcoind" + - "--bitcoin-rpcuser=lightning" + - "--bitcoin-rpcpassword=lightning" + - "--network=regtest" + - "--plugin-dir=/usr/libexec/c-lightning/plugins" + - "--alias=snyke" + - "--developer" + - "--dev-bitcoind-poll=1" + - "--dev-fast-gossip" + - "--log-level=debug" + - "--bind-addr=0.0.0.0:9735" + +networks: + regtest: + +volumes: + bitcoind: diff --git a/itest/docker/network.sh b/itest/docker/network.sh new file mode 100644 index 0000000..67fbdf8 --- /dev/null +++ b/itest/docker/network.sh @@ -0,0 +1,323 @@ +#!/bin/bash + +# This file contains all LN network related functions. + +# DIR is set to the directory of this script. +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source "$DIR/.env" + +function node_identity() { + local node="$1" + local key + if [[ "$node" =~ ^($CLN_NODES)$ ]]; then + key=$( $node getinfo | jq .id -r) + else + key=$( $node getinfo | jq .identity_pubkey -r) + fi + echo "$key" +} + +# wait_for_nodes waits for all the nodes in the argument list to start. +function wait_for_nodes() { + local nodes=("$@") + + for node in "${nodes[@]}"; do + wait_for_node $node + done + echo "🏎️ All nodes have started!" +} + +# wait_for_node waits for the given node in the cluster to start, with a +# timeout. +function wait_for_node() { + if [[ $# -ne 1 ]]; then + echo "❌ Error: wait_for_node requires exactly 1 argument (node)" + echo "Usage: wait_for_node " + return 1 + fi + + local node="$1" + local start_time=$(date +%s) + + echo -n "⌛ Waiting for $node to start (timeout: ${TIMEOUT}s)" + + if [[ "$node" =~ ^($CLN_NODES)$ ]]; then + while ! $node getinfo | grep -q \"id\"; do + sleep 1 + done + BLOCKS=$(bitcoin getblockchaininfo | jq .blocks -r) + while [[ $($node getinfo | jq .blockheight -r | xargs) -lt $BLOCKS ]]; do + sleep 1 + done + + echo + echo "✅ $node has started" + + return 0 + fi + + while ! $node state 2>/dev/null | grep -q SERVER_ACTIVE; do + echo -n "." + sleep 0.5 + + # Check if timeout has been reached. + local elapsed_time=$(( $(date +%s) - start_time )) + if [[ $elapsed_time -ge $TIMEOUT ]]; then + echo + echo "❌ Error: Timeout after $TIMEOUT seconds waiting for $node to start" + return 1 + fi + done + + echo + echo "✅ $node has started" +} + +# do_for is a generic function to execute a command for a set of nodes. +function do_for() { + if [[ $# -lt 2 ]]; then + echo "❌ Error: do_for requires at least 2 arguments (function and nodes)" + echo "Usage: do_for [node1] [node2] [node3]..." + return 1 + fi + + local func="$1" + shift + local nodes=("$@") + + for node in "${nodes[@]}"; do + "$func" "$node" + done +} + +# fund_node funds the specified node with 5 BTC. +function fund_node() { + local node="$1" + + if [[ "$node" =~ ^($CLN_NODES)$ ]]; then + ADDR=$( $node newaddr bech32 | jq .bech32 -r) + else + ADDR=$( $node newaddress p2wkh | jq .address -r) + fi + + bitcoin sendtoaddress "$ADDR" 5 > /dev/null + + echo "💰 Funded $node with 5 BTC" +} + +# connect_nodes connects two specified nodes. +function connect_nodes() { + if [[ $# -ne 2 ]]; then + echo "❌ Error: connect_nodes requires exactly 2 arguments (node1 and node2)" + echo "Usage: connect_nodes " + return 1 + fi + + local node1="$1" + local node2="$2" + + echo -ne "📞 Connecting $node1 to $node2...\r" + + KEY_2=$( node_identity $node2 ) + + if [[ "$node1" =~ ^($CLN_NODES)$ ]]; then + $node1 connect "$KEY_2" $node2 9735 > /dev/null + else + $node1 connect "$KEY_2"@$node2:9735 > /dev/null + fi + + echo -ne " \r" + echo "📞 Connected $node1 to $node2" +} + +# open_channel opens a channel between two specified nodes. +function open_channel() { + if [[ $# -ne 2 ]]; then + echo "❌ Error: open_channel requires exactly 2 arguments (node1 and node2)" + echo "Usage: open_channel " + return 1 + fi + + local node1="$1" + local node2="$2" + + KEY_2=$( node_identity $node2 ) + + if [[ "$node1" =~ ^($CLN_NODES)$ ]]; then + $node1 fundchannel "id=$KEY_2" amount=15000000 push_msat=7000000000 > /dev/null + else + $node1 openchannel --node_key "$KEY_2" --local_amt 15000000 --push_amt 7000000 > /dev/null + fi + + echo "🔗 Opened channel between $node1 and $node2" +} + +# Function to check if a node's graph has the expected number of channels. +function wait_graph_sync() { + if [[ $# -ne 2 ]]; then + echo "❌ Error: graph_synced requires exactly 2 arguments (node and num_chans)" + echo "Usage: graph_synced " + return 1 + fi + + local node="$1" + local num_chans="$2" + + while :; do + num_channels=$($node getnetworkinfo | jq -r '.num_channels') + + # Ensure num_channels is a valid number before proceeding. + if [[ "$num_channels" =~ ^[0-9]+$ ]]; then + echo -ne "⌛ $node sees $num_channels channels...\r" + + if [[ "$num_channels" -eq num_chans ]]; then + echo "👀 $node sees all the channels!" + break # Exit loop when num_channels reaches num_chans. + fi + fi + + sleep 1 + done +} + +# send_payment attempts to send a payment between two specified nodes. +function send_payment() { + if [[ $# -ne 2 ]]; then + echo "❌ Error: send_payment requires exactly 2 arguments (from_node and to_node)" + echo "Usage: send_payment " + return 1 + fi + + local from_node="$1" + local to_node="$2" + + # Generate invoice and capture error output, then extract payment request. + local invoice_output + local PAY_REQ + + if [[ "$to_node" =~ ^($CLN_NODES)$ ]]; then + label=$(openssl rand -hex 12) + if ! invoice_output=$($to_node invoice 10000 $label "" 2>&1); then + echo "❌ Error: Failed to generate invoice from $to_node" + echo "📜 Details: $invoice_output" + return 1 + fi + + PAY_REQ=$(echo "$invoice_output" | jq -r '.bolt11') + else + if ! invoice_output=$($to_node addinvoice 10000 2>&1); then + echo "❌ Error: Failed to generate invoice from $to_node" + echo "📜 Details: $invoice_output" + return 1 + fi + + PAY_REQ=$(echo "$invoice_output" | jq -r '.payment_request') + fi + + # Ensure invoice creation was successful. + if [[ -z "$PAY_REQ" || "$PAY_REQ" == "null" ]]; then + echo "❌ Error: Invoice response did not contain a valid payment request." + echo "📜 Raw Response: $invoice_output" + return 1 + fi + + # Send payment and capture error output. + local payment_output + if ! payment_output=$($from_node payinvoice --force "$PAY_REQ" 2>&1); then + echo "❌ Error: Payment failed from $from_node to $to_node" + echo "📜 Details: $payment_output" + return 1 + fi + + echo "💸 Payment sent from $from_node to $to_node" +} + +# wait_for_active_chans waits for a node to have the expected number of active +# channels. +function wait_for_active_chans() { + if [[ $# -ne 2 ]]; then + echo "❌ Error: wait_for_active_chans requires exactly 2 arguments (node and expected_active_channels)" + echo "Usage: wait_for_active_chans " + return 1 + fi + + local node="$1" + local expected_channels="$2" + + echo "🟠 Waiting for $node to have exactly $expected_channels active channels..." + + while :; do + # Get the active channel count. + local active_count + active_count=$($node --network=regtest listchannels 2>/dev/null | jq '[.channels[] | select(.active == true)] | length') + + # Ensure active_count is a valid number. + if [[ "$active_count" =~ ^[0-9]+$ ]]; then + echo -ne "⌛ $node sees $active_count active channels...\r" + + # Exit loop only if the expected number of channels is active. + if [[ "$active_count" -eq "$expected_channels" ]]; then + break + fi + fi + + sleep 1 + done + + echo + echo "🟢 $node now has exactly $expected_channels active channels!" +} + +# mine mines a number of blocks on the regtest network. If no argument is +# provided, it defaults to 6 blocks. +function mine() { + NUMBLOCKS="${1-6}" + bitcoin generatetoaddress "$NUMBLOCKS" "$(bitcoin getnewaddress "" legacy)" > /dev/null +} + +# setup_bitcoin performs various operations on the regtest bitcoind node so that +# it is ready to be used by the Lightning nodes and so that it can be used to +# fund the nodes. +function setup_bitcoin() { + echo "🔗 Setting up Bitcoin node" + bitcoin createwallet miner > /dev/null + + ADDR_BTC=$(bitcoin getnewaddress "" legacy) + bitcoin generatetoaddress 106 "$ADDR_BTC" > /dev/null + bitcoin getbalance > /dev/null + + echo "🔗 Bitcoin node is set up" +} + +function bitcoin() { + docker exec -i -u bitcoin bitcoind bitcoin-cli -regtest -rpcuser=lightning -rpcpassword=lightning "$@" +} + +function alice() { + docker exec -i alice lncli --network regtest "$@" +} + +function bob() { + docker exec -i bob lncli --network regtest "$@" +} + +function charlie() { + docker exec -i charlie lncli --network regtest "$@" +} + +function dave() { + docker exec -i dave lncli --network regtest "$@" +} + +function rusty() { + docker exec -i rusty lightning-cli --network regtest "$@" +} + +function nifty() { + docker exec -i nifty lightning-cli --network regtest "$@" +} + +function snyke() { + docker exec -i snyke lightning-cli --network regtest "$@" +} diff --git a/itest/docker/run-cmd.sh b/itest/docker/run-cmd.sh new file mode 100755 index 0000000..6c1d4b5 --- /dev/null +++ b/itest/docker/run-cmd.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# The run-cmd.sh file can be used to call any helper functions directly from the +# command line to call any function defined in compose.sh or network.sh. +# For example: +# $ ./run-cmd.sh compose-up + +# DIR is set to the directory of this script. +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source "$DIR/.env" +source "$DIR/compose.sh" +source "$DIR/network.sh" + +CMD=$1 +shift +$CMD "$@" diff --git a/itest/docker/setup-test-network.sh b/itest/docker/setup-test-network.sh new file mode 100755 index 0000000..7612617 --- /dev/null +++ b/itest/docker/setup-test-network.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +# This file sets up a test Lightning Network with multiple nodes and channels +# using Docker. It creates a network topology, opens channels, performs +# payments, and force closes some channels to prepare all node state for the +# integration tests. + +# DIR is set to the directory of this script. +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source "$DIR/compose.sh" +source "$DIR/network.sh" +source "$DIR/.env" + +cd $DIR + +# Prepare all folders. +export NODES=(alice bob charlie dave rusty nifty snyke chantools) + +shopt -s dotglob +for node in "${NODES[@]}"; do + mkdir -p "$DIR/node-data/${node}" + rm -rf "$DIR/node-data/${node}/"{*,.*} +done + +# Spin up the network in detached mode. +compose_up + +# Set up the basic A ◄─► B ◄─► C ◄─► D network. +# └────►└► R ◄┘ +# └► N +setup_bitcoin + +wait_for_nodes alice bob charlie dave rusty nifty snyke + +do_for fund_node alice bob charlie dave rusty nifty snyke + +# Alice, Bob and Charlie will open more than one channel each. +do_for fund_node alice alice bob charlie + +mine 6 + +wait_for_nodes rusty nifty snyke + +connect_nodes alice bob +connect_nodes alice rusty +connect_nodes alice nifty +connect_nodes alice snyke +connect_nodes bob charlie +connect_nodes bob rusty +connect_nodes bob nifty +connect_nodes charlie dave +connect_nodes charlie rusty +connect_nodes rusty nifty + +open_channel alice bob +open_channel alice rusty +open_channel bob charlie +open_channel charlie dave +open_channel bob rusty +open_channel charlie rusty +open_channel rusty nifty +open_channel alice snyke + +echo "🔗 Set up network: Alice ◄─► Bob ◄─► Charlie ◄─► Dave network." +echo " └────────►└► Rusty ◄┘ " +echo " | └► Nifty" +echo " └► Snyke" + +mine 12 + +num_channels=8 + +wait_graph_sync alice $num_channels +wait_graph_sync bob $num_channels +wait_graph_sync charlie $num_channels +wait_graph_sync dave $num_channels + +# Test several multi-hop payments. +send_payment bob dave +send_payment dave bob +send_payment alice dave +send_payment alice rusty +send_payment dave rusty +send_payment alice snyke + +# Repeat the basic tests. +send_payment bob dave +send_payment dave bob +send_payment alice dave +send_payment alice rusty +send_payment dave rusty +send_payment alice snyke + +# Store all the channel information in separate JSON files. +alice listchannels > "$DIR/node-data/chantools/alice-channels.json" +bob listchannels > "$DIR/node-data/chantools/bob-channels.json" +charlie listchannels > "$DIR/node-data/chantools/charlie-channels.json" +dave listchannels > "$DIR/node-data/chantools/dave-channels.json" +rusty listchannels > "$DIR/node-data/chantools/rusty-channels.json" + +# Store all the node pubkeys in a single file. +echo "alice: " $(node_identity alice) >> "$DIR/node-data/chantools/identities.txt" +echo "bob: " $(node_identity bob) >> "$DIR/node-data/chantools/identities.txt" +echo "charlie: " $(node_identity charlie) >> "$DIR/node-data/chantools/identities.txt" +echo "dave: " $(node_identity dave) >> "$DIR/node-data/chantools/identities.txt" +echo "rusty: " $(node_identity rusty) >> "$DIR/node-data/chantools/identities.txt" +echo "nifty: " $(node_identity nifty) >> "$DIR/node-data/chantools/identities.txt" +echo "snyke: " $(node_identity snyke) >> "$DIR/node-data/chantools/identities.txt" + +# Force close the two channels of Bob-Charlie and Charlie-Rusty. +RUSTY=$( node_identity rusty ) +CHARLIE=$( node_identity charlie ) +CHAN_BOB_CHARLIE=$(bob listchannels | jq -r '.channels[] | select(.remote_pubkey=="'$CHARLIE'") | .channel_point') +CHAN_ALICE_RUSTY=$(alice listchannels | jq -r '.channels[] | select(.remote_pubkey=="'$RUSTY'") | .channel_point') +echo "🛡️ Force closing Bob-Charlie channel: $CHAN_BOB_CHARLIE" +echo "🛡️ Force closing Alice-Rusty channel: $CHAN_ALICE_RUSTY" +bob closechannel --force --chan_point "$CHAN_BOB_CHARLIE" +alice closechannel --force --chan_point "$CHAN_ALICE_RUSTY" + +# Revert the changes that are made in lncli to change some of the field names. +sed -i.BAK 's/"chan_id"/"channel_id"/g' "$DIR/node-data/chantools/alice-channels.json" +sed -i.BAK 's/"chan_id"/"channel_id"/g' "$DIR/node-data/chantools/bob-channels.json" +sed -i.BAK 's/"chan_id"/"channel_id"/g' "$DIR/node-data/chantools/charlie-channels.json" +sed -i.BAK 's/"chan_id"/"channel_id"/g' "$DIR/node-data/chantools/dave-channels.json" +sed -i.BAK 's/"scid"/"chan_id"/g' "$DIR/node-data/chantools/alice-channels.json" +sed -i.BAK 's/"scid"/"chan_id"/g' "$DIR/node-data/chantools/bob-channels.json" +sed -i.BAK 's/"scid"/"chan_id"/g' "$DIR/node-data/chantools/charlie-channels.json" +sed -i.BAK 's/"scid"/"chan_id"/g' "$DIR/node-data/chantools/dave-channels.json" +rm "$DIR/node-data/chantools/"*.json.BAK + +# We stop all the nodes except for Dave and Snyke, which are used for the +# triggerforceclose sub command test. +compose_stop alice +compose_stop bob +compose_stop charlie +compose_stop rusty +compose_stop nifty + +# Mine the force closed channels, after shutting down the nodes, to prevent them +# from automatically sweeping the funds. +mine 1 + +echo "🛡️ ⚔️ 🫡 Test setup created successfully! 🫡 ⚔️ 🛡️" diff --git a/itest/itest.sh b/itest/itest.sh new file mode 100755 index 0000000..a067200 --- /dev/null +++ b/itest/itest.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# This script sets up the dockerized LN cluster and runs the integration tests. + +# Stop the script if an error is returned by any step. +set -e + +# ITEST_DIR is set to the directory of this script. +ITEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source "$ITEST_DIR/docker/compose.sh" +source "$ITEST_DIR/docker/network.sh" +source "$ITEST_DIR/docker/.env" + +# We make sure the cluster is always stopped in case it was left running from a +# previous run. +compose_down || true + +# Ensure that the cluster is shut down when the script errors out due to the +# set -e flag above. +trap compose_down ERR + +# If the user doesn't intend to debug the tests (i.e. by keeping the containers +# running after the tests), then we ensure that the cluster is torn down at the +# end of the script. +if [[ -z "$DEBUG" ]] && [[ -z "$debug" ]]; then + trap compose_down EXIT +else + echo "⚠️ Debug mode enabled, not stopping cluster at the end of the tests." +fi + +"$ITEST_DIR"/docker/setup-test-network.sh + +# The network setup part was successful, we don't need that trap anymore. +trap - ERR + +# Make sure we're in the itest directory before running the tests. +cd "$ITEST_DIR" + +# Run the integration tests. +go test -v -count=1 -test.run ^TestIntegration${CASE} ./... From 7a163873003dd2e651a2d7ccad71a80fae05e1f2 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 8 Oct 2025 23:41:28 +0200 Subject: [PATCH 4/6] itest: add Golang based integration tests --- itest/bitcoind_harness.go | 83 +++++ itest/chantools_harness.go | 66 ++-- itest/cmd_sweepremoteclosed_test.go | 49 +++ itest/cmd_triggerforceclose_test.go | 52 +++ itest/cmd_zombierecovery_test.go | 250 ++++++++++++++ itest/helpers.go | 505 ++++++++++++++++++++++++++++ itest/integration_test.go | 52 +++ itest/standalone_test.go | 46 ++- 8 files changed, 1056 insertions(+), 47 deletions(-) create mode 100644 itest/bitcoind_harness.go create mode 100644 itest/cmd_sweepremoteclosed_test.go create mode 100644 itest/cmd_triggerforceclose_test.go create mode 100644 itest/cmd_zombierecovery_test.go create mode 100644 itest/helpers.go create mode 100644 itest/integration_test.go diff --git a/itest/bitcoind_harness.go b/itest/bitcoind_harness.go new file mode 100644 index 0000000..c1e802a --- /dev/null +++ b/itest/bitcoind_harness.go @@ -0,0 +1,83 @@ +package itest + +import ( + "strconv" + "strings" + "testing" + + "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/stretchr/testify/require" +) + +func connectBitcoind(t *testing.T) *rpcclient.Client { + t.Helper() + + rpcCfg := rpcclient.ConnConfig{ + Host: "127.0.0.1:18443", + User: "lightning", + Pass: "lightning", + DisableConnectOnNew: true, + DisableAutoReconnect: false, + DisableTLS: true, + HTTPPostMode: true, + } + + client, err := rpcclient.New(&rpcCfg, nil) + require.NoError(t, err) + + return client +} + +func addressOfOutpoint(t *testing.T, client *rpcclient.Client, + op string) string { + + t.Helper() + + channelOp, err := wire.NewOutPointFromString(op) + require.NoError(t, err) + + channelTx, err := client.GetRawTransaction(&channelOp.Hash) + require.NoError(t, err) + + channelScript := channelTx.MsgTx().TxOut[channelOp.Index].PkScript + _, addrs, _, err := txscript.ExtractPkScriptAddrs( + channelScript, &testParams, + ) + require.NoError(t, err) + require.Len(t, addrs, 1) + + return addrs[0].EncodeAddress() +} + +func addrAndOpFromShortChannelID(t *testing.T, client *rpcclient.Client, + shortChanID string) (string, wire.OutPoint) { + + t.Helper() + + parts := strings.Split(shortChanID, "x") + require.Len(t, parts, 3) + + blockHeight, err := strconv.Atoi(parts[0]) + require.NoError(t, err) + txIndex, err := strconv.Atoi(parts[1]) + require.NoError(t, err) + outputIndex, err := strconv.Atoi(parts[2]) + require.NoError(t, err) + + blockHash, err := client.GetBlockHash(int64(blockHeight)) + require.NoError(t, err) + + block, err := client.GetBlock(blockHash) + require.NoError(t, err) + require.Greater(t, len(block.Transactions), outputIndex) + + tx := block.Transactions[txIndex] + op := wire.OutPoint{ + Hash: tx.TxHash(), + Index: uint32(outputIndex), + } + + return addressOfOutpoint(t, client, op.String()), op +} diff --git a/itest/chantools_harness.go b/itest/chantools_harness.go index c776da7..1e08f7b 100644 --- a/itest/chantools_harness.go +++ b/itest/chantools_harness.go @@ -5,6 +5,7 @@ import ( "bytes" "errors" "io" + "io/fs" "os" "os/exec" "strings" @@ -27,6 +28,8 @@ type ChantoolsProcess struct { func StartChantools(t *testing.T, args ...string) *ChantoolsProcess { t.Helper() + log.Debugf("Calling chantools with args: %v", args) + args = append([]string{"--nologfile"}, args...) cmd := exec.Command("chantools", args...) stdin, err := cmd.StdinPipe() @@ -42,13 +45,35 @@ func StartChantools(t *testing.T, args ...string) *ChantoolsProcess { require.NoError(t, cmd.Start()) - return &ChantoolsProcess{ + proc := &ChantoolsProcess{ cmd: cmd, stdin: stdin, stdout: stdoutFile, stdoutReader: bufio.NewReader(stdoutFile), stderr: bufio.NewReader(stderrPipe), } + + proc.AssertNoStderr(t) + return proc +} + +func (p *ChantoolsProcess) AssertNoStderr(t *testing.T) { + t.Helper() + + require.Never(t, func() bool { + stderrBytes, err := io.ReadAll(p.stderr) + if isProcessExitErr(err) { + return false + } + require.NoError(t, err) + + if len(stderrBytes) > 0 { + t.Logf("Stderr has unexpected output: %s", stderrBytes) + return true + } + + return false + }, shortTimeout, testTick) } // WriteInput writes input to the process's stdin. @@ -66,37 +91,11 @@ func (p *ChantoolsProcess) ReadAllOutput(t *testing.T) string { resp, err := io.ReadAll(p.stdout) require.NoError(t, err, "failed to read chantools output") - log.Debugf("[CHANTOOLS]: %s", resp) + log.Debugf("[CHANTOOLS]: %s", strings.TrimSpace(string(resp))) return string(resp) } -// ReadOutputUntil reads from stdout until the given substring is found or -// timeout. -func (p *ChantoolsProcess) ReadOutputUntil(t *testing.T, substr string, - timeout time.Duration) string { - - t.Helper() - - var out bytes.Buffer - deadline := time.Now().Add(timeout) - for { - if time.Now().After(deadline) { - t.Fatal("timeout waiting for chantools output") - } - line, err := p.stdoutReader.ReadString('\n') - out.WriteString(line) - - log.Debugf("[CHANTOOLS]: %s", line) - - if strings.Contains(out.String(), substr) { - return out.String() - } - - require.NoError(t, err) - } -} - // ReadAvailableOutput reads as many bytes as possible from stdout until the // timeout elapses. func (p *ChantoolsProcess) ReadAvailableOutput(t *testing.T, @@ -130,7 +129,7 @@ func (p *ChantoolsProcess) ReadAvailableOutput(t *testing.T, } } - log.Debugf("[CHANTOOLS]: %s", out.String()) + log.Debugf("[CHANTOOLS]: %s", strings.TrimSpace(out.String())) return out.String() } @@ -147,3 +146,12 @@ func (p *ChantoolsProcess) Kill(t *testing.T) { require.NoError(t, p.cmd.Process.Kill()) } + +func isProcessExitErr(err error) bool { + var pathError *fs.PathError + if err != nil && errors.As(err, &pathError) { + return errors.Is(pathError.Err, fs.ErrClosed) + } + + return false +} diff --git a/itest/cmd_sweepremoteclosed_test.go b/itest/cmd_sweepremoteclosed_test.go new file mode 100644 index 0000000..c026cf0 --- /dev/null +++ b/itest/cmd_sweepremoteclosed_test.go @@ -0,0 +1,49 @@ +package itest + +import ( + "bytes" + "encoding/hex" + "testing" + + "github.com/btcsuite/btcd/wire" + "github.com/stretchr/testify/require" +) + +func runSweepRemoteClosedLnd(t *testing.T) { + sweepAddr := randTaprootAddr(t) + txHex := getSweepRemoteClosed( + t, "charlie", tempDir, localElectrsAddr, sweepAddr, + ) + + txBytes, err := hex.DecodeString(txHex) + require.NoError(t, err) + + var tx wire.MsgTx + err = tx.Deserialize(bytes.NewReader(txBytes)) + require.NoError(t, err) + + backend := connectBitcoind(t) + txHash, err := backend.SendRawTransaction(&tx, false) + require.NoError(t, err) + t.Logf("Sweep transaction sent: %v", txHash.String()) +} + +func runSweepRemoteClosedCln(t *testing.T) { + aliceIdentity := getNodeIdentityKey(t, "alice") + sweepAddr := randTaprootAddr(t) + txHex := getSweepRemoteClosedCln( + t, "rusty", tempDir, localElectrsAddr, aliceIdentity, sweepAddr, + ) + + txBytes, err := hex.DecodeString(txHex) + require.NoError(t, err) + + var tx wire.MsgTx + err = tx.Deserialize(bytes.NewReader(txBytes)) + require.NoError(t, err) + + backend := connectBitcoind(t) + txHash, err := backend.SendRawTransaction(&tx, false) + require.NoError(t, err) + t.Logf("Sweep transaction sent: %v", txHash.String()) +} diff --git a/itest/cmd_triggerforceclose_test.go b/itest/cmd_triggerforceclose_test.go new file mode 100644 index 0000000..151834d --- /dev/null +++ b/itest/cmd_triggerforceclose_test.go @@ -0,0 +1,52 @@ +package itest + +import ( + "fmt" + "testing" + + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/stretchr/testify/require" +) + +func runTriggerForceCloseLnd(t *testing.T) { + daveChannels := readChannelsJSON(t, "dave") + charlieIdentity := getNodeIdentityKey(t, "charlie") + daveIdentity := readNodeIdentityFromFile(t, "dave") + daveURI := fmt.Sprintf(nodeURIPattern, daveIdentity, localDaveAddr) + + var charlieDaveChannel *lnrpc.Channel + for _, c := range daveChannels { + if c.RemotePubkey == charlieIdentity { + charlieDaveChannel = c + } + } + require.NotNil(t, charlieDaveChannel, "charlie-dave channel not found") + + txid := getTriggerForceClose( + t, "charlie", tempDir, localElectrsAddr, daveURI, + charlieDaveChannel.ChannelPoint, + ) + + t.Logf("Force close TX found: %v", txid) +} + +func runTriggerForceCloseCln(t *testing.T) { + aliceChannels := readChannelsJSON(t, "alice") + snykeIdentity := getNodeIdentityKeyCln(t, "snyke") + snykeURI := fmt.Sprintf(nodeURIPattern, snykeIdentity, localSnykeAddr) + + var aliceSnykeChannel *lnrpc.Channel + for _, c := range aliceChannels { + if c.RemotePubkey == snykeIdentity { + aliceSnykeChannel = c + } + } + require.NotNil(t, aliceSnykeChannel, "alice-snyke channel not found") + + txid := getTriggerForceClose( + t, "alice", tempDir, localElectrsAddr, snykeURI, + aliceSnykeChannel.ChannelPoint, + ) + + t.Logf("Force close TX found: %v", txid) +} diff --git a/itest/cmd_zombierecovery_test.go b/itest/cmd_zombierecovery_test.go new file mode 100644 index 0000000..dced933 --- /dev/null +++ b/itest/cmd_zombierecovery_test.go @@ -0,0 +1,250 @@ +package itest + +import ( + "bytes" + "encoding/hex" + "fmt" + "strconv" + "testing" + + "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/stretchr/testify/require" +) + +const ( + tempDir = "./docker/node-data/chantools" +) + +type zombieNode struct { + PubKey string `json:"identity_pubkey"` + Contact string `json:"contact"` + PayoutAddr string `json:"payout_addr,omitempty"` + MultisigKeys []string `json:"multisig_keys,omitempty"` +} + +type zombieChannel struct { + ChannelID string `json:"short_channel_id"` + ChanPoint string `json:"chan_point"` + Address string `json:"address"` + Capacity int64 `json:"capacity"` +} + +type zombieMatch struct { + Node1 *zombieNode `json:"node1"` + Node2 *zombieNode `json:"node2"` + Channels []*zombieChannel `json:"channels"` +} + +func makeMatchFile(t *testing.T, node1Name, node2Name, node1Identity, + node2Identity, channelPoint, channelID, address string, + capacity int64) string { + + match := &zombieMatch{ + Node1: &zombieNode{ + PubKey: node1Identity, + Contact: node1Name, + }, + Node2: &zombieNode{ + PubKey: node2Identity, + Contact: node2Name, + }, + Channels: []*zombieChannel{{ + ChannelID: channelID, + ChanPoint: channelPoint, + Address: address, + Capacity: capacity, + }}, + } + + matchFile := fmt.Sprintf("%s/%s-%s-match.json", tempDir, node1Name, + node2Name) + err := writeJSONFile(matchFile, match) + require.NoError(t, err) + + return matchFile +} + +func publishTx(t *testing.T, txHex string, backend *rpcclient.Client) { + txBytes, err := hex.DecodeString(txHex) + require.NoError(t, err) + + var tx wire.MsgTx + err = tx.Deserialize(bytes.NewReader(txBytes)) + require.NoError(t, err) + + txHash, err := backend.SendRawTransaction(&tx, false) + require.NoError(t, err) + t.Logf("Closing transaction sent: %v", txHash.String()) +} + +func runZombieRecoveryLndLnd(t *testing.T) { + aliceChannels := readChannelsJSON(t, "alice") + aliceIdentity := getNodeIdentityKey(t, "alice") + bobIdentity := getNodeIdentityKey(t, "bob") + aliceSweepAddr := randTaprootAddr(t) + bobSweepAddr := randTaprootAddr(t) + + var aliceBobChannel *lnrpc.Channel + for _, c := range aliceChannels { + if c.RemotePubkey == bobIdentity { + aliceBobChannel = c + } + } + require.NotNil(t, aliceBobChannel, "alice-bob channel not found") + + backend := connectBitcoind(t) + addr := addressOfOutpoint(t, backend, aliceBobChannel.ChannelPoint) + matchFile := makeMatchFile( + t, "alice", "bob", aliceIdentity, bobIdentity, + aliceBobChannel.ChannelPoint, + strconv.FormatUint(aliceBobChannel.ChanId, 10), addr, + aliceBobChannel.Capacity, + ) + + resultsFileAlice := getZombiePreparedKeys( + t, "alice", tempDir, matchFile, aliceSweepAddr, + ) + resultsFileBob := getZombiePreparedKeys( + t, "bob", tempDir, matchFile, bobSweepAddr, + ) + + psbt := getZombieMakeOffer( + t, "alice", tempDir, resultsFileAlice, resultsFileBob, + 7_000_000, + ) + + txHex := getZombieSignOffer(t, "bob", tempDir, psbt) + publishTx(t, txHex, backend) +} + +func runZombieRecoveryLndCln(t *testing.T) { + bobChannels := readChannelsJSON(t, "bob") + bobIdentity := getNodeIdentityKey(t, "bob") + rustyIdentity := getNodeIdentityKeyCln(t, "rusty") + bobSweepAddr := randTaprootAddr(t) + rustySweepAddr := randTaprootAddr(t) + + var bobRustyChannel *lnrpc.Channel + for _, c := range bobChannels { + if c.RemotePubkey == rustyIdentity { + bobRustyChannel = c + } + } + require.NotNil(t, bobRustyChannel, "bob-rusty channel not found") + + backend := connectBitcoind(t) + addr := addressOfOutpoint(t, backend, bobRustyChannel.ChannelPoint) + matchFile := makeMatchFile( + t, "bob", "rusty", bobIdentity, rustyIdentity, + bobRustyChannel.ChannelPoint, + strconv.FormatUint(bobRustyChannel.ChanId, 10), addr, + bobRustyChannel.Capacity, + ) + + resultsFileBob := getZombiePreparedKeys( + t, "bob", tempDir, matchFile, bobSweepAddr, + ) + resultsFileRusty := getZombiePreparedKeysCln( + t, "rusty", tempDir, matchFile, rustySweepAddr, + ) + + psbt := getZombieMakeOffer( + t, "bob", tempDir, resultsFileBob, resultsFileRusty, + 7_000_000, + ) + + txHex := getZombieSignOfferCln(t, "rusty", tempDir, bobIdentity, psbt) + publishTx(t, txHex, backend) +} + +func runZombieRecoveryClnLnd(t *testing.T) { + charlieChannels := readChannelsJSON(t, "charlie") + charlieIdentity := getNodeIdentityKey(t, "charlie") + rustyIdentity := getNodeIdentityKeyCln(t, "rusty") + charlieSweepAddr := randTaprootAddr(t) + rustySweepAddr := randTaprootAddr(t) + + var rustyCharlieChannel *lnrpc.Channel + for _, c := range charlieChannels { + if c.RemotePubkey == rustyIdentity { + rustyCharlieChannel = c + } + } + require.NotNil( + t, rustyCharlieChannel, "charlie-rusty channel not found", + ) + + backend := connectBitcoind(t) + addr := addressOfOutpoint(t, backend, rustyCharlieChannel.ChannelPoint) + matchFile := makeMatchFile( + t, "charlie", "rusty", charlieIdentity, rustyIdentity, + rustyCharlieChannel.ChannelPoint, + strconv.FormatUint(rustyCharlieChannel.ChanId, 10), addr, + rustyCharlieChannel.Capacity, + ) + + resultsFileCharlie := getZombiePreparedKeys( + t, "charlie", tempDir, matchFile, charlieSweepAddr, + ) + resultsFileRusty := getZombiePreparedKeysCln( + t, "rusty", tempDir, matchFile, rustySweepAddr, + ) + + psbt := getZombieMakeOfferCln( + t, "rusty", tempDir, resultsFileCharlie, resultsFileRusty, + 7_000_000, + ) + + txHex := getZombieSignOffer(t, "charlie", tempDir, psbt) + publishTx(t, txHex, backend) +} + +func runZombieRecoveryClnCln(t *testing.T) { + niftyIdentity := getNodeIdentityKeyCln(t, "nifty") + rustyChannels := readChannelsJSONCln(t, "rusty") + rustyIdentity := getNodeIdentityKeyCln(t, "rusty") + niftySweepAddr := randTaprootAddr(t) + rustySweepAddr := randTaprootAddr(t) + + var rustyNiftyChannel *clnChannel + for _, c := range rustyChannels { + src := c.Source + dst := c.Destination + if (dst == niftyIdentity && src == rustyIdentity) || + (dst == rustyIdentity && src == niftyIdentity) { + + rustyNiftyChannel = &c + } + } + require.NotNil( + t, rustyNiftyChannel, "rusty-nifty channel not found", + ) + + backend := connectBitcoind(t) + addr, op := addrAndOpFromShortChannelID( + t, backend, rustyNiftyChannel.ShortID, + ) + + matchFile := makeMatchFile( + t, "nifty", "rusty", niftyIdentity, rustyIdentity, + op.String(), rustyNiftyChannel.ShortID, addr, + rustyNiftyChannel.AmountMsat/1000, + ) + + resultsFileNifty := getZombiePreparedKeysCln( + t, "nifty", tempDir, matchFile, niftySweepAddr, + ) + resultsFileRusty := getZombiePreparedKeysCln( + t, "rusty", tempDir, matchFile, rustySweepAddr, + ) + + psbt := getZombieMakeOfferCln( + t, "rusty", tempDir, resultsFileNifty, resultsFileRusty, + 7_000_000, + ) + + txHex := getZombieSignOfferCln(t, "nifty", tempDir, rustyIdentity, psbt) + publishTx(t, txHex, backend) +} diff --git a/itest/helpers.go b/itest/helpers.go new file mode 100644 index 0000000..f97123b --- /dev/null +++ b/itest/helpers.go @@ -0,0 +1,505 @@ +// nolint: unparam +package itest + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "regexp" + "testing" + "time" + + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" +) + +// Local addresses for services running in the Docker Compose setup. +// See docker/.env, where they are defined. +const ( + localElectrsAddr = "http://127.0.0.1:3004" + localDaveAddr = "127.0.0.1:9700" + localSnykeAddr = "127.0.0.1:9701" +) + +const ( + channelsFilePattern = "docker/node-data/chantools/%s-channels.json" + walletFilePattern = "docker/node-data/%s/data/chain/bitcoin/" + + "regtest/wallet.db" + hsmSecretFilePattern = "docker/node-data/%s/regtest/hsm_secret" + nodeIdentityFilePattern = "docker/node-data/chantools/identities.txt" + nodeURIPattern = "%s@%s" + + // rowPublicKey matches "Public key:" as well as "Node identity public + // key:". + rowPublicKey = "ublic key:" + + rowResults = " Writing result to" + rowChannelBalance = "before fees?:" + rowOffer = "other party to review and sign (if they accept):" + psbtBase64Ident = "cHNid" + transactionHexIdent = "02000000" + rowSign = "Press to continue and sign the " + + "transaction or to abort:" + rowPublish = "Please publish this using any bitcoin node:" + rowTransaction = "Transaction:" + rowForceClose = "Found force close transaction" +) + +var ( + readTimeout = 100 * time.Millisecond + testTick = 50 * time.Millisecond + shortTimeout = 500 * time.Millisecond + defaultTimeout = 5 * time.Second + longTimeout = 30 * time.Second + + testParams = chaincfg.RegressionNetParams + + lncliOpts = &protojson.UnmarshalOptions{ + AllowPartial: true, + DiscardUnknown: true, + UseHexForBytes: true, + } + + emptyPassword = "" +) + +type clnChannel struct { + Source string `json:"source"` + Destination string `json:"destination"` + ShortID string `json:"short_channel_id"` + AmountMsat int64 `json:"amount_msat"` +} + +type clnChannelList struct { + Channels []clnChannel `json:"channels"` +} + +func extractRowContent(row, prefix string) string { + rex := regexp.MustCompile( + fmt.Sprintf(`(?sm)%s\s+(.*?)\s+`, regexp.QuoteMeta(prefix)), + ) + matches := rex.FindAllStringSubmatch(row, -1) + for _, groups := range matches { + return groups[1] + } + + return "" +} + +func randTaprootAddr(t *testing.T) string { + t.Helper() + + key, err := secp256k1.GeneratePrivateKey() + require.NoError(t, err) + + trKey := txscript.ComputeTaprootKeyNoScript(key.PubKey()) + + addr, err := btcutil.NewAddressTaproot( + schnorr.SerializePubKey(trKey), &testParams, + ) + require.NoError(t, err) + + return addr.EncodeAddress() +} + +func readChannelsJSON(t *testing.T, node string) []*lnrpc.Channel { + t.Helper() + + contentBytes, err := os.ReadFile(fmt.Sprintf(channelsFilePattern, node)) + require.NoError(t, err) + + var resp lnrpc.ListChannelsResponse + err = lncliOpts.Unmarshal(contentBytes, &resp) + require.NoError(t, err) + require.NotEmpty(t, resp.Channels) + + return resp.Channels +} + +func readNodeIdentityFromFile(t *testing.T, node string) string { + t.Helper() + + contentBytes, err := os.ReadFile(nodeIdentityFilePattern) + require.NoError(t, err) + + identity := extractRowContent(string(contentBytes), node+":") + + return identity +} + +func readChannelsJSONCln(t *testing.T, node string) []clnChannel { + t.Helper() + + contentBytes, err := os.ReadFile(fmt.Sprintf(channelsFilePattern, node)) + require.NoError(t, err) + + var resp clnChannelList + err = json.Unmarshal(contentBytes, &resp) + require.NoError(t, err) + require.NotEmpty(t, resp.Channels) + + return resp.Channels +} + +func writeJSONFile(fileName string, v any) error { + summaryBytes, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + log.Infof("Writing JSON to %s", fileName) + return os.WriteFile(fileName, summaryBytes, 0644) +} + +func invokeCmdDeriveKey(t *testing.T, walletPassword *string, + args ...string) string { + + t.Helper() + + fullArgs := append([]string{"--regtest", "derivekey"}, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + output := proc.ReadAvailableOutput(t, defaultTimeout) + require.Contains(t, output, rowPublicKey) + + return output +} + +func invokeCmdZombieRecoveryPrepareKeys(t *testing.T, walletPassword *string, + resultsDir string, args ...string) string { + + t.Helper() + + fullArgs := append([]string{ + "--regtest", "--resultsdir", resultsDir, + "zombierecovery", "preparekeys", + }, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + output := proc.ReadAvailableOutput(t, defaultTimeout) + require.Contains(t, output, rowResults) + + return output +} + +func invokeCmdZombieRecoveryMakeOffer(t *testing.T, walletPassword *string, + resultsDir string, localBalance int64, args ...string) string { + + t.Helper() + + fullArgs := append([]string{ + "--regtest", "--resultsdir", resultsDir, + "zombierecovery", "makeoffer", + }, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + question := proc.ReadAvailableOutput(t, defaultTimeout) + require.Contains(t, question, rowChannelBalance) + + proc.WriteInput(t, fmt.Sprintf("%d\n", localBalance)) + + output := proc.ReadAvailableOutput(t, readTimeout) + + return output +} + +func invokeCmdZombieRecoverySignOffer(t *testing.T, walletPassword *string, + resultsDir string, args ...string) string { + + t.Helper() + + fullArgs := append([]string{ + "--regtest", "--resultsdir", resultsDir, + "zombierecovery", "signoffer", + }, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + question := proc.ReadAvailableOutput(t, defaultTimeout) + require.Contains(t, question, rowSign) + + proc.WriteInput(t, "\n") + + output := proc.ReadAvailableOutput(t, readTimeout) + + return output +} + +func invokeCmdSweepRemoteClosed(t *testing.T, walletPassword *string, + resultsDir, apiURL string, args ...string) string { + + t.Helper() + + fullArgs := append([]string{ + "--regtest", "--resultsdir", resultsDir, + "sweepremoteclosed", "--apiurl", apiURL, + }, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + output := proc.ReadAvailableOutput(t, longTimeout) + return output +} + +func invokeCmdTriggerForceClose(t *testing.T, walletPassword *string, + resultsDir, apiURL string, args ...string) string { + + t.Helper() + + fullArgs := append([]string{ + "--regtest", "--resultsdir", resultsDir, + "triggerforceclose", "--apiurl", apiURL, + }, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + output := proc.ReadAvailableOutput(t, longTimeout) + return output +} + +func getNodeIdentityKey(t *testing.T, node string) string { + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdDeriveKey( + t, &emptyPassword, "--identity", "--walletdb", walletDbPath, + ) + pubKey := extractRowContent(cmdOutput, rowPublicKey) + require.Len( + t, pubKey, hex.EncodedLen(secp256k1.PubKeyBytesLenCompressed), + ) + + return pubKey +} + +func readHsmSecret(t *testing.T, node string) string { + t.Helper() + + hsmSecretPath := fmt.Sprintf(hsmSecretFilePattern, node) + contentBytes, err := os.ReadFile(hsmSecretPath) + require.NoError(t, err) + require.Len(t, contentBytes, 32) + + return hex.EncodeToString(contentBytes) +} + +func getNodeIdentityKeyCln(t *testing.T, node string) string { + t.Helper() + + cmdOutput := invokeCmdDeriveKey( + t, nil, "--identity", "--hsm_secret", readHsmSecret(t, node), + ) + pubKey := extractRowContent(cmdOutput, rowPublicKey) + require.Len( + t, pubKey, hex.EncodedLen(secp256k1.PubKeyBytesLenCompressed), + ) + + return pubKey +} + +func getZombiePreparedKeys(t *testing.T, node, tempDir, matchFile, + payoutAddr string) string { + + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdZombieRecoveryPrepareKeys( + t, &emptyPassword, tempDir, "--match_file", matchFile, + "--payout_addr", payoutAddr, "--walletdb", walletDbPath, + ) + resultFile := extractRowContent(cmdOutput, rowResults) + require.Contains(t, resultFile, "preparedkeys") + + return resultFile +} + +func getZombiePreparedKeysCln(t *testing.T, node, tempDir, matchFile, + payoutAddr string) string { + + t.Helper() + + cmdOutput := invokeCmdZombieRecoveryPrepareKeys( + t, nil, tempDir, "--match_file", matchFile, + "--payout_addr", payoutAddr, + "--hsm_secret", readHsmSecret(t, node), + ) + resultFile := extractRowContent(cmdOutput, rowResults) + require.Contains(t, resultFile, "preparedkeys") + + return resultFile +} + +func getZombieMakeOffer(t *testing.T, node, tempDir, keys1File, + keys2File string, localBalance int64) string { + + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdZombieRecoveryMakeOffer( + t, &emptyPassword, tempDir, localBalance, + "--node1_keys", keys1File, "--node2_keys", keys2File, + "--walletdb", walletDbPath, + ) + psbt := extractRowContent(cmdOutput, rowOffer) + require.Contains(t, psbt, psbtBase64Ident) + + return psbt +} + +func getZombieMakeOfferCln(t *testing.T, node, tempDir, keys1File, + keys2File string, localBalance int64) string { + + t.Helper() + + cmdOutput := invokeCmdZombieRecoveryMakeOffer( + t, nil, tempDir, localBalance, + "--node1_keys", keys1File, "--node2_keys", keys2File, + "--hsm_secret", readHsmSecret(t, node), + ) + psbt := extractRowContent(cmdOutput, rowOffer) + require.Contains(t, psbt, psbtBase64Ident) + + return psbt +} + +func getZombieSignOffer(t *testing.T, node, tempDir, psbt string) string { + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdZombieRecoverySignOffer( + t, &emptyPassword, tempDir, + "--psbt", psbt, "--walletdb", walletDbPath, + ) + txHex := extractRowContent(cmdOutput, rowPublish) + require.Contains(t, txHex, transactionHexIdent) + + return txHex +} + +func getZombieSignOfferCln(t *testing.T, node, tempDir, peerIdentity, + psbt string) string { + + t.Helper() + + cmdOutput := invokeCmdZombieRecoverySignOffer( + t, nil, tempDir, "--remote_peer", peerIdentity, "--psbt", psbt, + "--hsm_secret", readHsmSecret(t, node), + ) + txHex := extractRowContent(cmdOutput, rowPublish) + require.Contains(t, txHex, transactionHexIdent) + + return txHex +} + +func getSweepRemoteClosed(t *testing.T, node, tempDir, apiURL, + sweepAddr string) string { + + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdSweepRemoteClosed( + t, &emptyPassword, tempDir, apiURL, "--sweepaddr", sweepAddr, + "--recoverywindow", "10", "--walletdb", walletDbPath, + ) + txHex := extractRowContent(cmdOutput, rowTransaction) + require.Contains(t, txHex, transactionHexIdent) + + return txHex +} + +func getSweepRemoteClosedCln(t *testing.T, node, tempDir, apiURL, peerIdentity, + sweepAddr string) string { + + t.Helper() + + cmdOutput := invokeCmdSweepRemoteClosed( + t, nil, tempDir, apiURL, "--sweepaddr", sweepAddr, + "--recoverywindow", "10", "--peers", peerIdentity, + "--hsm_secret", readHsmSecret(t, node), + ) + txHex := extractRowContent(cmdOutput, rowTransaction) + require.Contains(t, txHex, transactionHexIdent) + + return txHex +} + +func getTriggerForceClose(t *testing.T, node, tempDir, apiURL, peerURI, + channelPoint string) string { + + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdTriggerForceClose( + t, &emptyPassword, tempDir, apiURL, "--peer", peerURI, + "--channel_point", channelPoint, + "--walletdb", walletDbPath, + ) + txid := extractRowContent(cmdOutput, rowForceClose) + require.Len(t, txid, hex.EncodedLen(sha256.Size)) + + return txid +} diff --git a/itest/integration_test.go b/itest/integration_test.go new file mode 100644 index 0000000..a4940d2 --- /dev/null +++ b/itest/integration_test.go @@ -0,0 +1,52 @@ +package itest + +import ( + "testing" +) + +type testCase struct { + name string + fn func(t *testing.T) +} + +var testCases = []testCase{ + { + name: "zombie recovery lnd <-> lnd", + fn: runZombieRecoveryLndLnd, + }, + { + name: "zombie recovery lnd <-> cln", + fn: runZombieRecoveryLndCln, + }, + { + name: "zombie recovery cln <-> lnd", + fn: runZombieRecoveryClnLnd, + }, + { + name: "zombie recovery cln <-> cln", + fn: runZombieRecoveryClnCln, + }, + { + name: "sweep remote closed lnd", + fn: runSweepRemoteClosedLnd, + }, + { + name: "sweep remote closed cln", + fn: runSweepRemoteClosedCln, + }, + { + name: "trigger force close lnd", + fn: runTriggerForceCloseLnd, + }, + { + name: "trigger force close cln", + fn: runTriggerForceCloseCln, + }, +} + +// TestIntegration runs all integration test cases. +func TestIntegration(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, tc.fn) + } +} diff --git a/itest/standalone_test.go b/itest/standalone_test.go index beff118..2a0ea45 100644 --- a/itest/standalone_test.go +++ b/itest/standalone_test.go @@ -2,7 +2,6 @@ package itest import ( "testing" - "time" "github.com/stretchr/testify/require" ) @@ -14,31 +13,28 @@ const ( testMnemonic = "about wolf boost other battle asthma refuse wedding " + "few purchase track one smooth tunnel immune glass infant " + "tag manual multiply diagram orient wrist agent" -) -var ( - readTimeout = 100 * time.Millisecond - defaultTimeout = 5 * time.Second + testIdentityKey = "03c0da201eedf786d432b6b93fc054355478aee2a97448971c" + + "dfcfa8f13953c58c" + + testHsmSecret = "f85e33c27dc7a87c81ee1f9d8ae15c6d756e53089d75aa6dc480" + + "3d23b4af4b2b" + + testClnIdentityKey = "026672d7c7bce3ffb9cdc7fe42c433dc78f113732d8459e" + + "608ae301409ba1a6f05" ) func TestChantoolsShowRootKeyXPriv(t *testing.T) { proc := StartChantools(t, "showrootkey", "--rootkey", testXPriv) - defer proc.Kill(t) + defer proc.Wait(t) - output := proc.ReadOutputUntil( - t, "Your BIP32 HD root key is:", defaultTimeout, - ) + output := proc.ReadAvailableOutput(t, defaultTimeout) require.Contains(t, output, "Your BIP32 HD root key is: "+testXPriv) } func TestChantoolsShowRootKeyMnemonic(t *testing.T) { proc := StartChantools(t, "showrootkey") - defer proc.Kill(t) - - go func() { - errString, err := proc.stderr.ReadString('\n') - log.Errorf("chantools stderr: %v, error: %v", errString, err) - }() + defer proc.Wait(t) mnemonicPrompt := proc.ReadAvailableOutput(t, readTimeout) require.Contains(t, mnemonicPrompt, "Input your 24-word mnemonic") @@ -50,8 +46,22 @@ func TestChantoolsShowRootKeyMnemonic(t *testing.T) { ) proc.WriteInput(t, "\n") - output := proc.ReadOutputUntil( - t, "Your BIP32 HD root key is:", defaultTimeout, - ) + output := proc.ReadAvailableOutput(t, defaultTimeout) require.Contains(t, output, "Your BIP32 HD root key is: "+testXPriv) } + +func TestDeriveKey(t *testing.T) { + cmdOutput := invokeCmdDeriveKey( + t, nil, "--identity", "--rootkey", testXPriv, + ) + pubKey := extractRowContent(cmdOutput, rowPublicKey) + require.Equal(t, testIdentityKey, pubKey) +} + +func TestDeriveKeyCln(t *testing.T) { + cmdOutput := invokeCmdDeriveKey( + t, nil, "--identity", "--hsm_secret", testHsmSecret, + ) + pubKey := extractRowContent(cmdOutput, rowPublicKey) + require.Equal(t, testClnIdentityKey, pubKey) +} From d6351bcfebf6d4028ad30b01efb99394160fcf02 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 8 Oct 2025 23:41:29 +0200 Subject: [PATCH 5/6] GitHub: run integration tests in CI --- .github/workflows/main.yml | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ed485ce..e270442 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,9 +13,6 @@ defaults: shell: bash env: - # go needs absolute directories, using the $HOME variable doesn't work here. - GOCACHE: /home/runner/work/go/pkg/build - GOPATH: /home/runner/work/go GO_VERSION: 1.23.9 jobs: @@ -27,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: git checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 with: fetch-depth: 0 @@ -42,10 +39,10 @@ jobs: runs-on: ubuntu-latest steps: - name: git checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: setup go ${{ env.GO_VERSION }} - uses: actions/setup-go@v2 + uses: actions/setup-go@v5 with: go-version: '${{ env.GO_VERSION }}' @@ -54,3 +51,24 @@ jobs: - name: run unit tests run: make unit + + ######################## + # run integration tests + ######################## + integration-test: + name: run integration tests + runs-on: ubuntu-latest + steps: + - name: git checkout + uses: actions/checkout@v5 + + - name: setup go ${{ env.GO_VERSION }} + uses: actions/setup-go@v5 + with: + go-version: '${{ env.GO_VERSION }}' + + - name: Install chantools + run: make install + + - name: run integration tests + run: make itest From d739aec3588a2521b286243d96fc50f37f55147b Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Fri, 10 Oct 2025 12:31:13 +0200 Subject: [PATCH 6/6] tools: update linter --- .golangci.yml | 73 ++++---- tools/Dockerfile | 4 +- tools/go.mod | 207 ++++++++++++--------- tools/go.sum | 472 +++++++++++++++++++++++++---------------------- tools/tools.go | 2 +- 5 files changed, 407 insertions(+), 351 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 12b186d..5dddc30 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,32 +1,11 @@ +version: "2" + run: - # timeout for analysis - timeout: 4m + timeout: 5m go: "1.23" -linters-settings: - govet: - # Don't report about shadowed variables - shadow: false - gofmt: - # simplify code: gofmt with `-s` option, true by default - simplify: true - whitespace: - multi-func: true - multi-if: true - tagliatelle: - case: - rules: - json: snake - staticcheck: - checks: ["-SA1019"] - gomoddirectives: - replace-allow-list: - # See go.mod for the explanation why these are needed. - - google.golang.org/protobuf - - linters: - enable-all: true + default: all disable: - gochecknoglobals - gosec @@ -43,20 +22,50 @@ linters: - cyclop - gocyclo - nlreturn - - stylecheck - paralleltest - ireturn - maintidx - noctx - - gofumpt - exhaustive - protogetter - depguard - mnd - gomoddirectives + - nolintlint + - errcheck + - funcorder + - godoclint + - noinlineerr + - revive + - wsl_v5 + + settings: + govet: + # Don't report about shadowed variables. + shadow: false + gofmt: + # simplify code: gofmt with `-s` option, true by default. + simplify: true + whitespace: + multi-func: true + multi-if: true + tagliatelle: + case: + rules: + json: snake + staticcheck: + checks: [ "-SA1019" ] + gomoddirectives: + replace-allow-list: + # See go.mod for the explanation why these are needed. + - google.golang.org/protobuf -issues: - exclude-rules: - - path: cmd/chantools - linters: - - lll + exclusions: + rules: + - path: cmd/chantools + linters: + - lll + - path: itest + linters: + - dupl + - thelper diff --git a/tools/Dockerfile b/tools/Dockerfile index cc836da..1070998 100644 --- a/tools/Dockerfile +++ b/tools/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23.9-bookworm +FROM golang:1.25.2-bookworm RUN apt-get update && apt-get install -y git ENV GOCACHE=/tmp/build/.cache @@ -11,7 +11,7 @@ RUN cd /tmp \ && mkdir -p /tmp/build/.cache \ && mkdir -p /tmp/build/.modcache \ && cd /tmp/tools \ - && go install -trimpath github.com/golangci/golangci-lint/cmd/golangci-lint \ + && go install -trimpath github.com/golangci/golangci-lint/v2/cmd/golangci-lint \ && chmod -R 777 /tmp/build/ WORKDIR /build diff --git a/tools/go.mod b/tools/go.mod index cebd89e..972caee 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -1,42 +1,52 @@ module github.com/lightninglabs/chantools/tools -go 1.23.9 +go 1.24.0 + +toolchain go1.24.6 require ( github.com/btcsuite/btcd v0.24.2 - github.com/golangci/golangci-lint v1.64.5 + github.com/golangci/golangci-lint/v2 v2.5.0 github.com/ory/go-acc v0.2.8 github.com/rinchsan/gosimports v0.1.5 ) require ( - 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect + 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect 4d63.com/gochecknoglobals v0.2.2 // indirect - github.com/4meepo/tagalign v1.4.1 // indirect - github.com/Abirdcfly/dupword v0.1.3 // indirect - github.com/Antonboom/errname v1.0.0 // indirect - github.com/Antonboom/nilnil v1.0.1 // indirect - github.com/Antonboom/testifylint v1.5.2 // indirect - github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect - github.com/Crocmagnon/fatcontext v0.7.1 // indirect - github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect - github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect - github.com/Masterminds/semver/v3 v3.3.0 // indirect - github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect + codeberg.org/chavacava/garif v0.2.0 // indirect + dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect + dev.gaijin.team/go/golib v0.6.0 // indirect + github.com/4meepo/tagalign v1.4.3 // indirect + github.com/Abirdcfly/dupword v0.1.6 // indirect + github.com/AdminBenni/iota-mixing v1.0.0 // indirect + github.com/AlwxSin/noinlineerr v1.0.5 // indirect + github.com/Antonboom/errname v1.1.1 // indirect + github.com/Antonboom/nilnil v1.1.1 // indirect + github.com/Antonboom/testifylint v1.6.4 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/Djarvur/go-err113 v0.1.1 // indirect + github.com/Masterminds/semver/v3 v3.3.1 // indirect + github.com/MirrexOne/unqueryvet v1.2.1 // indirect + github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect github.com/aead/siphash v1.0.1 // indirect + github.com/alecthomas/chroma/v2 v2.20.0 // indirect github.com/alecthomas/go-check-sumtype v0.3.1 // indirect - github.com/alexkohler/nakedret/v2 v2.0.5 // indirect + github.com/alexkohler/nakedret/v2 v2.0.6 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect + github.com/alfatraining/structtag v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect - github.com/alingse/nilnesserr v0.1.2 // indirect - github.com/ashanbrown/forbidigo v1.6.0 // indirect - github.com/ashanbrown/makezero v1.2.0 // indirect + github.com/alingse/nilnesserr v0.2.0 // indirect + github.com/ashanbrown/forbidigo/v2 v2.1.0 // indirect + github.com/ashanbrown/makezero/v2 v2.0.1 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.3 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v4 v4.5.0 // indirect - github.com/breml/bidichk v0.3.2 // indirect - github.com/breml/errchkjson v0.4.0 // indirect + github.com/bombsimon/wsl/v4 v4.7.0 // indirect + github.com/bombsimon/wsl/v5 v5.2.0 // indirect + github.com/breml/bidichk v0.3.3 // indirect + github.com/breml/errchkjson v0.4.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect github.com/btcsuite/btcd/btcutil v1.1.5 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect @@ -44,31 +54,37 @@ require ( github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/btcsuite/winsvc v1.0.0 // indirect - github.com/butuzov/ireturn v0.3.1 // indirect + github.com/butuzov/ireturn v0.4.0 // indirect github.com/butuzov/mirror v1.3.0 // indirect - github.com/catenacyber/perfsprint v0.8.1 // indirect - github.com/ccojocar/zxcvbn-go v1.0.2 // indirect + github.com/catenacyber/perfsprint v0.9.1 // indirect + github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charithe/durationcheck v0.0.10 // indirect - github.com/chavacava/garif v0.1.0 // indirect - github.com/ckaznocha/intrange v0.3.0 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect + github.com/charmbracelet/lipgloss v1.1.0 // indirect + github.com/charmbracelet/x/ansi v0.8.0 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/ckaznocha/intrange v0.3.1 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect - github.com/daixiang0/gci v0.13.5 // indirect + github.com/daixiang0/gci v0.13.7 // indirect + github.com/dave/dst v0.27.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/decred/dcrd/lru v1.0.0 // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/dgraph-io/ristretto v0.0.2 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/firefart/nonamedreturns v1.0.5 // indirect + github.com/firefart/nonamedreturns v1.0.6 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghostiam/protogetter v0.3.9 // indirect - github.com/go-critic/go-critic v0.12.0 // indirect + github.com/ghostiam/protogetter v0.3.16 // indirect + github.com/go-critic/go-critic v0.13.0 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.2.0 // indirect @@ -76,26 +92,30 @@ require ( github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/godoc-lint/godoc-lint v0.10.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/go-printf-func-name v0.1.0 // indirect + github.com/golangci/asciicheck v0.5.0 // indirect + github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect + github.com/golangci/go-printf-func-name v0.1.1 // indirect github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect - github.com/golangci/misspell v0.6.0 // indirect - github.com/golangci/plugin-module-register v0.1.1 // indirect + github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 // indirect + github.com/golangci/misspell v0.7.0 // indirect + github.com/golangci/nilerr v0.0.0-20250918000102-015671e622fe // indirect + github.com/golangci/plugin-module-register v0.1.2 // indirect github.com/golangci/revgrep v0.8.0 // indirect - github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect + github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gordonklaus/ineffassign v0.1.0 // indirect + github.com/gordonklaus/ineffassign v0.2.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect - github.com/gostaticanalysis/comment v1.4.2 // indirect + github.com/gostaticanalysis/comment v1.5.0 // indirect github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect - github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -103,26 +123,29 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jessevdk/go-flags v1.4.0 // indirect - github.com/jgautheron/goconst v1.7.1 // indirect + github.com/jgautheron/goconst v1.8.2 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect - github.com/jjti/go-spancheck v0.6.4 // indirect + github.com/jjti/go-spancheck v0.6.5 // indirect github.com/jrick/logrotate v1.0.0 // indirect github.com/julz/importas v0.2.0 // indirect github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect - github.com/kisielk/errcheck v1.8.0 // indirect - github.com/kkHAIKE/contextcheck v1.1.5 // indirect + github.com/kisielk/errcheck v1.9.0 // indirect + github.com/kkHAIKE/contextcheck v1.1.6 // indirect github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 // indirect - github.com/kulti/thelper v0.6.3 // indirect - github.com/kunwardeep/paralleltest v1.0.10 // indirect + github.com/kulti/thelper v0.7.1 // indirect + github.com/kunwardeep/paralleltest v1.0.14 // indirect github.com/lasiar/canonicalheader v1.1.2 // indirect - github.com/ldez/exptostd v0.4.1 // indirect - github.com/ldez/gomoddirectives v0.6.1 // indirect - github.com/ldez/grignotin v0.9.0 // indirect - github.com/ldez/tagliatelle v0.7.1 // indirect - github.com/ldez/usetesting v0.4.2 // indirect + github.com/ldez/exptostd v0.4.4 // indirect + github.com/ldez/gomoddirectives v0.7.0 // indirect + github.com/ldez/grignotin v0.10.1 // indirect + github.com/ldez/tagliatelle v0.7.2 // indirect + github.com/ldez/usetesting v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect - github.com/macabu/inamedparam v0.1.3 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/macabu/inamedparam v0.2.0 // indirect github.com/magiconair/properties v1.8.6 // indirect + github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect + github.com/manuelarte/funcorder v0.5.0 // indirect github.com/maratori/testableexamples v1.0.0 // indirect github.com/maratori/testpackage v1.1.1 // indirect github.com/matoous/godox v1.1.0 // indirect @@ -130,90 +153,90 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mgechev/revive v1.6.1 // indirect + github.com/mgechev/revive v1.12.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moricho/tparallel v0.3.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.19.0 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/nunnatsa/ginkgolinter v0.21.0 // indirect github.com/ory/viper v1.7.5 // indirect github.com/pborman/uuid v1.2.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/polyfloyd/go-errorlint v1.7.1 // indirect + github.com/polyfloyd/go-errorlint v1.8.0 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect + github.com/quasilyte/go-ruleguard v0.4.4 // indirect github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/raeperd/recvcheck v0.2.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect - github.com/ryancurrah/gomodguard v1.3.5 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/ryancurrah/gomodguard v1.4.1 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect - github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect - github.com/securego/gosec/v2 v2.22.1 // indirect + github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect + github.com/securego/gosec/v2 v2.22.8 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect - github.com/sivchari/tenv v1.12.1 // indirect - github.com/sonatard/noctx v0.1.0 // indirect + github.com/sonatard/noctx v0.4.0 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect - github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/afero v1.14.0 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.12.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/stretchr/testify v1.10.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/tdakkota/asciicheck v0.4.0 // indirect - github.com/tetafro/godot v1.4.20 // indirect - github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect - github.com/timonwong/loggercheck v0.10.1 // indirect - github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect + github.com/tetafro/godot v1.5.4 // indirect + github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect + github.com/timonwong/loggercheck v0.11.0 // indirect + github.com/tomarrell/wrapcheck/v2 v2.11.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect github.com/uudashr/gocognit v1.2.0 // indirect - github.com/uudashr/iface v1.3.1 // indirect - github.com/xen0n/gosmopolitan v1.2.2 // indirect + github.com/uudashr/iface v1.4.1 // indirect + github.com/xen0n/gosmopolitan v1.3.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.3.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect - go-simpler.org/musttag v0.13.0 // indirect - go-simpler.org/sloglint v0.9.0 // indirect - go.uber.org/atomic v1.7.0 // indirect + go-simpler.org/musttag v0.14.0 // indirect + go-simpler.org/sloglint v0.11.1 // indirect + go.augendre.info/arangolint v0.2.0 // indirect + go.augendre.info/fatcontext v0.8.1 // indirect go.uber.org/automaxprocs v1.6.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.30.0 // indirect - google.golang.org/protobuf v1.36.4 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 // indirect + golang.org/x/mod v0.28.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/tools v0.37.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.6.0 // indirect - mvdan.cc/gofumpt v0.7.0 // indirect - mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect + honnef.co/go/tools v0.6.1 // indirect + mvdan.cc/gofumpt v0.9.1 // indirect + mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect ) diff --git a/tools/go.sum b/tools/go.sum index 36a4fd2..598c07f 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -1,5 +1,5 @@ -4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= -4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= +4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= 4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -34,61 +34,73 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= +codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= +dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= +dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= +dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= +dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/4meepo/tagalign v1.4.1 h1:GYTu2FaPGOGb/xJalcqHeD4il5BiCywyEYZOA55P6J4= -github.com/4meepo/tagalign v1.4.1/go.mod h1:2H9Yu6sZ67hmuraFgfZkNcg5Py9Ch/Om9l2K/2W1qS4= -github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE= -github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw= -github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA= -github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI= -github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs= -github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0= -github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk= -github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8= +github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= +github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= +github.com/Abirdcfly/dupword v0.1.6 h1:qeL6u0442RPRe3mcaLcbaCi2/Y/hOcdtw6DE9odjz9c= +github.com/Abirdcfly/dupword v0.1.6/go.mod h1:s+BFMuL/I4YSiFv29snqyjwzDp4b65W2Kvy+PKzZ6cw= +github.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= +github.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY= +github.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY= +github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= +github.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q= +github.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ= +github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ= +github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= +github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= +github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Crocmagnon/fatcontext v0.7.1 h1:SC/VIbRRZQeQWj/TcQBS6JmrXcfA+BU4OGSVUt54PjM= -github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= +github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/MirrexOne/unqueryvet v1.2.1 h1:M+zdXMq84g+E1YOLa7g7ExN3dWfZQrdDSTCM7gC+m/A= +github.com/MirrexOne/unqueryvet v1.2.1/go.mod h1:IWwCwMQlSWjAIteW0t+28Q5vouyktfujzYznSIWiuOg= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= -github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= +github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= +github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 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.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw= +github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= -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/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg= +github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU= -github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= +github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= +github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= +github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= -github.com/alingse/nilnesserr v0.1.2 h1:Yf8Iwm3z2hUUrP4muWfW83DF4nE3r1xZ26fGWUKCZlo= -github.com/alingse/nilnesserr v0.1.2/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= +github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= +github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= -github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= -github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU= -github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/ashanbrown/forbidigo/v2 v2.1.0 h1:NAxZrWqNUQiDz19FKScQ/xvwzmij6BiOw3S0+QUQ+Hs= +github.com/ashanbrown/forbidigo/v2 v2.1.0/go.mod h1:0zZfdNAuZIL7rSComLGthgc/9/n2FqspBOH90xlCHdA= +github.com/ashanbrown/makezero/v2 v2.0.1 h1:r8GtKetWOgoJ4sLyUx97UTwyt2dO7WkGFHizn/Lo8TY= +github.com/ashanbrown/makezero/v2 v2.0.1/go.mod h1:kKU4IMxmYW1M4fiEHMb2vc5SFoPzXvgbMR9gIp5pjSw= +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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -97,12 +109,14 @@ github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5 github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A= -github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc= -github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs= -github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos= -github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk= -github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8= +github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= +github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= +github.com/bombsimon/wsl/v5 v5.2.0 h1:PyCCwd3Q7abGs3e34IW4jLYlBS+FbsU6iK+Tb3NnDp4= +github.com/bombsimon/wsl/v5 v5.2.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= +github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= +github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= +github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= +github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= @@ -132,14 +146,14 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3 github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY= -github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M= +github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= +github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= -github.com/catenacyber/perfsprint v0.8.1 h1:bGOHuzHe0IkoGeY831RW4aSlt1lPRd3WRAScSWOaV7E= -github.com/catenacyber/perfsprint v0.8.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= -github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= -github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/catenacyber/perfsprint v0.9.1 h1:5LlTp4RwTooQjJCvGEFV6XksZvWE7wCOUvjD2z0vls0= +github.com/catenacyber/perfsprint v0.9.1/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM= +github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= +github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -149,13 +163,21 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= -github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= -github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= +github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY= -github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo= +github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= +github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -164,11 +186,15 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= -github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= -github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= +github.com/daixiang0/gci v0.13.7 h1:+0bG5eK9vlI08J+J/NWGbWPTNiXPG4WhNLJOkSxWITQ= +github.com/daixiang0/gci v0.13.7/go.mod h1:812WVN6JLFY9S6Tv76twqmNqevN0pa3SX3nih0brVzQ= +github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= +github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= +github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= +github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -188,8 +214,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 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.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -200,8 +226,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= -github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= +github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -211,10 +237,10 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghostiam/protogetter v0.3.9 h1:j+zlLLWzqLay22Cz/aYwTHKQ88GE2DQ6GkWSYFOI4lQ= -github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= -github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w= -github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w= +github.com/ghostiam/protogetter v0.3.16 h1:UkrisuJBYLnZW6FcYUNBDJOqY3X22RtoYMlCsiNlFFA= +github.com/ghostiam/protogetter v0.3.16/go.mod h1:4SRRIv6PcjkIMpUkRUsP4TsUTqO/N3Fmvwivuc/sCHA= +github.com/go-critic/go-critic v0.13.0 h1:kJzM7wzltQasSUXtYyTl6UaPVySO6GkaR1thFnJ6afY= +github.com/go-critic/go-critic v0.13.0/go.mod h1:M/YeuJ3vOCQDnP2SU+ZhjgRzwzcBW87JqLpMJLrZDLI= 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-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -224,8 +250,8 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -250,12 +276,14 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= -github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +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/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= 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/godoc-lint/godoc-lint v0.10.0 h1:OcyrziBi18sQSEpib6NesVHEJ/Xcng97NunePBA48g4= +github.com/godoc-lint/godoc-lint v0.10.0/go.mod h1:KleLcHu/CGSvkjUH2RvZyoK1MBC7pDQg4NxMYLcBBsw= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -292,22 +320,30 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU= -github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= +github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= +github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= +github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= +github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= +github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= +github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint v1.64.5 h1:5omC86XFBKXZgCrVdUWU+WNHKd+CWCxNx717KXnzKZY= -github.com/golangci/golangci-lint v1.64.5/go.mod h1:WZnwq8TF0z61h3jLQ7Sk5trcP7b3kUFxLD6l1ivtdvU= -github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= -github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= -github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= -github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= +github.com/golangci/golangci-lint/v2 v2.5.0 h1:BDRg4ASm4J1y/DSRY6zwJ5tr5Yy8ZqbZ79XrCeFxaQo= +github.com/golangci/golangci-lint/v2 v2.5.0/go.mod h1:IJtWJBZkLbx7AVrIUzLd8Oi3ADtwaNpWbR3wthVWHcc= +github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 h1:AkK+w9FZBXlU/xUmBtSJN1+tAI4FIvy5WtnUnY8e4p8= +github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95/go.mod h1:k9mmcyWKSTMcPPvQUCfRWWQ9VHJ1U9Dc0R7kaXAgtnQ= +github.com/golangci/misspell v0.7.0 h1:4GOHr/T1lTW0hhR4tgaaV1WS/lJ+ncvYCoFKmqJsj0c= +github.com/golangci/misspell v0.7.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= +github.com/golangci/nilerr v0.0.0-20250918000102-015671e622fe h1:F1pK9tBy41i7eesBFkSNMldwtiAaWiU+3fT/24sTnNI= +github.com/golangci/nilerr v0.0.0-20250918000102-015671e622fe/go.mod h1:CtTxAluxD2ng9aIT9bPrVoMuISFWCD+SaxtvYtdWA2k= +github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= +github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= 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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -320,10 +356,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -334,8 +369,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18= +github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -344,19 +379,17 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= -github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= +github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= -github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= -github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8= +github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk= github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= -github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= -github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8= github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= @@ -386,12 +419,12 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= -github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4= +github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc= -github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk= +github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= +github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= @@ -410,11 +443,11 @@ github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx github.com/karamaru-alpha/copyloopvar v1.2.1 h1:wmZaZYIjnJ0b5UoKDjUHrikcV0zuPyyxI4SVplLd2CI= github.com/karamaru-alpha/copyloopvar v1.2.1/go.mod h1:nFmMlFNlClC2BPvNaHMdkirmTJxVCY0lhxBtlfOypMM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg= -github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= +github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M= +github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= -github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= +github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= +github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -428,30 +461,36 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= -github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= -github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98= +github.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs= +github.com/kunwardeep/paralleltest v1.0.14 h1:wAkMoMeGX/kGfhQBPODT/BL8XhK23ol/nuQ3SwFaUw8= +github.com/kunwardeep/paralleltest v1.0.14/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= -github.com/ldez/exptostd v0.4.1 h1:DIollgQ3LWZMp3HJbSXsdE2giJxMfjyHj3eX4oiD6JU= -github.com/ldez/exptostd v0.4.1/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ= -github.com/ldez/gomoddirectives v0.6.1 h1:Z+PxGAY+217f/bSGjNZr/b2KTXcyYLgiWI6geMBN2Qc= -github.com/ldez/gomoddirectives v0.6.1/go.mod h1:cVBiu3AHR9V31em9u2kwfMKD43ayN5/XDgr+cdaFaKs= -github.com/ldez/grignotin v0.9.0 h1:MgOEmjZIVNn6p5wPaGp/0OKWyvq42KnzAt/DAb8O4Ow= -github.com/ldez/grignotin v0.9.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk= -github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk= -github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I= -github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA= -github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ= +github.com/ldez/exptostd v0.4.4 h1:58AtQjnLcT/tI5W/1KU7xE/O7zW9RAWB6c/ScQAnfus= +github.com/ldez/exptostd v0.4.4/go.mod h1:QfdzPw6oHjFVdNV7ILoPu5sw3OZ3OG1JS0I5JN3J4Js= +github.com/ldez/gomoddirectives v0.7.0 h1:EOx8Dd56BZYSez11LVgdj025lKwlP0/E5OLSl9HDwsY= +github.com/ldez/gomoddirectives v0.7.0/go.mod h1:wR4v8MN9J8kcwvrkzrx6sC9xe9Cp68gWYCsda5xvyGc= +github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= +github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= +github.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk= +github.com/ldez/tagliatelle v0.7.2/go.mod h1:PtGgm163ZplJfZMZ2sf5nhUT170rSuPgBimoyYtdaSI= +github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc= +github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= -github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= +github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= +github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM= +github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= +github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= @@ -464,13 +503,12 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgechev/revive v1.6.1 h1:ncK0ZCMWtb8GXwVAmk+IeWF2ULIDsvRxSRfg5sTwQ2w= -github.com/mgechev/revive v1.6.1/go.mod h1:/2tfHWVO8UQi/hqJsIYNEKELi+DJy/e+PQpLgTB1v88= +github.com/mgechev/revive v1.12.0 h1:Q+/kkbbwerrVYPv9d9efaPGmAO/NsxwW/nE6ahpQaCU= +github.com/mgechev/revive v1.12.0/go.mod h1:VXsY2LsTigk8XU9BpZauVLjVrhICMOV3k1lpB3CXrp8= 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/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -484,6 +522,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= @@ -492,26 +532,24 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.19.0 h1:CnHRFAeBS3LdLI9h+Jidbcc5KH71GKOmaBZQk8Srnto= -github.com/nunnatsa/ginkgolinter v0.19.0/go.mod h1:jkQ3naZDmxaZMXPWaS9rblH+i+GWXQCaS/JFIWcOH2s= +github.com/nunnatsa/ginkgolinter v0.21.0 h1:IYwuX+ajy3G1MezlMLB1BENRtFj16+Evyi4uki1NOOQ= +github.com/nunnatsa/ginkgolinter v0.21.0/go.mod h1:QlzY9UP9zaqu58FjYxhp9bnjuwXwG1bfW5rid9ChNMw= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 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.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= +github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= github.com/ory/go-acc v0.2.8 h1:rOHHAPQjf0u7eHFGWpiXK+gIu/e0GRSJNr9pDukdNC4= github.com/ory/go-acc v0.2.8/go.mod h1:iCRZUdGb/7nqvSn8xWZkhfVrtXRZ9Wru2E5rabCjFPI= github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE= @@ -529,16 +567,15 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= 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.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.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/polyfloyd/go-errorlint v1.7.1 h1:RyLVXIbosq1gBdk/pChWA8zWYLsq9UEw7a1L5TVMCnA= -github.com/polyfloyd/go-errorlint v1.7.1/go.mod h1:aXjNb1x2TNhoLsk26iv1yl7a+zTnXPhwEMtEXukiLR8= +github.com/polyfloyd/go-errorlint v1.8.0 h1:DL4RestQqRLr8U4LygLw8g2DX6RN1eBJOpa2mzsrl1Q= +github.com/polyfloyd/go-errorlint v1.8.0/go.mod h1:G2W0Q5roxbLCt0ZQbdoxQxXktTjwNyDbEaj3n7jvl4s= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -568,8 +605,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= -github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= +github.com/quasilyte/go-ruleguard v0.4.4 h1:53DncefIeLX3qEpjzlS1lyUmQoUEeOWPFWqaTJq9eAQ= +github.com/quasilyte/go-ruleguard v0.4.4/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= @@ -587,24 +624,26 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= -github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= +github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= +github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ= -github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= -github.com/securego/gosec/v2 v2.22.1 h1:IcBt3TpI5Y9VN1YlwjSpM2cHu0i3Iw52QM+PQeg7jN8= -github.com/securego/gosec/v2 v2.22.1/go.mod h1:4bb95X4Jz7VSEPdVjC0hD7C/yR6kdeUBvCPOy9gDQ0g= +github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= +github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= +github.com/securego/gosec/v2 v2.22.8 h1:3NMpmfXO8wAVFZPNsd3EscOTa32Jyo6FLLlW53bexMI= +github.com/securego/gosec/v2 v2.22.8/go.mod h1:ZAw8K2ikuH9qDlfdV87JmNghnVfKB1XC7+TVzk6Utto= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -615,35 +654,34 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY= -github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM= -github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c= +github.com/sonatard/noctx v0.4.0 h1:7MC/5Gg4SQ4lhLYR6mvOP6mQVSxCrdyiExo7atBs27o= +github.com/sonatard/noctx v0.4.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= @@ -653,8 +691,6 @@ github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8B github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= 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= @@ -662,31 +698,26 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tdakkota/asciicheck v0.4.0 h1:VZ13Itw4k1i7d+dpDSNS8Op645XgGHpkCEh/WHicgWw= -github.com/tdakkota/asciicheck v0.4.0/go.mod h1:0k7M3rCfRXb0Z6bwgvkEIMleKH3kXNz9UqJ9Xuqopr8= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.20 h1:z/p8Ek55UdNvzt4TFn2zx2KscpW4rWqcnUrdmvWJj7E= -github.com/tetafro/godot v1.4.20/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= -github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg= -github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= -github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg= -github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +github.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg= +github.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= +github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= +github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg= -github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tomarrell/wrapcheck/v2 v2.11.0 h1:BJSt36snX9+4WTIXeJ7nvHBQBcm1h2SjQMSlmQ6aFSU= +github.com/tomarrell/wrapcheck/v2 v2.11.0/go.mod h1:wFL9pDWDAbXhhPZZt+nG8Fu+h29TtnZ2MW6Lx4BRXIU= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -696,11 +727,13 @@ github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSW github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA= github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= -github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U= -github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= -github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= -github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= +github.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU= +github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= +github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= +github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= @@ -719,10 +752,14 @@ gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= -go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE= -go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM= -go-simpler.org/sloglint v0.9.0 h1:/40NQtjRx9txvsB/RN022KsUJU+zaaSb/9q9BSefSrE= -go-simpler.org/sloglint v0.9.0/go.mod h1:G/OrAF6uxj48sHahCzrbarVMptL2kjWTaUeC8+fOGww= +go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= +go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= +go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= +go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= +go.augendre.info/arangolint v0.2.0 h1:2NP/XudpPmfBhQKX4rMk+zDYIj//qbt4hfZmSSTcpj8= +go.augendre.info/arangolint v0.2.0/go.mod h1:Vx4KSJwu48tkE+8uxuf0cbBnAPgnt8O1KWiT7bljq7w= +go.augendre.info/fatcontext v0.8.1 h1:/T4+cCjpL9g71gJpcFAgVo/K5VFpqlN+NPU7QXxD5+A= +go.augendre.info/fatcontext v0.8.1/go.mod h1:r3Qz4ZOzex66wfyyj5VZ1xUcl81vzvHQ6/GWzzlMEwA= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -730,18 +767,16 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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= @@ -753,8 +788,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= 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= @@ -769,8 +804,8 @@ golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWB golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rPv1pNOQtl1I8knsO4S9trOxNMOLVP4= -golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 h1:Yl4H5w2RV7L/dvSHp2GerziT5K2CORgFINPaMFxWGWw= +golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= 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= @@ -796,13 +831,11 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -843,14 +876,12 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.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.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= 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= @@ -872,8 +903,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.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= @@ -930,19 +961,16 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc 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.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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 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.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= @@ -953,13 +981,11 @@ 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.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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= 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.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -997,7 +1023,6 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1007,23 +1032,22 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= 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= @@ -1104,8 +1128,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= -google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= @@ -1140,12 +1164,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.6.0 h1:TAODvD3knlq75WCp2nyGJtT4LeRV/o7NN9nYPeVJXf8= -honnef.co/go/tools v0.6.0/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= -mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= -mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= -mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= +honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= +honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= +mvdan.cc/gofumpt v0.9.1 h1:p5YT2NfFWsYyTieYgwcQ8aKV3xRvFH4uuN/zB2gBbMQ= +mvdan.cc/gofumpt v0.9.1/go.mod h1:3xYtNemnKiXaTh6R4VtlqDATFwBbdXI8lJvH/4qk7mw= +mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8= +mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5ginj6dA2oLE7YNlta9qhBNNdCaLE= 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= diff --git a/tools/tools.go b/tools/tools.go index 3d7dae0..c8b45e1 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -9,7 +9,7 @@ package lnd // dependencies here and pin the version in go.mod. import ( _ "github.com/btcsuite/btcd" - _ "github.com/golangci/golangci-lint/cmd/golangci-lint" + _ "github.com/golangci/golangci-lint/v2/cmd/golangci-lint" _ "github.com/ory/go-acc" _ "github.com/rinchsan/gosimports/cmd/gosimports" )