From 15338a7256d405d6ba0df4663df16c264a3a6e9f Mon Sep 17 00:00:00 2001 From: Zeno Belli Date: Wed, 10 Dec 2025 18:18:09 +0100 Subject: [PATCH 1/3] ci: add go tests for requests handlers --- cmd/requests.go | 2 +- internal/certinfo/certinfo_handlers.go | 11 +- internal/requests/main_test.go | 27 +- internal/requests/requests.go | 5 +- internal/requests/requests_handlers.go | 70 +-- internal/requests/requests_handlers_test.go | 539 ++++++++++++++++++++ 6 files changed, 616 insertions(+), 38 deletions(-) create mode 100644 internal/requests/requests_handlers_test.go diff --git a/cmd/requests.go b/cmd/requests.go index 8a55705..52e1749 100644 --- a/cmd/requests.go +++ b/cmd/requests.go @@ -94,7 +94,7 @@ Examples: fmt.Print(err) } - responseMap, err := requests.HandleRequests(requestsCfg) + responseMap, err := requests.HandleRequests(os.Stdout, requestsCfg) if err != nil { fmt.Print(err) } diff --git a/internal/certinfo/certinfo_handlers.go b/internal/certinfo/certinfo_handlers.go index 361f82a..0a70141 100644 --- a/internal/certinfo/certinfo_handlers.go +++ b/internal/certinfo/certinfo_handlers.go @@ -10,6 +10,7 @@ import ( "crypto/x509" "encoding/hex" "fmt" + "io" "net" "os" "strconv" @@ -62,7 +63,7 @@ func (c *CertinfoConfig) PrintData() { )) } - CertsToTables(c.CertsBundle) + CertsToTables(os.Stdout, c.CertsBundle) } if len(c.TLSEndpointCerts) > 0 { @@ -96,7 +97,7 @@ func (c *CertinfoConfig) PrintData() { )) } - CertsToTables(c.TLSEndpointCerts) + CertsToTables(os.Stdout, c.TLSEndpointCerts) } if len(c.CACertsFilePath) > 0 { @@ -116,7 +117,7 @@ func (c *CertinfoConfig) PrintData() { return } - CertsToTables(rootCerts) + CertsToTables(os.Stdout, rootCerts) } } @@ -162,7 +163,7 @@ func (c *CertinfoConfig) GetRemoteCerts() { } } -func CertsToTables(certs []*x509.Certificate) { +func CertsToTables(w io.Writer, certs []*x509.Certificate) { sl := style.CertKeyP4.Render sv := style.CertValue.Render svn := style.CertValueNotice.Render @@ -214,7 +215,7 @@ func CertsToTables(certs []*x509.Certificate) { t.Row(sl("SignatureAlgorithm"), sv(signatureAlgorithm)) t.Row(sl("SerialNumber"), sv(serialNumber)) t.Row(sl("Fingerprint SHA-256"), sv(fingerprintSha256)) - fmt.Println(t.Render()) + fmt.Fprintln(w, t.Render()) t.ClearRows() } } diff --git a/internal/requests/main_test.go b/internal/requests/main_test.go index a93c614..2f3d2a7 100644 --- a/internal/requests/main_test.go +++ b/internal/requests/main_test.go @@ -36,6 +36,8 @@ type demoHttpServerData struct { serverAddr string proxyprotoEnabled bool serverName string + tlsCipherSuites []uint16 + tlsMaxVersion uint16 } var ( @@ -209,7 +211,30 @@ func NewHTTPSTestServer(data demoHttpServerData) (*httptest.Server, error) { return nil, err } - ts.TLS = &tls.Config{Certificates: []tls.Certificate{cert}} + // Set default TLS CipherSuites to TLS 1.3 cipher suites + // https://pkg.go.dev/crypto/tls#pkg-constants + tlsCipherSuites := []uint16{ + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + } + + if len(data.tlsCipherSuites) > 0 { + tlsCipherSuites = data.tlsCipherSuites + } + + // Set default TLS MaxVersion to 1.3 + var tlsMaxVersion uint16 = tls.VersionTLS13 + + if data.tlsMaxVersion > 0 { + tlsMaxVersion = data.tlsMaxVersion + } + + ts.TLS = &tls.Config{ + Certificates: []tls.Certificate{cert}, + CipherSuites: tlsCipherSuites, + MaxVersion: tlsMaxVersion, + } ts.StartTLS() diff --git a/internal/requests/requests.go b/internal/requests/requests.go index 23821df..7cb3972 100644 --- a/internal/requests/requests.go +++ b/internal/requests/requests.go @@ -568,7 +568,10 @@ func processHTTPRequestsByHost(r RequestConfig, caPool *x509.CertPool, isVerbose return nil, err } - urlList := getUrlsFromHost(host) + urlList, err := getUrlsFromHost(host) + if err != nil { + return nil, err + } for _, reqURL := range urlList { responseData := ResponseData{ diff --git a/internal/requests/requests_handlers.go b/internal/requests/requests_handlers.go index 8f88eb3..b48903a 100644 --- a/internal/requests/requests_handlers.go +++ b/internal/requests/requests_handlers.go @@ -27,6 +27,7 @@ func (h ResponseHeader) String() string { } func (u URI) Parse() bool { + // URIs must start with a slash as in /uri matched, err := regexp.Match(`^\/.*`, []byte(u)) if err != nil { return false @@ -54,14 +55,14 @@ func TLSVersionName(v uint16) string { func cipherSuiteName(id uint16) string { cs := tls.CipherSuiteName(id) - if cs == "" { + if strings.Contains(cs, "0x") { return fmt.Sprintf("Unknown (0x%x)", id) } return cs } -func parseResponseHeaders(headers http.Header, filter []string) string { +func filterResponseHeaders(headers http.Header, filter []string) string { var outputStr string var outputMap map[string][]string @@ -94,42 +95,40 @@ func parseResponseHeaders(headers http.Header, filter []string) string { return outputStr } -func getUrlsFromHost(h Host) []string { +func getUrlsFromHost(h Host) ([]string, error) { var list []string if len(h.URIList) == 0 { s := httpClientDefaultScheme + "://" + h.Name list = append(list, s) - return list + return list, nil } for _, uri := range h.URIList { if parsed := uri.Parse(); !parsed { - fmt.Printf("Invalid uri %s for host %s", uri, h.Name) - - break + return nil, fmt.Errorf("invalid uri %s for host %s", uri, h.Name) } s := fmt.Sprintf("%s://%s%s", httpClientDefaultScheme, h.Name, uri) list = append(list, s) } - return list -} - -func transportAddressFromRequest(r RequestConfig) (string, error) { - addr, err := transportAddressFromURLString(r.TransportOverrideURL) - if err != nil { - return emptyString, err - } - - return addr, nil + return list, nil } func transportAddressFromURLString(transportURL string) (string, error) { var addr string + if transportURL == emptyString { + return emptyString, errors.New("empty string provided as transportURL") + } + + // Add HTTPS scheme if missing from transportURL + if match, _ := regexp.MatchString("^https://", transportURL); !match { + transportURL = "https://" + transportURL + } + overrideURL, err := url.Parse(transportURL) if err != nil { return "", err @@ -137,6 +136,7 @@ func transportAddressFromURLString(transportURL string) (string, error) { addr = overrideURL.Host + // Add default HTTPS port if a port is missing from transportURL if match, _ := regexp.MatchString("\\:\\d+$", addr); !match { addr += ":443" } @@ -203,10 +203,10 @@ func proxyProtoHeaderFromRequest(r RequestConfig, serverName string) (proxyproto return header, nil } -func HandleRequests(cfg *RequestsMetaConfig) (map[string][]ResponseData, error) { +func HandleRequests(w io.Writer, cfg *RequestsMetaConfig) (map[string][]ResponseData, error) { responseDataMap := make(map[string][]ResponseData) - cfg.PrintCmd(os.Stdout) + cfg.PrintCmd(w) for _, r := range cfg.Requests { responseDataList, err := processHTTPRequestsByHost( @@ -304,11 +304,11 @@ func (rd ResponseData) PrintResponseData(isVerbose bool) { style.StatusCodeParse(rd.Response.StatusCode))) if rd.Request.PrintResponseCertificates { - RenderTLSData(rd.Response) + RenderTLSData(os.Stdout, rd.Response) } if rd.Request.PrintResponseHeaders { - headersStr := parseResponseHeaders( + headersStr := filterResponseHeaders( rd.Response.Header, rd.Request.ResponseHeadersFilter) @@ -330,26 +330,36 @@ func (rd ResponseData) PrintResponseData(isVerbose bool) { } } -func RenderTLSData(r *http.Response) { +func RenderTLSData(w io.Writer, r *http.Response) { respTLS := r.TLS sl := style.CertKeyP4.Render sv := style.CertValue.Render - fmt.Println(style.LgSprintf(style.ItemKeyP3, "TLS:")) + fmt.Fprintln(w, style.LgSprintf(style.ItemKeyP3, "TLS:")) if respTLS == nil { - fmt.Println(style.LgSprintf(style.CertKeyP4, - "%s", - style.Error.Render("No TLS connection state available"))) + fmt.Fprintln( + w, + style.LgSprintf(style.CertKeyP4, + "%s", + style.Error.Render("No TLS connection state available"), + ), + ) return } t := table.New().Border(style.LGDefBorder) - t.Row(sl("Version"), sv(TLSVersionName(respTLS.Version))) - t.Row(sl("CipherSuite"), sv(cipherSuiteName(respTLS.CipherSuite))) - fmt.Println(t.Render()) + t.Row( + sl("Version"), + sv(TLSVersionName(respTLS.Version)), + ) + t.Row( + sl("CipherSuite"), + sv(cipherSuiteName(respTLS.CipherSuite)), + ) + fmt.Fprintln(w, t.Render()) t.ClearRows() - certinfo.CertsToTables(respTLS.PeerCertificates) + certinfo.CertsToTables(w, respTLS.PeerCertificates) } diff --git a/internal/requests/requests_handlers_test.go b/internal/requests/requests_handlers_test.go new file mode 100644 index 0000000..a5eec23 --- /dev/null +++ b/internal/requests/requests_handlers_test.go @@ -0,0 +1,539 @@ +package requests + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "fmt" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestResponseHeader_Print(t *testing.T) { + tests := []struct { + header ResponseHeader + str string + }{ + { + header: "testString", + str: "testString", + }, + } + + for i, tc := range tests { + tt := tc // safer when using t.Parallel() + testname := fmt.Sprintf("TestString%v", i) + t.Run(testname, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.str, tt.header.String()) + }) + } +} + +func TestURI_Parse(t *testing.T) { + tests := []struct { + uri URI + expectValid bool + }{ + {uri: "testString", expectValid: false}, + {uri: "/validUri", expectValid: true}, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + testname := fmt.Sprintf("TestURI_%s", tt.uri) + t.Run(testname, func(t *testing.T) { + t.Parallel() + + if tt.expectValid { + assert.True(t, tt.uri.Parse()) + } + + if !tt.expectValid { + assert.False(t, tt.uri.Parse()) + } + }) + } +} + +func TestTLSVersionName(t *testing.T) { + tests := []struct { + inputVal uint16 + expectedStr string + }{ + { + inputVal: tls.VersionSSL30, + expectedStr: "SSL 3.0", + }, + { + inputVal: tls.VersionTLS10, + expectedStr: "TLS 1.0", + }, + { + inputVal: tls.VersionTLS11, + expectedStr: "TLS 1.1", + }, + { + inputVal: tls.VersionTLS12, + expectedStr: "TLS 1.2", + }, + { + inputVal: tls.VersionTLS13, + expectedStr: "TLS 1.3", + }, + { + inputVal: 0x0399, + expectedStr: "Unknown (0x399)", + }, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + // testname := fmt.Sprintf("%s", tt.expectedStr) + t.Run(tt.expectedStr, func(t *testing.T) { + t.Parallel() + + version := TLSVersionName(tt.inputVal) + + assert.Contains(t, version, tt.expectedStr) + }) + } +} + +func TestCipherSuiteName(t *testing.T) { + tests := []struct { + inputVal uint16 + expectedStr string + }{ + { + inputVal: 0xcca9, + expectedStr: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, + + { + inputVal: 0x1303, + expectedStr: "TLS_CHACHA20_POLY1305_SHA256", + }, + + { + inputVal: 0xc023, + expectedStr: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + }, + + { + inputVal: 0x9999, + expectedStr: "Unknown (0x9999)", + }, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + testname := fmt.Sprintf("Test_%s", tt.expectedStr) + t.Run(testname, func(t *testing.T) { + t.Parallel() + + name := cipherSuiteName(tt.inputVal) + + assert.Equal(t, tt.expectedStr, name) + }) + } +} + +func TestFilterResponseHeaders(t *testing.T) { + sampleHTTPHeader := http.Header{ + "Content-Type": []string{"application/json"}, + "Server": []string{"nginx"}, + "Cache-Control": []string{"max-age=3600"}, + } + + sampleHTTPHeader2 := http.Header{ + "Server": []string{"Envoy"}, + "User-Agent": []string{"go-test"}, + } + + tests := []struct { + inputHeader http.Header + filter []string + expectedOutput []string + unexpectedOutput []string + }{ + { + inputHeader: sampleHTTPHeader, + filter: []string{"Server"}, + expectedOutput: []string{"nginx", "Server"}, + unexpectedOutput: []string{ + "application/json", + "Content-Type", "Cache-Control", "max-age", + }, + }, + { + inputHeader: sampleHTTPHeader2, + filter: []string{"User-Agent"}, + expectedOutput: []string{"User-Agent", "go-test"}, + unexpectedOutput: []string{"Envoy", "Server"}, + }, + { + inputHeader: sampleHTTPHeader2, + filter: []string{}, + expectedOutput: []string{"go-test", "Envoy"}, + unexpectedOutput: []string{"NotInMap"}, + }, + } + + for i, tc := range tests { + tt := tc // safer when using t.Parallel() + testname := fmt.Sprintf("Test_%v", i) + t.Run(testname, func(t *testing.T) { + // t.Parallel() // WARN the test fails if t.Parallel() + output := filterResponseHeaders(tt.inputHeader, tt.filter) + + for _, o := range tt.expectedOutput { + assert.Contains(t, output, o) + } + + for _, uo := range tt.unexpectedOutput { + require.NotContains(t, output, uo) + } + }) + } +} + +func TestGetUrlsFromHost(t *testing.T) { + tests := []struct { + desc string + inputHost Host + expectedOutput []string + expectedError bool + }{ + { + desc: "AllValid", + inputHost: Host{Name: "localhost", URIList: []URI{"/one", "/two", "/three"}}, + expectedOutput: []string{ + "https://localhost/one", + "https://localhost/two", + "https://localhost/three", + }, + }, + { + desc: "OneNotParsing", + inputHost: Host{Name: "localhost", URIList: []URI{"one", "/two", "/three"}}, + expectedOutput: []string{ + "https://localhost/two", + "https://localhost/three", + }, + expectedError: true, + }, + { + desc: "NoURIList", + inputHost: Host{Name: "example.com"}, + expectedOutput: []string{ + "https://example.com", + }, + }, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + t.Run(tt.desc, func(t *testing.T) { + t.Parallel() + + output, err := getUrlsFromHost(tt.inputHost) + + if tt.expectedError { + require.Error(t, err) + } + + if !tt.expectedError { + require.NoError(t, err) + assert.Equal(t, tt.expectedOutput, output) + } + }) + } +} + +func TestTransportAddressFromURLString(t *testing.T) { + tests := []struct { + desc string + input string + expectError bool + expectOutput string + }{ + { + desc: "NoPort", + input: "https://localhost", + expectError: false, + expectOutput: "localhost:443", + }, + + { + desc: "Valid", + input: "https://example.com:8443", + expectError: false, + expectOutput: "example.com:8443", + }, + + { + desc: "NoScheme", + input: "example.com:8443", + expectError: false, + expectOutput: "example.com:8443", + }, + + { + desc: "EmptyInput", + input: emptyString, + expectError: true, + expectOutput: "empty string provided as transportURL", + }, + + { + desc: "Invalid", + input: "loca$%^lhost", + expectError: true, + expectOutput: "parse \"https://loca$%^lhost\": invalid URL escape \"%^l\"", + }, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + t.Run(tt.desc, func(t *testing.T) { + t.Parallel() + + output, err := transportAddressFromURLString(tt.input) + + if tt.expectError { + require.Error(t, err) + assert.Equal(t, tt.expectOutput, err.Error()) + } + + if !tt.expectError { + require.NoError(t, err) + assert.Equal(t, tt.expectOutput, output) + } + }) + } +} + +func TestRenderTLSData(t *testing.T) { + tests := []struct { + srvAddr string + srvTLSCipherSuite uint16 + srvTLSMaxVersion uint16 + reqConf RequestConfig + pool *x509.CertPool + injectTLSError bool + }{ + // WARN: not all cipher suites listed as 'TLS 1.0 - 1.2 cipher suites' + // are supported. + // Ref: + // https://pkg.go.dev/crypto/tls#pkg-constants + // https://github.com/golang/go/issues/53750 + { + srvAddr: "localhost:46101", + srvTLSCipherSuite: tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + srvTLSMaxVersion: tls.VersionTLS12, + reqConf: RequestConfig{ + Name: "example.com", + TransportOverrideURL: "https://localhost:46101", + Hosts: []Host{ + {Name: "example.com"}, + }, + }, + pool: caCertPool, + }, + + // WARN: I was expecting a cipherSuite list of one element as input to the server conf + // would make only that one available. + // This test seems to prove the default list is returned instead (..SHA256 vs ...SHA384) + // Is this related to the certificate? + { + srvAddr: "localhost:46102", + // srvTLSCipherSuite: tls.TLS_AES_256_GCM_SHA384, + srvTLSCipherSuite: tls.TLS_AES_128_GCM_SHA256, + srvTLSMaxVersion: tls.VersionTLS13, + reqConf: RequestConfig{ + Name: "example.net", + TransportOverrideURL: "https://localhost:46102", + Hosts: []Host{ + {Name: "example.net"}, + }, + }, + pool: caCertPool, + }, + { + srvAddr: "localhost:46103", + srvTLSCipherSuite: tls.TLS_AES_128_GCM_SHA256, + srvTLSMaxVersion: tls.VersionTLS13, + reqConf: RequestConfig{ + Name: "example.de", + TransportOverrideURL: "https://localhost:46103", + Hosts: []Host{ + {Name: "example.de"}, + }, + }, + pool: caCertPool, + injectTLSError: true, + }, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + t.Run(tt.reqConf.Name, func(t *testing.T) { + t.Parallel() + + httpSrvData := demoHttpServerData{ + serverAddr: tt.srvAddr, + tlsCipherSuites: []uint16{tt.srvTLSCipherSuite}, + tlsMaxVersion: tt.srvTLSMaxVersion, + proxyprotoEnabled: false, + serverName: "localhost", + } + + ts, err := NewHTTPSTestServer(httpSrvData) + require.NoError(t, err) + + defer ts.Close() + + respList, err := processHTTPRequestsByHost( + tt.reqConf, + tt.pool, + false, + ) + require.NoError(t, err) + + for _, r := range respList { + buffer := bytes.Buffer{} + + if tt.injectTLSError { + r.Response.TLS = nil + } + + RenderTLSData(&buffer, r.Response) + got := buffer.String() + + if tt.injectTLSError { + assert.Contains(t, got, "No TLS connection state available") + break + } + + assert.Contains(t, got, "TLS:") + assert.Contains(t, got, "Version") + + expectedTLSVersion := tls.VersionName(tt.srvTLSMaxVersion) + assert.Contains(t, got, expectedTLSVersion) + + assert.Contains(t, got, "CipherSuite") + + expectedCipherSuiteName := tls.CipherSuiteName(tt.srvTLSCipherSuite) + assert.Contains(t, got, expectedCipherSuiteName) + + assert.Contains(t, got, "Certificate 0") + assert.Contains(t, got, "Subject") + assert.Contains(t, got, "DNSNames") + assert.Contains(t, got, "Issuer") + assert.Contains(t, got, tt.reqConf.Hosts[0].Name) + } + }) + } +} + +func TestHandleRequests(t *testing.T) { + reqMeta1 := RequestsMetaConfig{ + CACertsPool: caCertPool, + RequestVerbose: true, + Requests: []RequestConfig{ + { + Name: "Meta10", + TransportOverrideURL: "localhost:46201", + UserAgent: "Meta10", + Hosts: []Host{ + {Name: "example.com"}, + }, + }, + }, + } + + reqMeta2 := RequestsMetaConfig{ + CACertsPool: caCertPool, + RequestVerbose: true, + Requests: []RequestConfig{ + { + Name: "Meta11", + TransportOverrideURL: "localhost:46202", + UserAgent: "Meta11", + Hosts: []Host{ + {Name: emptyString}, + }, + }, + }, + } + + tests := []struct { + desc string + srvAddr string + reqMeta RequestsMetaConfig + expectErr bool + }{ + { + desc: "Meta10", + srvAddr: "localhost:46201", + reqMeta: reqMeta1, + }, + { + desc: "Meta11", + srvAddr: "localhost:46202", + reqMeta: reqMeta2, + expectErr: true, + }, + } + + for _, tc := range tests { + tt := tc // safer when using t.Parallel() + t.Run(tt.desc, func(t *testing.T) { + t.Parallel() + + httpSrvData := demoHttpServerData{ + serverAddr: tt.srvAddr, + serverName: "localhost", + } + + ts, err := NewHTTPSTestServer(httpSrvData) + require.NoError(t, err) + + defer ts.Close() + + buffer := bytes.Buffer{} + respMap, err := HandleRequests(&buffer, &tt.reqMeta) + + if tt.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + out := buffer.String() + assert.Contains(t, out, "Requests") + + for reqConfName, rdList := range respMap { + for _, rd := range rdList { + gotReqConfName := rd.Request.Name + + assert.Equal(t, gotReqConfName, reqConfName) + + ua := tt.reqMeta.Requests[0].UserAgent + wantUa := httpUserAgent + + if ua != wantUa { + wantUa = ua + } + + gotUa := rd.Response.Request.UserAgent() + assert.Equal(t, wantUa, gotUa) + } + } + }) + } +} From 92769987ed83f7b9ee8ec534071850800986faa9 Mon Sep 17 00:00:00 2001 From: Zeno Belli Date: Wed, 10 Dec 2025 18:18:30 +0100 Subject: [PATCH 2/3] ci: update devenv conf --- devenv.lock | 24 ++++++++++++++++++++---- devenv.nix | 11 +++++++++-- devenv.yaml | 3 +++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/devenv.lock b/devenv.lock index c6dfda3..2836f56 100644 --- a/devenv.lock +++ b/devenv.lock @@ -3,10 +3,10 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1763386227, + "lastModified": 1764449550, "owner": "cachix", "repo": "devenv", - "rev": "9f855598530d6ee075cc126e4f13812fd008209a", + "rev": "dfb58ac03bed07b93f629df55034bc50394d3971", "type": "github" }, "original": { @@ -40,10 +40,10 @@ ] }, "locked": { - "lastModified": 1763319842, + "lastModified": 1763988335, "owner": "cachix", "repo": "git-hooks.nix", - "rev": "7275fa67fbbb75891c16d9dee7d88e58aea2d761", + "rev": "50b9238891e388c9fdc6a5c49e49c42533a1b5ce", "type": "github" }, "original": { @@ -87,11 +87,27 @@ "type": "github" } }, + "nixpkgsStable": { + "locked": { + "lastModified": 1764560356, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6c8f0cca84510cc79e09ea99a299c9bc17d03cb6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, "root": { "inputs": { "devenv": "devenv", "git-hooks": "git-hooks", "nixpkgs": "nixpkgs", + "nixpkgsStable": "nixpkgsStable", "pre-commit-hooks": [ "git-hooks" ] diff --git a/devenv.nix b/devenv.nix index 506e50a..d366ada 100644 --- a/devenv.nix +++ b/devenv.nix @@ -4,7 +4,9 @@ config, inputs, ... -}: { +}: let + pkgsStable = import inputs.nixpkgsStable {system = pkgs.stdenv.system;}; +in { env = { GUM_FORMAT_THEME = "tokyo-night"; CAROOT = "tests/certs"; @@ -49,7 +51,12 @@ }; }; - # languages.go.enable = true; + # https://devenv.sh/reference/options/#languagesgoenable + # TODO: align go related versions used by vim to this before enabling + # languages.go = { + # enable = true; + # package = pkgs.go; + # }; services.nginx = { enable = true; diff --git a/devenv.yaml b/devenv.yaml index 116a2ad..12f405d 100644 --- a/devenv.yaml +++ b/devenv.yaml @@ -1,7 +1,10 @@ +--- # yaml-language-server: $schema=https://devenv.sh/devenv.schema.json inputs: nixpkgs: url: github:cachix/devenv-nixpkgs/rolling + nixpkgsStable: + url: "github:NixOS/nixpkgs/nixos-25.05" # If you're using non-OSS software, you can set allowUnfree to true. # allowUnfree: true From 39a84b95fb084f9a227dd0a5aa757a001e82941d Mon Sep 17 00:00:00 2001 From: Zeno Belli Date: Wed, 10 Dec 2025 19:43:28 +0100 Subject: [PATCH 3/3] refactor: remove unused test data from TestGetUrlsFromHost --- devenv.nix | 1 + internal/requests/requests_handlers_test.go | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/devenv.nix b/devenv.nix index d366ada..35d2263 100644 --- a/devenv.nix +++ b/devenv.nix @@ -5,6 +5,7 @@ inputs, ... }: let + # TODO: align go version between nixos/nixvim and devenv pkgsStable = import inputs.nixpkgsStable {system = pkgs.stdenv.system;}; in { env = { diff --git a/internal/requests/requests_handlers_test.go b/internal/requests/requests_handlers_test.go index a5eec23..fe3c06c 100644 --- a/internal/requests/requests_handlers_test.go +++ b/internal/requests/requests_handlers_test.go @@ -218,12 +218,8 @@ func TestGetUrlsFromHost(t *testing.T) { }, }, { - desc: "OneNotParsing", - inputHost: Host{Name: "localhost", URIList: []URI{"one", "/two", "/three"}}, - expectedOutput: []string{ - "https://localhost/two", - "https://localhost/three", - }, + desc: "OneNotParsing", + inputHost: Host{Name: "localhost", URIList: []URI{"one", "/two", "/three"}}, expectedError: true, }, {