From 4a7faeaff38e1a5036a77dcbebd14d09dcf3cd5d Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 13:05:41 +0100 Subject: [PATCH 1/8] nixos/invidious: remove obsolete database maintenance service See the note on https://docs.invidious.io/db-maintenance/. Manual maintenance is no longer required. --- nixos/modules/services/web-apps/invidious.nix | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix index cfba3c8a29708..9294e33dfea36 100644 --- a/nixos/modules/services/web-apps/invidious.nix +++ b/nixos/modules/services/web-apps/invidious.nix @@ -133,22 +133,6 @@ let ''; }; - systemd.services.invidious-db-clean = { - description = "Invidious database cleanup"; - documentation = [ "https://docs.invidious.io/Database-Information-and-Maintenance.md" ]; - startAt = lib.mkDefault "weekly"; - path = [ config.services.postgresql.package ]; - after = [ "postgresql.service" ]; - script = '' - psql ${cfg.settings.db.dbname} ${cfg.settings.db.user} -c "DELETE FROM nonces * WHERE expire < current_timestamp" - psql ${cfg.settings.db.dbname} ${cfg.settings.db.user} -c "TRUNCATE TABLE videos" - ''; - serviceConfig = { - DynamicUser = true; - User = "invidious"; - }; - }; - systemd.services.invidious = { requires = [ "postgresql.service" ]; after = [ "postgresql.service" ]; From 460e34b273592fb6b4fa7e57d65c02c82895d03a Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 14:23:24 +0100 Subject: [PATCH 2/8] nixos/tests/invidious: move postgres-tcp into second machine and fix tests Using PostgreSQL 15 without the init script fails due to https://github.com/NixOS/nixpkgs/issues/216989. --- nixos/tests/invidious.nix | 84 ++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/nixos/tests/invidious.nix b/nixos/tests/invidious.nix index 701e8e5e7a3fc..5be7270bc1dc3 100644 --- a/nixos/tests/invidious.nix +++ b/nixos/tests/invidious.nix @@ -5,48 +5,51 @@ import ./make-test-python.nix ({ pkgs, ... }: { maintainers = [ sbruder ]; }; - nodes.machine = { config, lib, pkgs, ... }: { - services.invidious = { - enable = true; + nodes = { + postgres-tcp = { config, pkgs, ... }: { + services.postgresql = { + enable = true; + initialScript = pkgs.writeText "init-postgres-with-password" '' + CREATE USER kemal WITH PASSWORD 'correct horse battery staple'; + CREATE DATABASE invidious WITH OWNER kemal; + ''; + enableTCPIP = true; + authentication = '' + host invidious kemal samenet scram-sha-256 + ''; + }; + networking.firewall.allowedTCPPorts = [ config.services.postgresql.port ]; }; - - specialisation = { - nginx.configuration = { - services.invidious = { - nginx.enable = true; - domain = "invidious.example.com"; - }; - services.nginx.virtualHosts."invidious.example.com" = { - forceSSL = false; - enableACME = false; - }; - networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; + machine = { config, lib, pkgs, ... }: { + services.invidious = { + enable = true; }; - postgres-tcp.configuration = { - services.invidious = { - database = { - createLocally = false; - host = "127.0.0.1"; - passwordFile = toString (pkgs.writeText "database-password" "correct horse battery staple"); + services.postgresql.initialScript = pkgs.writeText "init-postgres-with-password" '' + CREATE USER kemal; + CREATE DATABASE invidious WITH OWNER kemal; + ''; + + specialisation = { + nginx.configuration = { + services.invidious = { + nginx.enable = true; + domain = "invidious.example.com"; }; + services.nginx.virtualHosts."invidious.example.com" = { + forceSSL = false; + enableACME = false; + }; + networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; }; - # Normally not needed because when connecting to postgres over TCP/IP - # the database is most likely on another host. - systemd.services.invidious = { - after = [ "postgresql.service" ]; - requires = [ "postgresql.service" ]; - }; - services.postgresql = - let - inherit (config.services.invidious.settings.db) dbname user; - in - { - enable = true; - initialScript = pkgs.writeText "init-postgres-with-password" '' - CREATE USER kemal WITH PASSWORD 'correct horse battery staple'; - CREATE DATABASE invidious OWNER kemal; - ''; + postgres-tcp.configuration = { + services.invidious = { + database = { + createLocally = false; + host = "postgres-tcp"; + passwordFile = toString (pkgs.writeText "database-password" "correct horse battery staple"); + }; }; + }; }; }; }; @@ -63,6 +66,9 @@ import ./make-test-python.nix ({ pkgs, ... }: { url = "http://localhost:${toString nodes.machine.config.services.invidious.port}" port = ${toString nodes.machine.config.services.invidious.port} + # start postgres vm now + postgres_tcp.start() + machine.wait_for_open_port(port) curl_assert_status_code(f"{url}/search", 200) @@ -70,9 +76,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { machine.wait_for_open_port(80) curl_assert_status_code("http://invidious.example.com/search", 200) - # Remove the state so the `initialScript` gets run - machine.succeed("systemctl stop postgresql") - machine.succeed("rm -r /var/lib/postgresql") + postgres_tcp.wait_for_unit("postgresql.service") activate_specialisation("postgres-tcp") machine.wait_for_open_port(port) curl_assert_status_code(f"{url}/search", 200) From 45bd4b1159bb29d4a60c1d811f24b3487acbcab6 Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 13:40:46 +0100 Subject: [PATCH 3/8] nixos/invidious: add option to run more invidious instances --- nixos/modules/services/web-apps/invidious.nix | 215 +++++++++++------- 1 file changed, 133 insertions(+), 82 deletions(-) diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix index 9294e33dfea36..b281345db197a 100644 --- a/nixos/modules/services/web-apps/invidious.nix +++ b/nixos/modules/services/web-apps/invidious.nix @@ -10,77 +10,106 @@ let generatedHmacKeyFile = "/var/lib/invidious/hmac_key"; generateHmac = cfg.hmacKeyFile == null; - serviceConfig = { - systemd.services.invidious = { - description = "Invidious (An alternative YouTube front-end)"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - - preStart = lib.optionalString generateHmac '' - if [[ ! -e "${generatedHmacKeyFile}" ]]; then - ${pkgs.pwgen}/bin/pwgen 20 1 > "${generatedHmacKeyFile}" - chmod 0600 "${generatedHmacKeyFile}" - fi - ''; - - script = '' - configParts=() - '' - # autogenerated hmac_key - + lib.optionalString generateHmac '' - configParts+=("$(${pkgs.jq}/bin/jq -R '{"hmac_key":.}' <"${generatedHmacKeyFile}")") - '' - # generated settings file - + '' - configParts+=("$(< ${lib.escapeShellArg settingsFile})") - '' - # optional database password file - + lib.optionalString (cfg.database.host != null) '' - configParts+=("$(${pkgs.jq}/bin/jq -R '{"db":{"password":.}}' ${lib.escapeShellArg cfg.database.passwordFile})") - '' - # optional extra settings file - + lib.optionalString (cfg.extraSettingsFile != null) '' - configParts+=("$(< ${lib.escapeShellArg cfg.extraSettingsFile})") - '' - # explicitly specified hmac key file - + lib.optionalString (cfg.hmacKeyFile != null) '' - configParts+=("$(< ${lib.escapeShellArg cfg.hmacKeyFile})") - '' - # merge all parts into a single configuration with later elements overriding previous elements - + '' - export INVIDIOUS_CONFIG="$(${pkgs.jq}/bin/jq -s 'reduce .[] as $item ({}; . * $item)' <<<"''${configParts[*]}")" - exec ${cfg.package}/bin/invidious - ''; - - serviceConfig = { - RestartSec = "2s"; - DynamicUser = true; - StateDirectory = "invidious"; - StateDirectoryMode = "0750"; - - CapabilityBoundingSet = ""; - PrivateDevices = true; - PrivateUsers = true; - ProtectHome = true; - ProtectKernelLogs = true; - ProtectProc = "invisible"; - RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; - RestrictNamespaces = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; - - # Because of various issues Invidious must be restarted often, at least once a day, ideally - # every hour. - # This option enables the automatic restarting of the Invidious instance. - Restart = lib.mkDefault "always"; - RuntimeMaxSec = lib.mkDefault "1h"; - }; + commonInvidousServiceConfig = { + description = "Invidious (An alternative YouTube front-end)"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service"; + requires = lib.optional cfg.database.createLocally "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + RestartSec = "2s"; + DynamicUser = true; + User = lib.mkIf (cfg.database.createLocally || cfg.serviceScale > 1) "invidious"; + StateDirectory = "invidious"; + StateDirectoryMode = "0750"; + + CapabilityBoundingSet = ""; + PrivateDevices = true; + PrivateUsers = true; + ProtectHome = true; + ProtectKernelLogs = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; + + # Because of various issues Invidious must be restarted often, at least once a day, ideally + # every hour. + # This option enables the automatic restarting of the Invidious instance. + # To ensure multiple instances of Invidious are not restarted at the exact same time, a + # randomized extra offset of up to 5 minutes is added. + Restart = lib.mkDefault "always"; + RuntimeMaxSec = lib.mkDefault "1h"; + RuntimeRandomizedExtraSec = lib.mkDefault "5min"; }; + }; + mkInvidiousService = scaleIndex: + lib.foldl' lib.recursiveUpdate commonInvidousServiceConfig [ + # only generate the hmac file in the first service + (lib.optionalAttrs (scaleIndex == 0) { + preStart = lib.optionalString generateHmac '' + if [[ ! -e "${generatedHmacKeyFile}" ]]; then + ${pkgs.pwgen}/bin/pwgen 20 1 > "${generatedHmacKeyFile}" + chmod 0600 "${generatedHmacKeyFile}" + fi + ''; + }) + # configure the secondary services to run after the first service + (lib.optionalAttrs (scaleIndex > 0) { + after = commonInvidousServiceConfig.after ++ [ "invidious.service" ]; + wants = commonInvidousServiceConfig.wants ++ [ "invidious.service" ]; + }) + { + script = '' + configParts=() + '' + # autogenerated hmac_key + + lib.optionalString generateHmac '' + configParts+=("$(${pkgs.jq}/bin/jq -R '{"hmac_key":.}' <"${generatedHmacKeyFile}")") + '' + # generated settings file + + '' + configParts+=("$(< ${lib.escapeShellArg settingsFile})") + '' + # optional database password file + + lib.optionalString (cfg.database.host != null) '' + configParts+=("$(${pkgs.jq}/bin/jq -R '{"db":{"password":.}}' ${lib.escapeShellArg cfg.database.passwordFile})") + '' + # optional extra settings file + + lib.optionalString (cfg.extraSettingsFile != null) '' + configParts+=("$(< ${lib.escapeShellArg cfg.extraSettingsFile})") + '' + # explicitly specified hmac key file + + lib.optionalString (cfg.hmacKeyFile != null) '' + configParts+=("$(< ${lib.escapeShellArg cfg.hmacKeyFile})") + '' + # configure threads for secondary instances + + lib.optionalString (scaleIndex > 0) '' + configParts+=('{"channel_threads":0, "feed_threads":0}') + '' + # configure different ports for the instances + + '' + configParts+=('{"port":${toString (cfg.port + scaleIndex)}}') + '' + # merge all parts into a single configuration with later elements overriding previous elements + + '' + export INVIDIOUS_CONFIG="$(${pkgs.jq}/bin/jq -s 'reduce .[] as $item ({}; . * $item)' <<<"''${configParts[*]}")" + exec ${cfg.package}/bin/invidious + ''; + } + ]; - services.invidious.settings = { - inherit (cfg) port; + serviceConfig = { + systemd.services = builtins.listToAttrs (builtins.genList + (scaleIndex: { + name = "invidious" + lib.optionalString (scaleIndex > 0) "-${builtins.toString scaleIndex}"; + value = mkInvidiousService scaleIndex; + }) + cfg.serviceScale); + services.invidious.settings = { # Automatically initialises and migrates the database if necessary check_tables = true; @@ -98,10 +127,16 @@ let inherit (cfg) domain; }); - assertions = [{ - assertion = cfg.database.host != null -> cfg.database.passwordFile != null; - message = "If database host isn't null, database password needs to be set"; - }]; + assertions = [ + { + assertion = cfg.database.host != null -> cfg.database.passwordFile != null; + message = "If database host isn't null, database password needs to be set"; + } + { + assertion = cfg.serviceScale >= 1; + message = "Service can't be scaled below one instance"; + } + ]; }; # Settings necessary for running with an automatically managed local database @@ -132,15 +167,6 @@ let local ${cfg.settings.db.dbname} ${cfg.settings.db.user} peer map=invidious ''; }; - - systemd.services.invidious = { - requires = [ "postgresql.service" ]; - after = [ "postgresql.service" ]; - - serviceConfig = { - User = "invidious"; - }; - }; }; nginxConfig = lib.mkIf cfg.nginx.enable { @@ -152,11 +178,22 @@ let services.nginx = { enable = true; virtualHosts.${cfg.domain} = { - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; + locations."/".proxyPass = + if cfg.serviceScale == 1 then + "http://127.0.0.1:${toString cfg.port}" + else "http://upstream-invidious"; enableACME = lib.mkDefault true; forceSSL = lib.mkDefault true; }; + upstreams = lib.mkIf (cfg.serviceScale > 1) { + "upstream-invidious".servers = builtins.listToAttrs (builtins.genList + (scaleIndex: { + name = "127.0.0.1:${toString (cfg.port + scaleIndex)}"; + value = { }; + }) + cfg.serviceScale); + }; }; assertions = [{ @@ -204,6 +241,20 @@ in ''; }; + serviceScale = lib.mkOption { + type = types.int; + default = 1; + description = lib.mdDoc '' + How many invidious instances to run. + + See https://docs.invidious.io/improve-public-instance/#2-multiple-invidious-processes for more details + on how this is intended to work. All instances beyond the first one have the options `channel_threads` + and `feed_threads` set to 0 to avoid conflicts with multiple instances refreshing subscriptions. Instances + will be configured to bind to consecutive ports starting with {option}`services.invidious.port` for the + first instance. + ''; + }; + # This needs to be outside of settings to avoid infinite recursion # (determining if nginx should be enabled and therefore the settings # modified). From 65e8f8a69790c61ff862ccc6de977644566f8456 Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 14:34:42 +0100 Subject: [PATCH 4/8] nixos/tests/invidious: add test for scaled invidious --- nixos/tests/invidious.nix | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/nixos/tests/invidious.nix b/nixos/tests/invidious.nix index 5be7270bc1dc3..8c2342f66ea68 100644 --- a/nixos/tests/invidious.nix +++ b/nixos/tests/invidious.nix @@ -41,6 +41,18 @@ import ./make-test-python.nix ({ pkgs, ... }: { }; networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; }; + nginx-scale.configuration = { + services.invidious = { + nginx.enable = true; + domain = "invidious.example.com"; + serviceScale = 3; + }; + services.nginx.virtualHosts."invidious.example.com" = { + forceSSL = false; + enableACME = false; + }; + networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; + }; postgres-tcp.configuration = { services.invidious = { database = { @@ -76,6 +88,16 @@ import ./make-test-python.nix ({ pkgs, ... }: { machine.wait_for_open_port(80) curl_assert_status_code("http://invidious.example.com/search", 200) + activate_specialisation("nginx-scale") + machine.wait_for_open_port(80) + # this depends on nginx round-robin behaviour for the upstream servers + curl_assert_status_code("http://invidious.example.com/search", 200) + curl_assert_status_code("http://invidious.example.com/search", 200) + curl_assert_status_code("http://invidious.example.com/search", 200) + machine.succeed("journalctl -eu invidious.service | grep -o '200 GET /search'") + machine.succeed("journalctl -eu invidious-1.service | grep -o '200 GET /search'") + machine.succeed("journalctl -eu invidious-2.service | grep -o '200 GET /search'") + postgres_tcp.wait_for_unit("postgresql.service") activate_specialisation("postgres-tcp") machine.wait_for_open_port(port) From d41706bae27673db9e307e6165eb47d75ee74ce6 Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 14:53:23 +0100 Subject: [PATCH 5/8] nixos/invidious: bind to 127.0.0.1 instead of 0.0.0.0 if nginx is used --- nixos/modules/services/web-apps/invidious.nix | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix index b281345db197a..a91132c9b85c6 100644 --- a/nixos/modules/services/web-apps/invidious.nix +++ b/nixos/modules/services/web-apps/invidious.nix @@ -123,6 +123,8 @@ let # Not needed because peer authentication is enabled password = lib.mkIf (cfg.database.host == null) ""; }; + + host_binding = cfg.address; } // (lib.optionalAttrs (cfg.domain != null) { inherit (cfg) domain; }); @@ -175,12 +177,15 @@ let external_port = 80; }; - services.nginx = { + services.nginx = let + ip = if cfg.address == "0.0.0.0" then "127.0.0.1" else cfg.address; + in + { enable = true; virtualHosts.${cfg.domain} = { locations."/".proxyPass = if cfg.serviceScale == 1 then - "http://127.0.0.1:${toString cfg.port}" + "http://${ip}:${toString cfg.port}" else "http://upstream-invidious"; enableACME = lib.mkDefault true; @@ -189,7 +194,7 @@ let upstreams = lib.mkIf (cfg.serviceScale > 1) { "upstream-invidious".servers = builtins.listToAttrs (builtins.genList (scaleIndex: { - name = "127.0.0.1:${toString (cfg.port + scaleIndex)}"; + name = "${ip}:${toString (cfg.port + scaleIndex)}"; value = { }; }) cfg.serviceScale); @@ -268,6 +273,16 @@ in ''; }; + address = lib.mkOption { + type = types.str; + # default from https://github.com/iv-org/invidious/blob/master/config/config.example.yml + default = if cfg.nginx.enable then "127.0.0.1" else "0.0.0.0"; + defaultText = lib.literalExpression ''if config.services.invidious.nginx.enable then "127.0.0.1" else "0.0.0.0"''; + description = lib.mdDoc '' + The IP address Invidious should bind to. + ''; + }; + port = lib.mkOption { type = types.port; # Default from https://docs.invidious.io/Configuration.md From 5e320dba222b5bd67f80289818ec7f361b04b112 Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 16:59:38 +0100 Subject: [PATCH 6/8] http3-ytproxy: init at unstable-2022-07-03 --- .../ht/http3-ytproxy/dependencies.patch | 378 ++++++++++++++++++ pkgs/by-name/ht/http3-ytproxy/package.nix | 36 ++ 2 files changed, 414 insertions(+) create mode 100644 pkgs/by-name/ht/http3-ytproxy/dependencies.patch create mode 100644 pkgs/by-name/ht/http3-ytproxy/package.nix diff --git a/pkgs/by-name/ht/http3-ytproxy/dependencies.patch b/pkgs/by-name/ht/http3-ytproxy/dependencies.patch new file mode 100644 index 0000000000000..1394156b4d5b2 --- /dev/null +++ b/pkgs/by-name/ht/http3-ytproxy/dependencies.patch @@ -0,0 +1,378 @@ +diff --git a/go.mod b/go.mod +index 2343724..a734d33 100644 +--- a/go.mod ++++ b/go.mod +@@ -1,8 +1,24 @@ + module github.com/FireMasterK/http3-ytproxy/v2 + +-go 1.16 ++go 1.18 + + require ( + github.com/kolesa-team/go-webp v1.0.1 +- github.com/lucas-clemente/quic-go v0.25.0 ++ github.com/quic-go/quic-go v0.40.0 ++) ++ ++require ( ++ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect ++ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect ++ github.com/onsi/ginkgo/v2 v2.9.5 // indirect ++ github.com/quic-go/qpack v0.4.0 // indirect ++ github.com/quic-go/qtls-go1-20 v0.4.1 // indirect ++ go.uber.org/mock v0.3.0 // indirect ++ golang.org/x/crypto v0.4.0 // indirect ++ golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect ++ golang.org/x/mod v0.11.0 // indirect ++ golang.org/x/net v0.10.0 // indirect ++ golang.org/x/sys v0.8.0 // indirect ++ golang.org/x/text v0.9.0 // indirect ++ golang.org/x/tools v0.9.1 // indirect + ) +diff --git a/go.sum b/go.sum +index 378f95e..214f9ff 100644 +--- a/go.sum ++++ b/go.sum +@@ -1,289 +1,56 @@ +-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +-cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +-cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +-dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +-dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +-dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +-dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +-git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +-github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +-github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +-github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +-github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +-github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= ++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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= + github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= + github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +-github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +-github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +-github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +-github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +-github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +-github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= ++github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= ++github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= ++github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= ++github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= ++github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= ++github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= ++github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= ++github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= + github.com/kolesa-team/go-webp v1.0.1 h1:Btojkbzr6tt10zJ40xlbSfJeHFiNn0aR7H03QUqmMoI= + github.com/kolesa-team/go-webp v1.0.1/go.mod h1:oMvdivD6K+Q5qIIkVC2w4k2ZUnI1H+MyP7inwgWq9aA= +-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +-github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +-github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc= +-github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +-github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +-github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs= +-github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= +-github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +-github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco= +-github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +-github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= +-github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= +-github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM= +-github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +-github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +-github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +-github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +-github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +-github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +-github.com/onsi/ginkgo v1.6.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/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +-github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +-github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +-github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +-github.com/onsi/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.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +-github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= ++github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= ++github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= ++github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= + 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/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +-github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +-github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +-github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +-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/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +-github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +-github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +-github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +-github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +-github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +-github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +-github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +-github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +-github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +-github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +-github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +-github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +-github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +-github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +-github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +-github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +-github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= ++github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= ++github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= ++github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= ++github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= ++github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw= ++github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= + github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= ++github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= + github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= + github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +-github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +-github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +-github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +-go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +-go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +-golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +-golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +-golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= ++go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= ++go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= ++golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= ++golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= ++golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= ++golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= + golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= + golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +-golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= +-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +-golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +-golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +-golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +-golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +-golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +-golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= ++golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= ++golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= ++golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= ++golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= ++golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= ++golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= ++golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= + golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= ++golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= ++golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= + golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +-golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +-golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +-golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= +-golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +-google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +-google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +-google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +-google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +-google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +-google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +-google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +-google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= ++golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= ++golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= ++google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +-grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +-sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +-sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= ++gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +diff --git a/main.go b/main.go +index 8c64018..2290108 100644 +--- a/main.go ++++ b/main.go +@@ -16,7 +16,7 @@ import ( + + "github.com/kolesa-team/go-webp/encoder" + "github.com/kolesa-team/go-webp/webp" +- "github.com/lucas-clemente/quic-go/http3" ++ "github.com/quic-go/quic-go/http3" + ) + + // http/3 client diff --git a/pkgs/by-name/ht/http3-ytproxy/package.nix b/pkgs/by-name/ht/http3-ytproxy/package.nix new file mode 100644 index 0000000000000..04e6965012937 --- /dev/null +++ b/pkgs/by-name/ht/http3-ytproxy/package.nix @@ -0,0 +1,36 @@ +{ lib +, fetchFromGitHub +, buildGoModule +, libwebp +}: +buildGoModule rec { + pname = "http3-ytproxy"; + version = "unstable-2022-07-03"; + + src = fetchFromGitHub { + owner = "TeamPiped"; + repo = pname; + rev = "4059da180bb9d7b0de10c1a041bd0e134f1b6408"; + hash = "sha256-ilIOkZ9lcuSigh/mMU7IGpWlFMFb2/Y11ri3659S8+I="; + }; + + patches = [ + # this patch was created by updating the quic-go dependency, bumping the go version + # and running `go mod tidy` + ./dependencies.patch + ]; + + vendorHash = "sha256-17y+kxlLSqCFoxinNNKzg7IqGpbiv0IBsUuC9EC8xnk="; + + buildInputs = [ libwebp ]; + + ldflags = [ "-s" "-w" ]; + + meta = with lib; { + description = "YouTube traffic proxy for video playback and images"; + homepage = "https://github.com/TeamPiped/http3-ytproxy"; + license = licenses.agpl3Only; + maintainers = with maintainers; [ _999eagle ]; + mainProgram = "http3-ytproxy"; + }; +} From ac5c1886fd9fe49748d7ab80accc4c847481df14 Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Mon, 6 Nov 2023 17:54:28 +0100 Subject: [PATCH 7/8] nixos/invidious: add option to configure http3-ytproxy for invidious --- nixos/modules/services/web-apps/invidious.nix | 45 +++++++++++++++++++ nixos/tests/invidious.nix | 22 +++++++++ 2 files changed, 67 insertions(+) diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix index a91132c9b85c6..7af1d35e46104 100644 --- a/nixos/modules/services/web-apps/invidious.nix +++ b/nixos/modules/services/web-apps/invidious.nix @@ -171,6 +171,34 @@ let }; }; + ytproxyConfig = lib.mkIf cfg.http3-ytproxy.enable { + systemd.services.http3-ytproxy = { + description = "HTTP3 ytproxy for Invidious"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + script = '' + mkdir -p socket + exec ${lib.getExe cfg.http3-ytproxy.package}; + ''; + + serviceConfig = { + RestartSec = "2s"; + DynamicUser = true; + User = lib.mkIf cfg.nginx.enable config.services.nginx.user; + RuntimeDirectory = "http3-ytproxy"; + WorkingDirectory = "/run/http3-ytproxy"; + }; + }; + + services.nginx.virtualHosts.${cfg.domain} = lib.mkIf cfg.nginx.enable { + locations."~ (^/videoplayback|^/vi/|^/ggpht/|^/sb/)" = { + proxyPass = "http://unix:/run/http3-ytproxy/socket/http-proxy.sock"; + }; + }; + }; + nginxConfig = lib.mkIf cfg.nginx.enable { services.invidious.settings = { https_only = config.services.nginx.virtualHosts.${cfg.domain}.forceSSL; @@ -348,11 +376,28 @@ in which can also be used to disable AMCE and TLS. ''; }; + + http3-ytproxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc '' + Whether to enable http3-ytproxy for faster loading of images and video playback. + + If {option}`services.invidious.nginx.enable` is used, nginx will be configured automatically. If not, you + need to configure a reverse proxy yourself according to + https://docs.invidious.io/improve-public-instance/#3-speed-up-video-playback-with-http3-ytproxy. + ''; + }; + + package = lib.mkPackageOptionMD pkgs "http3-ytproxy" { }; + }; }; config = lib.mkIf cfg.enable (lib.mkMerge [ serviceConfig localDatabaseConfig nginxConfig + ytproxyConfig ]); } diff --git a/nixos/tests/invidious.nix b/nixos/tests/invidious.nix index 8c2342f66ea68..aab62e26b82b7 100644 --- a/nixos/tests/invidious.nix +++ b/nixos/tests/invidious.nix @@ -53,6 +53,19 @@ import ./make-test-python.nix ({ pkgs, ... }: { }; networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; }; + nginx-scale-ytproxy.configuration = { + services.invidious = { + nginx.enable = true; + http3-ytproxy.enable = true; + domain = "invidious.example.com"; + serviceScale = 3; + }; + services.nginx.virtualHosts."invidious.example.com" = { + forceSSL = false; + enableACME = false; + }; + networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; + }; postgres-tcp.configuration = { services.invidious = { database = { @@ -98,6 +111,15 @@ import ./make-test-python.nix ({ pkgs, ... }: { machine.succeed("journalctl -eu invidious-1.service | grep -o '200 GET /search'") machine.succeed("journalctl -eu invidious-2.service | grep -o '200 GET /search'") + activate_specialisation("nginx-scale-ytproxy") + machine.wait_for_unit("http3-ytproxy.service") + machine.wait_for_open_port(80) + machine.wait_until_succeeds("ls /run/http3-ytproxy/socket/http-proxy.sock") + curl_assert_status_code("http://invidious.example.com/search", 200) + # this should error out as no internet connectivity is available in the test + curl_assert_status_code("http://invidious.example.com/vi/dQw4w9WgXcQ/mqdefault.jpg", 502) + machine.succeed("journalctl -eu http3-ytproxy.service | grep -o 'dQw4w9WgXcQ'") + postgres_tcp.wait_for_unit("postgresql.service") activate_specialisation("postgres-tcp") machine.wait_for_open_port(port) From 24e561fabca19b9cee1fef98e793b712901b8482 Mon Sep 17 00:00:00 2001 From: Sophie Tauchert Date: Sat, 18 Nov 2023 20:15:26 +0100 Subject: [PATCH 8/8] nixos/invidious: change default database user to invidious This makes sure we don't need any workarounds for running Invidious with a local PostgreSQL database. Changing the default user should be fine as the new init script for PostgreSQL automatically creates the new user and changes the existing database's owner to the new user. The old user will still linger and must be removed manually. See also: https://github.com/NixOS/nixpkgs/pull/266270 --- .../manual/release-notes/rl-2405.section.md | 2 + nixos/modules/services/web-apps/invidious.nix | 39 +++++++++---------- nixos/tests/invidious.nix | 10 ++--- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index d30e0b6624c56..34b1fd1f36853 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -37,6 +37,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `k9s` was updated to v0.29. There have been breaking changes in the config file format, check out the [changelog](https://github.com/derailed/k9s/releases/tag/v0.29.0) for details. +- Invidious has changed its default database username from `kemal` to `invidious`. Setups involving an externally provisioned database (i.e. `services.invidious.database.createLocally == false`) should adjust their configuration accordingly. The old `kemal` user will not be removed automatically even when the database is provisioned automatically.(https://github.com/NixOS/nixpkgs/pull/265857) + - `mkosi` was updated to v19. Parts of the user interface have changed. Consult the [release notes](https://github.com/systemd/mkosi/releases/tag/v19) for a list of changes. diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix index 7af1d35e46104..471027c357056 100644 --- a/nixos/modules/services/web-apps/invidious.nix +++ b/nixos/modules/services/web-apps/invidious.nix @@ -114,7 +114,11 @@ let check_tables = true; db = { - user = lib.mkDefault "kemal"; + user = lib.mkDefault ( + if (lib.versionAtLeast config.system.stateVersion "24.05") + then "invidious" + else "kemal" + ); dbname = lib.mkDefault "invidious"; port = cfg.database.port; # Blank for unix sockets, see @@ -143,31 +147,26 @@ let # Settings necessary for running with an automatically managed local database localDatabaseConfig = lib.mkIf cfg.database.createLocally { + assertions = [ + { + assertion = cfg.settings.db.user == cfg.settings.db.dbname; + message = '' + For local automatic database provisioning (services.invidious.database.createLocally == true) + to work, the username used to connect to PostgreSQL must match the database name, that is + services.invidious.database.user must match services.invidious.database.dbName. + This is the default since NixOS 24.05. For older systems, it is normally safe to manually set + services.invidious.database.user to "invidious" as the new user will be created with permissions + for the existing database. + ''; + } + ]; # Default to using the local database if we create it services.invidious.database.host = lib.mkDefault null; - - # TODO(raitobezarius to maintainers of invidious): I strongly advise to clean up the kemal specific - # thing for 24.05 and use `ensureDBOwnership`. - # See https://github.com/NixOS/nixpkgs/issues/216989 - systemd.services.postgresql.postStart = lib.mkAfter '' - $PSQL -tAc 'ALTER DATABASE "${cfg.settings.db.dbname}" OWNER TO "${cfg.settings.db.user}";' - ''; services.postgresql = { enable = true; - ensureUsers = lib.singleton { name = cfg.settings.db.user; ensureDBOwnership = false; }; + ensureUsers = lib.singleton { name = cfg.settings.db.user; ensureDBOwnership = true; }; ensureDatabases = lib.singleton cfg.settings.db.dbname; - # This is only needed because the unix user invidious isn't the same as - # the database user. This tells postgres to map one to the other. - identMap = '' - invidious invidious ${cfg.settings.db.user} - ''; - # And this specifically enables peer authentication for only this - # database, which allows passwordless authentication over the postgres - # unix socket for the user map given above. - authentication = '' - local ${cfg.settings.db.dbname} ${cfg.settings.db.user} peer map=invidious - ''; }; }; diff --git a/nixos/tests/invidious.nix b/nixos/tests/invidious.nix index aab62e26b82b7..e31cd87f6a004 100644 --- a/nixos/tests/invidious.nix +++ b/nixos/tests/invidious.nix @@ -10,12 +10,12 @@ import ./make-test-python.nix ({ pkgs, ... }: { services.postgresql = { enable = true; initialScript = pkgs.writeText "init-postgres-with-password" '' - CREATE USER kemal WITH PASSWORD 'correct horse battery staple'; - CREATE DATABASE invidious WITH OWNER kemal; + CREATE USER invidious WITH PASSWORD 'correct horse battery staple'; + CREATE DATABASE invidious WITH OWNER invidious; ''; enableTCPIP = true; authentication = '' - host invidious kemal samenet scram-sha-256 + host invidious invidious samenet scram-sha-256 ''; }; networking.firewall.allowedTCPPorts = [ config.services.postgresql.port ]; @@ -24,10 +24,6 @@ import ./make-test-python.nix ({ pkgs, ... }: { services.invidious = { enable = true; }; - services.postgresql.initialScript = pkgs.writeText "init-postgres-with-password" '' - CREATE USER kemal; - CREATE DATABASE invidious WITH OWNER kemal; - ''; specialisation = { nginx.configuration = {