TUN-9016: update go to 1.24

## Summary

Update several moving parts of cloudflared build system:

* use goboring 1.24.2 in cfsetup
* update linter and fix lint issues
* update packages namely **quic-go and net**
* install script for macos
* update docker files to use go 1.24.1
* remove usage of cloudflare-go
* pin golang linter

Closes TUN-9016
This commit is contained in:
Luis Neto 2025-06-06 09:05:49 +00:00
parent e144eac2af
commit 96ce66bd30
585 changed files with 23572 additions and 21356 deletions

View File

@ -57,8 +57,7 @@ build_cloudflared_macos: &build
- '[ "${RUNNER_ARCH}" = "intel" ] && export TARGET_ARCH=amd64' - '[ "${RUNNER_ARCH}" = "intel" ] && export TARGET_ARCH=amd64'
- ARCH=$(uname -m) - ARCH=$(uname -m)
- echo ARCH=$ARCH - TARGET_ARCH=$TARGET_ARCH - echo ARCH=$ARCH - TARGET_ARCH=$TARGET_ARCH
- ./.teamcity/mac/install-cloudflare-go.sh - ./.teamcity/mac/install-go.sh
- export PATH="/tmp/go/bin:$PATH"
- BUILD_SCRIPT=.teamcity/mac/build.sh - BUILD_SCRIPT=.teamcity/mac/build.sh
- if [[ ! -x ${BUILD_SCRIPT} ]] ; then exit ; fi - if [[ ! -x ${BUILD_SCRIPT} ]] ; then exit ; fi
- set -euo pipefail - set -euo pipefail

View File

@ -27,7 +27,7 @@ linters:
- sloglint # Ensure consistent code style when using log/slog. - sloglint # Ensure consistent code style when using log/slog.
- sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed. - sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed.
- staticcheck # It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. - staticcheck # It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary.
- tenv # Tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17. - usetesting # Reports uses of functions with replacement inside the testing package.
- testableexamples # Linter checks if examples are testable (have an expected output). - testableexamples # Linter checks if examples are testable (have an expected output).
- testifylint # Checks usage of github.com/stretchr/testify. - testifylint # Checks usage of github.com/stretchr/testify.
- tparallel # Tparallel detects inappropriate usage of t.Parallel() method in your Go test codes. - tparallel # Tparallel detects inappropriate usage of t.Parallel() method in your Go test codes.

10
.teamcity/mac/install-go.sh vendored Executable file
View File

@ -0,0 +1,10 @@
rm -rf /tmp/go
export GOCACHE=/tmp/gocache
rm -rf $GOCACHE
brew install go@1.24
go version
which go
go env

View File

@ -32,7 +32,7 @@ Write-Output "Running unit tests"
# Not testing with race detector because of https://github.com/golang/go/issues/61058 # Not testing with race detector because of https://github.com/golang/go/issues/61058
# We already test it on other platforms # We already test it on other platforms
& go test -failfast -mod=vendor ./... go test -failfast -v -mod=vendor ./...
if ($LASTEXITCODE -ne 0) { throw "Failed unit tests" } if ($LASTEXITCODE -ne 0) { throw "Failed unit tests" }
Write-Output "Running component tests" Write-Output "Running component tests"

View File

@ -1,7 +1,7 @@
# use a builder image for building cloudflare # use a builder image for building cloudflare
ARG TARGET_GOOS ARG TARGET_GOOS
ARG TARGET_GOARCH ARG TARGET_GOARCH
FROM golang:1.22.10 as builder FROM golang:1.24.2 AS builder
ENV GO111MODULE=on \ ENV GO111MODULE=on \
CGO_ENABLED=0 \ CGO_ENABLED=0 \
TARGET_GOOS=${TARGET_GOOS} \ TARGET_GOOS=${TARGET_GOOS} \
@ -16,10 +16,8 @@ WORKDIR /go/src/github.com/cloudflare/cloudflared/
# copy our sources into the builder image # copy our sources into the builder image
COPY . . COPY . .
RUN .teamcity/install-cloudflare-go.sh
# compile cloudflared # compile cloudflared
RUN PATH="/tmp/go/bin:$PATH" make cloudflared RUN make cloudflared
# use a distroless base image with glibc # use a distroless base image with glibc
FROM gcr.io/distroless/base-debian12:nonroot FROM gcr.io/distroless/base-debian12:nonroot

View File

@ -1,5 +1,5 @@
# use a builder image for building cloudflare # use a builder image for building cloudflare
FROM golang:1.22.10 as builder FROM golang:1.24.2 AS builder
ENV GO111MODULE=on \ ENV GO111MODULE=on \
CGO_ENABLED=0 \ CGO_ENABLED=0 \
# the CONTAINER_BUILD envvar is used set github.com/cloudflare/cloudflared/metrics.Runtime=virtual # the CONTAINER_BUILD envvar is used set github.com/cloudflare/cloudflared/metrics.Runtime=virtual
@ -11,10 +11,8 @@ WORKDIR /go/src/github.com/cloudflare/cloudflared/
# copy our sources into the builder image # copy our sources into the builder image
COPY . . COPY . .
RUN .teamcity/install-cloudflare-go.sh
# compile cloudflared # compile cloudflared
RUN GOOS=linux GOARCH=amd64 PATH="/tmp/go/bin:$PATH" make cloudflared RUN GOOS=linux GOARCH=amd64 make cloudflared
# use a distroless base image with glibc # use a distroless base image with glibc
FROM gcr.io/distroless/base-debian12:nonroot FROM gcr.io/distroless/base-debian12:nonroot

View File

@ -1,5 +1,5 @@
# use a builder image for building cloudflare # use a builder image for building cloudflare
FROM golang:1.22.10 as builder FROM golang:1.24.2 AS builder
ENV GO111MODULE=on \ ENV GO111MODULE=on \
CGO_ENABLED=0 \ CGO_ENABLED=0 \
# the CONTAINER_BUILD envvar is used set github.com/cloudflare/cloudflared/metrics.Runtime=virtual # the CONTAINER_BUILD envvar is used set github.com/cloudflare/cloudflared/metrics.Runtime=virtual
@ -11,10 +11,8 @@ WORKDIR /go/src/github.com/cloudflare/cloudflared/
# copy our sources into the builder image # copy our sources into the builder image
COPY . . COPY . .
RUN .teamcity/install-cloudflare-go.sh
# compile cloudflared # compile cloudflared
RUN GOOS=linux GOARCH=arm64 PATH="/tmp/go/bin:$PATH" make cloudflared RUN GOOS=linux GOARCH=arm64 make cloudflared
# use a distroless base image with glibc # use a distroless base image with glibc
FROM gcr.io/distroless/base-debian12:nonroot-arm64 FROM gcr.io/distroless/base-debian12:nonroot-arm64

View File

@ -1,4 +1,4 @@
pinned_go: &pinned_go go-boring=1.22.10-1 pinned_go: &pinned_go go-boring=1.24.2-1
build_dir: &build_dir /cfsetup_build build_dir: &build_dir /cfsetup_build
default-flavor: bookworm default-flavor: bookworm
@ -13,7 +13,7 @@ bullseye: &bullseye
- rubygem-fpm - rubygem-fpm
- rpm - rpm
- libffi-dev - libffi-dev
- golangci-lint - golangci-lint=1.64.8-2
pre-cache: &build_pre_cache pre-cache: &build_pre_cache
- export GOCACHE=/cfsetup_build/.cache/go-build - export GOCACHE=/cfsetup_build/.cache/go-build
- go install golang.org/x/tools/cmd/goimports@v0.30.0 - go install golang.org/x/tools/cmd/goimports@v0.30.0

View File

@ -4,6 +4,7 @@ package main
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -15,7 +16,7 @@ import (
"github.com/cloudflare/cloudflared/logger" "github.com/cloudflare/cloudflared/logger"
) )
func runApp(app *cli.App, graceShutdownC chan struct{}) { func runApp(app *cli.App, _ chan struct{}) {
app.Commands = append(app.Commands, &cli.Command{ app.Commands = append(app.Commands, &cli.Command{
Name: "service", Name: "service",
Usage: "Manages the cloudflared system service", Usage: "Manages the cloudflared system service",
@ -35,7 +36,7 @@ func runApp(app *cli.App, graceShutdownC chan struct{}) {
}, },
}, },
}) })
app.Run(os.Args) _ = app.Run(os.Args)
} }
// The directory and files that are used by the service. // The directory and files that are used by the service.
@ -97,6 +98,7 @@ WantedBy=timers.target
var sysvTemplate = ServiceTemplate{ var sysvTemplate = ServiceTemplate{
Path: "/etc/init.d/cloudflared", Path: "/etc/init.d/cloudflared",
FileMode: 0755, FileMode: 0755,
// nolint: dupword
Content: `#!/bin/sh Content: `#!/bin/sh
# For RedHat and cousins: # For RedHat and cousins:
# chkconfig: 2345 99 01 # chkconfig: 2345 99 01
@ -184,13 +186,11 @@ exit 0
`, `,
} }
var ( var noUpdateServiceFlag = &cli.BoolFlag{
noUpdateServiceFlag = &cli.BoolFlag{
Name: "no-update-service", Name: "no-update-service",
Usage: "Disable auto-update of the cloudflared linux service, which restarts the server to upgrade for new versions.", Usage: "Disable auto-update of the cloudflared linux service, which restarts the server to upgrade for new versions.",
Value: false, Value: false,
} }
)
func isSystemd() bool { func isSystemd() bool {
if _, err := os.Stat("/run/systemd/system"); err == nil { if _, err := os.Stat("/run/systemd/system"); err == nil {
@ -430,3 +430,38 @@ func uninstallSysv(log *zerolog.Logger) error {
} }
return nil return nil
} }
func ensureConfigDirExists(configDir string) error {
ok, err := config.FileExists(configDir)
if !ok && err == nil {
err = os.Mkdir(configDir, 0755)
}
return err
}
func copyFile(src, dest string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()
destFile, err := os.Create(dest)
if err != nil {
return err
}
ok := false
defer func() {
destFile.Close()
if !ok {
_ = os.Remove(dest)
}
}()
if _, err := io.Copy(destFile, srcFile); err != nil {
return err
}
ok = true
return nil
}

View File

@ -11,8 +11,6 @@ import (
"text/template" "text/template"
homedir "github.com/mitchellh/go-homedir" homedir "github.com/mitchellh/go-homedir"
"github.com/cloudflare/cloudflared/config"
) )
type ServiceTemplate struct { type ServiceTemplate struct {
@ -109,38 +107,3 @@ func runCommand(command string, args ...string) error {
} }
return nil return nil
} }
func ensureConfigDirExists(configDir string) error {
ok, err := config.FileExists(configDir)
if !ok && err == nil {
err = os.Mkdir(configDir, 0755)
}
return err
}
func copyFile(src, dest string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()
destFile, err := os.Create(dest)
if err != nil {
return err
}
ok := false
defer func() {
destFile.Close()
if !ok {
_ = os.Remove(dest)
}
}()
if _, err := io.Copy(destFile, srcFile); err != nil {
return err
}
ok = true
return nil
}

View File

@ -761,7 +761,7 @@ func runCommand(c *cli.Context) error {
if tokenFile := c.String(TunnelTokenFileFlag); tokenFile != "" { if tokenFile := c.String(TunnelTokenFileFlag); tokenFile != "" {
data, err := os.ReadFile(tokenFile) data, err := os.ReadFile(tokenFile)
if err != nil { if err != nil {
return cliutil.UsageError("Failed to read token file: " + err.Error()) return cliutil.UsageError("Failed to read token file: %s", err.Error())
} }
tokenStr = strings.TrimSpace(string(data)) tokenStr = strings.TrimSpace(string(data))
} }

View File

@ -190,7 +190,7 @@ func installWindowsService(c *cli.Context) error {
log := zeroLogger.With().Str(LogFieldWindowsServiceName, windowsServiceName).Logger() log := zeroLogger.With().Str(LogFieldWindowsServiceName, windowsServiceName).Logger()
if err == nil { if err == nil {
s.Close() s.Close()
return fmt.Errorf(serviceAlreadyExistsWarn(windowsServiceName)) return errors.New(serviceAlreadyExistsWarn(windowsServiceName))
} }
extraArgs, err := getServiceExtraArgsFromCliArgs(c, &log) extraArgs, err := getServiceExtraArgsFromCliArgs(c, &log)
if err != nil { if err != nil {
@ -238,7 +238,7 @@ func uninstallWindowsService(c *cli.Context) error {
defer m.Disconnect() defer m.Disconnect()
s, err := m.OpenService(windowsServiceName) s, err := m.OpenService(windowsServiceName)
if err != nil { if err != nil {
return fmt.Errorf("Agent service %s is not installed, so it could not be uninstalled", windowsServiceName) return fmt.Errorf("agent service %s is not installed, so it could not be uninstalled", windowsServiceName)
} }
defer s.Close() defer s.Close()

View File

@ -27,13 +27,11 @@ import (
"github.com/cloudflare/cloudflared/tunnelrpc/pogs" "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
) )
var ( var testTransport = http2.Transport{}
testTransport = http2.Transport{}
)
func newTestHTTP2Connection() (*HTTP2Connection, net.Conn) { func newTestHTTP2Connection() (*HTTP2Connection, net.Conn) {
edgeConn, cfdConn := net.Pipe() edgeConn, cfdConn := net.Pipe()
var connIndex = uint8(0) connIndex := uint8(0)
log := zerolog.Nop() log := zerolog.Nop()
obs := NewObserver(&log, &log) obs := NewObserver(&log, &log)
controlStream := NewControlStream( controlStream := NewControlStream(
@ -63,7 +61,7 @@ func newTestHTTP2Connection() (*HTTP2Connection, net.Conn) {
func TestHTTP2ConfigurationSet(t *testing.T) { func TestHTTP2ConfigurationSet(t *testing.T) {
http2Conn, edgeConn := newTestHTTP2Connection() http2Conn, edgeConn := newTestHTTP2Connection()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -131,7 +129,7 @@ func TestServeHTTP(t *testing.T) {
http2Conn, edgeConn := newTestHTTP2Connection() http2Conn, edgeConn := newTestHTTP2Connection()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -262,7 +260,7 @@ func (w *wsRespWriter) close() {
func TestServeWS(t *testing.T) { func TestServeWS(t *testing.T) {
http2Conn, _ := newTestHTTP2Connection() http2Conn, _ := newTestHTTP2Connection()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
respWriter := newWSRespWriter() respWriter := newWSRespWriter()
readPipe, writePipe := io.Pipe() readPipe, writePipe := io.Pipe()
@ -302,7 +300,7 @@ func TestServeWS(t *testing.T) {
func TestNoWriteAfterServeHTTPReturns(t *testing.T) { func TestNoWriteAfterServeHTTPReturns(t *testing.T) {
cfdHTTP2Conn, edgeTCPConn := newTestHTTP2Connection() cfdHTTP2Conn, edgeTCPConn := newTestHTTP2Connection()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
serverDone := make(chan struct{}) serverDone := make(chan struct{})
@ -380,7 +378,7 @@ func TestServeControlStream(t *testing.T) {
) )
http2Conn.controlStreamHandler = controlStream http2Conn.controlStreamHandler = controlStream
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -434,7 +432,7 @@ func TestFailRegistration(t *testing.T) {
) )
http2Conn.controlStreamHandler = controlStream http2Conn.controlStreamHandler = controlStream
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -485,7 +483,7 @@ func TestGracefulShutdownHTTP2(t *testing.T) {
http2Conn.controlStreamHandler = controlStream http2Conn.controlStreamHandler = controlStream
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -535,7 +533,7 @@ func TestGracefulShutdownHTTP2(t *testing.T) {
} }
func TestServeTCP_RateLimited(t *testing.T) { func TestServeTCP_RateLimited(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
http2Conn, edgeConn := newTestHTTP2Connection() http2Conn, edgeConn := newTestHTTP2Connection()
var wg sync.WaitGroup var wg sync.WaitGroup
@ -567,7 +565,7 @@ func TestServeTCP_RateLimited(t *testing.T) {
func benchmarkServeHTTP(b *testing.B, test testRequest) { func benchmarkServeHTTP(b *testing.B, test testRequest) {
http2Conn, edgeConn := newTestHTTP2Connection() http2Conn, edgeConn := newTestHTTP2Connection()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(b.Context())
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {

View File

@ -60,7 +60,7 @@ func TestQUICServer(t *testing.T) {
err := wsutil.WriteClientBinary(wsBuf, []byte("Hello")) err := wsutil.WriteClientBinary(wsBuf, []byte("Hello"))
require.NoError(t, err) require.NoError(t, err)
var tests = []struct { tests := []struct {
desc string desc string
dest string dest string
connectionType pogs.ConnectionType connectionType pogs.ConnectionType
@ -150,7 +150,7 @@ func TestQUICServer(t *testing.T) {
for i, test := range tests { for i, test := range tests {
test := test // capture range variable test := test // capture range variable
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
// Start a UDP Listener for QUIC. // Start a UDP Listener for QUIC.
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
require.NoError(t, err) require.NoError(t, err)
@ -194,6 +194,7 @@ func (fakeControlStream) ServeControlStream(ctx context.Context, rw io.ReadWrite
<-ctx.Done() <-ctx.Done()
return nil return nil
} }
func (fakeControlStream) IsStopped() bool { func (fakeControlStream) IsStopped() bool {
return true return true
} }
@ -211,7 +212,7 @@ func quicServer(
session, err := listener.Accept(ctx) session, err := listener.Accept(ctx)
require.NoError(t, err) require.NoError(t, err)
quicStream, err := session.OpenStreamSync(context.Background()) quicStream, err := session.OpenStreamSync(t.Context())
require.NoError(t, err) require.NoError(t, err)
stream := cfdquic.NewSafeStreamCloser(quicStream, defaultQUICTimeout, &log) stream := cfdquic.NewSafeStreamCloser(quicStream, defaultQUICTimeout, &log)
@ -278,7 +279,7 @@ func (moc *mockOriginProxyWithRequest) ProxyHTTP(w ResponseWriter, tr *tracing.T
} }
func TestBuildHTTPRequest(t *testing.T) { func TestBuildHTTPRequest(t *testing.T) {
var tests = []struct { tests := []struct {
name string name string
connectRequest *pogs.ConnectRequest connectRequest *pogs.ConnectRequest
body io.ReadCloser body io.ReadCloser
@ -499,7 +500,7 @@ func TestBuildHTTPRequest(t *testing.T) {
for _, test := range tests { for _, test := range tests {
test := test // capture range variable test := test // capture range variable
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
req, err := buildHTTPRequest(context.Background(), test.connectRequest, test.body, 0, &log) req, err := buildHTTPRequest(t.Context(), test.connectRequest, test.body, 0, &log)
require.NoError(t, err) require.NoError(t, err)
test.req = test.req.WithContext(req.Context()) test.req = test.req.WithContext(req.Context())
require.Equal(t, test.req, req.Request) require.Equal(t, test.req, req.Request)
@ -525,7 +526,7 @@ func TestServeUDPSession(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer udpListener.Close() defer udpListener.Close()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
// Establish QUIC connection with edge // Establish QUIC connection with edge
edgeQUICSessionChan := make(chan quic.Connection) edgeQUICSessionChan := make(chan quic.Connection)
@ -606,7 +607,7 @@ func TestCreateUDPConnReuseSourcePort(t *testing.T) {
// TestTCPProxy_FlowRateLimited tests if the pogs.ConnectResponse returns the expected error and metadata, when a // TestTCPProxy_FlowRateLimited tests if the pogs.ConnectResponse returns the expected error and metadata, when a
// new flow is rate limited. // new flow is rate limited.
func TestTCPProxy_FlowRateLimited(t *testing.T) { func TestTCPProxy_FlowRateLimited(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
// Start a UDP Listener for QUIC. // Start a UDP Listener for QUIC.
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
@ -627,7 +628,7 @@ func TestTCPProxy_FlowRateLimited(t *testing.T) {
session, err := quicListener.Accept(ctx) session, err := quicListener.Accept(ctx)
assert.NoError(t, err) assert.NoError(t, err)
quicStream, err := session.OpenStreamSync(context.Background()) quicStream, err := session.OpenStreamSync(t.Context())
assert.NoError(t, err) assert.NoError(t, err)
stream := cfdquic.NewSafeStreamCloser(quicStream, defaultQUICTimeout, &log) stream := cfdquic.NewSafeStreamCloser(quicStream, defaultQUICTimeout, &log)
@ -688,9 +689,7 @@ func testCreateUDPConnReuseSourcePortForEdgeIP(t *testing.T, edgeIP netip.AddrPo
} }
func serveSession(ctx context.Context, datagramConn *datagramV2Connection, edgeQUICSession quic.Connection, closeType closeReason, expectedReason string, t *testing.T) { func serveSession(ctx context.Context, datagramConn *datagramV2Connection, edgeQUICSession quic.Connection, closeType closeReason, expectedReason string, t *testing.T) {
var ( payload := []byte(t.Name())
payload = []byte(t.Name())
)
sessionID := uuid.New() sessionID := uuid.New()
cfdConn, originConn := net.Pipe() cfdConn, originConn := net.Pipe()
// Registers and run a new session // Registers and run a new session
@ -803,7 +802,7 @@ func testTunnelConnection(t *testing.T, serverAddr netip.AddrPort, index uint8)
} }
// Start a mock httpProxy // Start a mock httpProxy
log := zerolog.New(io.Discard) log := zerolog.New(io.Discard)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
defer cancel() defer cancel()
// Dial the QUIC connection to the edge // Dial the QUIC connection to the edge

View File

@ -16,8 +16,7 @@ import (
"github.com/cloudflare/cloudflared/mocks" "github.com/cloudflare/cloudflared/mocks"
) )
type mockQuicConnection struct { type mockQuicConnection struct{}
}
func (m *mockQuicConnection) AcceptStream(_ context.Context) (quic.Stream, error) { func (m *mockQuicConnection) AcceptStream(_ context.Context) (quic.Stream, error) {
return nil, nil return nil, nil
@ -71,6 +70,10 @@ func (m *mockQuicConnection) ReceiveDatagram(_ context.Context) ([]byte, error)
return nil, nil return nil, nil
} }
func (m *mockQuicConnection) AddPath(*quic.Transport) (*quic.Path, error) {
return nil, nil
}
func TestRateLimitOnNewDatagramV2UDPSession(t *testing.T) { func TestRateLimitOnNewDatagramV2UDPSession(t *testing.T) {
log := zerolog.Nop() log := zerolog.Nop()
conn := &mockQuicConnection{} conn := &mockQuicConnection{}
@ -78,7 +81,7 @@ func TestRateLimitOnNewDatagramV2UDPSession(t *testing.T) {
flowLimiterMock := mocks.NewMockLimiter(ctrl) flowLimiterMock := mocks.NewMockLimiter(ctrl)
datagramConn := NewDatagramV2Connection( datagramConn := NewDatagramV2Connection(
context.Background(), t.Context(),
conn, conn,
nil, nil,
0, 0,
@ -91,6 +94,6 @@ func TestRateLimitOnNewDatagramV2UDPSession(t *testing.T) {
flowLimiterMock.EXPECT().Acquire("udp").Return(cfdflow.ErrTooManyActiveFlows) flowLimiterMock.EXPECT().Acquire("udp").Return(cfdflow.ErrTooManyActiveFlows)
flowLimiterMock.EXPECT().Release().Times(0) flowLimiterMock.EXPECT().Release().Times(0)
_, err := datagramConn.RegisterUdpSession(context.Background(), uuid.New(), net.IPv4(0, 0, 0, 0), 1000, 1*time.Second, "") _, err := datagramConn.RegisterUdpSession(t.Context(), uuid.New(), net.IPv4(0, 0, 0, 0), 1000, 1*time.Second, "")
require.ErrorIs(t, err, cfdflow.ErrTooManyActiveFlows) require.ErrorIs(t, err, cfdflow.ErrTooManyActiveFlows)
} }

View File

@ -35,12 +35,10 @@ func TestCloseIdle(t *testing.T) {
} }
func testSessionReturns(t *testing.T, closeBy closeMethod, closeAfterIdle time.Duration) { func testSessionReturns(t *testing.T, closeBy closeMethod, closeAfterIdle time.Duration) {
var ( localCloseReason := &errClosedSession{
localCloseReason = &errClosedSession{
message: "connection closed by origin", message: "connection closed by origin",
byRemote: false, byRemote: false,
} }
)
sessionID := uuid.New() sessionID := uuid.New()
cfdConn, originConn := net.Pipe() cfdConn, originConn := net.Pipe()
payload := testPayload(sessionID) payload := testPayload(sessionID)
@ -49,7 +47,7 @@ func testSessionReturns(t *testing.T, closeBy closeMethod, closeAfterIdle time.D
mg := NewManager(&log, nil, nil) mg := NewManager(&log, nil, nil)
session := mg.newSession(sessionID, cfdConn) session := mg.newSession(sessionID, cfdConn)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
sessionDone := make(chan struct{}) sessionDone := make(chan struct{})
go func() { go func() {
closedByRemote, err := session.Serve(ctx, closeAfterIdle) closedByRemote, err := session.Serve(ctx, closeAfterIdle)
@ -128,7 +126,7 @@ func testActiveSessionNotClosed(t *testing.T, readFromDst bool, writeToDst bool)
startTime := time.Now() startTime := time.Now()
activeUntil := startTime.Add(activeTime) activeUntil := startTime.Add(activeTime)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
errGroup, ctx := errgroup.WithContext(ctx) errGroup, ctx := errgroup.WithContext(ctx)
errGroup.Go(func() error { errGroup.Go(func() error {
_, _ = session.Serve(ctx, closeAfterIdle) _, _ = session.Serve(ctx, closeAfterIdle)
@ -211,7 +209,7 @@ func TestZeroBytePayload(t *testing.T) {
mg := NewManager(&nopLogger, sender.muxSession, nil) mg := NewManager(&nopLogger, sender.muxSession, nil)
session := mg.newSession(sessionID, cfdConn) session := mg.newSession(sessionID, cfdConn)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
errGroup, ctx := errgroup.WithContext(ctx) errGroup, ctx := errgroup.WithContext(ctx)
errGroup.Go(func() error { errGroup.Go(func() error {
// Read from underlying conn and send to transport // Read from underlying conn and send to transport

View File

@ -1,10 +0,0 @@
FROM golang:1.22.10 as builder
ENV GO111MODULE=on \
CGO_ENABLED=0
WORKDIR /go/src/github.com/cloudflare/cloudflared/
RUN apt-get update
COPY . .
RUN .teamcity/install-cloudflare-go.sh
# compile cloudflared
RUN PATH="/tmp/go/bin:$PATH" make cloudflared
RUN cp /go/src/github.com/cloudflare/cloudflared/cloudflared /usr/local/bin/

View File

@ -77,7 +77,7 @@ func TestFeaturePrecedenceEvaluationPostQuantum(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
resolver := &staticResolver{record: featuresRecord{}} resolver := &staticResolver{record: featuresRecord{}}
selector, err := newFeatureSelector(context.Background(), test.name, &logger, resolver, []string{}, test.cli, time.Second) selector, err := newFeatureSelector(t.Context(), test.name, &logger, resolver, []string{}, test.cli, time.Second)
require.NoError(t, err) require.NoError(t, err)
snapshot := selector.Snapshot() snapshot := selector.Snapshot()
require.ElementsMatch(t, test.expectedFeatures, snapshot.FeaturesList) require.ElementsMatch(t, test.expectedFeatures, snapshot.FeaturesList)
@ -121,7 +121,7 @@ func TestFeaturePrecedenceEvaluationDatagramVersion(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
resolver := &staticResolver{record: test.remote} resolver := &staticResolver{record: test.remote}
selector, err := newFeatureSelector(context.Background(), test.name, &logger, resolver, test.cli, false, time.Second) selector, err := newFeatureSelector(t.Context(), test.name, &logger, resolver, test.cli, false, time.Second)
require.NoError(t, err) require.NoError(t, err)
snapshot := selector.Snapshot() snapshot := selector.Snapshot()
require.ElementsMatch(t, test.expectedFeatures, snapshot.FeaturesList) require.ElementsMatch(t, test.expectedFeatures, snapshot.FeaturesList)
@ -155,7 +155,7 @@ func TestDeprecatedFeaturesRemoved(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
resolver := &staticResolver{record: test.remote} resolver := &staticResolver{record: test.remote}
selector, err := newFeatureSelector(context.Background(), test.name, &logger, resolver, test.cli, false, time.Second) selector, err := newFeatureSelector(t.Context(), test.name, &logger, resolver, test.cli, false, time.Second)
require.NoError(t, err) require.NoError(t, err)
snapshot := selector.Snapshot() snapshot := selector.Snapshot()
require.ElementsMatch(t, test.expectedFeatures, snapshot.FeaturesList) require.ElementsMatch(t, test.expectedFeatures, snapshot.FeaturesList)
@ -180,7 +180,7 @@ func TestRefreshFeaturesRecord(t *testing.T) {
} }
// Manually progress the next refresh // Manually progress the next refresh
_ = selector.refresh(context.Background()) _ = selector.refresh(t.Context())
} }
// Make sure a resolver error doesn't override the last fetched features // Make sure a resolver error doesn't override the last fetched features
@ -197,7 +197,7 @@ func TestSnapshotIsolation(t *testing.T) {
require.Equal(t, DatagramV2, snapshot.DatagramVersion) require.Equal(t, DatagramV2, snapshot.DatagramVersion)
// Manually progress the next refresh // Manually progress the next refresh
_ = selector.refresh(context.Background()) _ = selector.refresh(t.Context())
snapshot2 := selector.Snapshot() snapshot2 := selector.Snapshot()
require.Equal(t, DatagramV3, snapshot2.DatagramVersion) require.Equal(t, DatagramV3, snapshot2.DatagramVersion)
@ -224,7 +224,7 @@ func newTestSelector(t *testing.T, percentages []uint32, pq bool, refreshFreq ti
percentages: percentages, percentages: percentages,
} }
selector, err := newFeatureSelector(context.Background(), testAccountTag, &logger, resolver, []string{}, pq, refreshFreq) selector, err := newFeatureSelector(t.Context(), testAccountTag, &logger, resolver, []string{}, pq, refreshFreq)
require.NoError(t, err) require.NoError(t, err)
return selector return selector

45
go.mod
View File

@ -1,6 +1,6 @@
module github.com/cloudflare/cloudflared module github.com/cloudflare/cloudflared
go 1.22 go 1.24
require ( require (
github.com/coredns/coredns v1.11.3 github.com/coredns/coredns v1.11.3
@ -12,7 +12,7 @@ require (
github.com/getsentry/sentry-go v0.16.0 github.com/getsentry/sentry-go v0.16.0
github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/chi/v5 v5.0.8
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/go-jose/go-jose/v4 v4.0.1 github.com/go-jose/go-jose/v4 v4.1.0
github.com/gobwas/ws v1.2.1 github.com/gobwas/ws v1.2.1
github.com/google/gopacket v1.1.19 github.com/google/gopacket v1.1.19
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
@ -24,9 +24,9 @@ require (
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_golang v1.19.1
github.com/prometheus/client_model v0.6.0 github.com/prometheus/client_model v0.6.0
github.com/quic-go/quic-go v0.45.0 github.com/quic-go/quic-go v0.51.0
github.com/rs/zerolog v1.20.0 github.com/rs/zerolog v1.20.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
go.opentelemetry.io/contrib/propagators v0.22.0 go.opentelemetry.io/contrib/propagators v0.22.0
go.opentelemetry.io/otel v1.26.0 go.opentelemetry.io/otel v1.26.0
@ -34,14 +34,14 @@ require (
go.opentelemetry.io/otel/sdk v1.26.0 go.opentelemetry.io/otel/sdk v1.26.0
go.opentelemetry.io/otel/trace v1.26.0 go.opentelemetry.io/otel/trace v1.26.0
go.opentelemetry.io/proto/otlp v1.2.0 go.opentelemetry.io/proto/otlp v1.2.0
go.uber.org/automaxprocs v1.4.0 go.uber.org/automaxprocs v1.6.0
go.uber.org/mock v0.5.0 go.uber.org/mock v0.5.1
golang.org/x/crypto v0.31.0 golang.org/x/crypto v0.37.0
golang.org/x/net v0.26.0 golang.org/x/net v0.39.0
golang.org/x/sync v0.10.0 golang.org/x/sync v0.13.0
golang.org/x/sys v0.28.0 golang.org/x/sys v0.32.0
golang.org/x/term v0.27.0 golang.org/x/term v0.31.0
google.golang.org/protobuf v1.34.1 google.golang.org/protobuf v1.36.5
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
nhooyr.io/websocket v1.8.7 nhooyr.io/websocket v1.8.7
@ -61,35 +61,32 @@ require (
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/pool v0.2.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
github.com/klauspost/compress v1.15.11 // indirect github.com/klauspost/compress v1.15.11 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect github.com/onsi/ginkgo/v2 v2.23.4 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.53.0 // indirect github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
go.opentelemetry.io/otel/metric v1.26.0 // indirect go.opentelemetry.io/otel/metric v1.26.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.24.0 // indirect
golang.org/x/mod v0.18.0 // indirect golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/text v0.24.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.32.0 // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
google.golang.org/grpc v1.63.2 // indirect google.golang.org/grpc v1.63.2 // indirect
@ -104,4 +101,4 @@ replace github.com/prometheus/golang_client => github.com/prometheus/golang_clie
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
// This fork is based on quic-go v0.45 // This fork is based on quic-go v0.45
replace github.com/quic-go/quic-go => github.com/chungthuang/quic-go v0.45.1-0.20250128102735-2687bd175910 replace github.com/quic-go/quic-go => github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd

120
go.sum
View File

@ -7,8 +7,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chungthuang/quic-go v0.45.1-0.20250128102735-2687bd175910 h1:/hTvBpxBDj/3NIzTodi1oEOyNBpirvgDSPKSV7VqAZU= github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd h1:VdYI5zFQ2h1/qzoC6rhyPx479bkF8i177Qpg4Q2n1vk=
github.com/chungthuang/quic-go v0.45.1-0.20250128102735-2687bd175910/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0=
github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4=
github.com/coredns/coredns v1.11.3 h1:8RjnpZc42db5th84/QJKH2i137ecJdzZK1HJwhetSPk= github.com/coredns/coredns v1.11.3 h1:8RjnpZc42db5th84/QJKH2i137ecJdzZK1HJwhetSPk=
@ -21,7 +21,6 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
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.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@ -55,11 +54,11 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -72,8 +71,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
@ -89,20 +88,17 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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-cmp v0.5.6/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 h1:b/8HpQhvKLSNzH5oTXN2WkNcMl6YB5K3FRbb+i+Ml34=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20250418163039-24c5476c6587/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -121,11 +117,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
@ -150,10 +143,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
@ -167,6 +160,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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 v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
@ -187,10 +182,9 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
@ -198,7 +192,6 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/contrib/propagators v0.22.0 h1:KGdv58M2//veiYLIhb31mofaI2LgkIPXXAZVeYVyfd8= go.opentelemetry.io/contrib/propagators v0.22.0 h1:KGdv58M2//veiYLIhb31mofaI2LgkIPXXAZVeYVyfd8=
go.opentelemetry.io/contrib/propagators v0.22.0/go.mod h1:xGOuXr6lLIF9BXipA4pm6UuOSI0M98U6tsI3khbOiwU= go.opentelemetry.io/contrib/propagators v0.22.0/go.mod h1:xGOuXr6lLIF9BXipA4pm6UuOSI0M98U6tsI3khbOiwU=
go.opentelemetry.io/otel v1.0.0-RC2/go.mod h1:w1thVQ7qbAy8MHb0IFj8a5Q2QU0l2ksf8u/CN8m3NOM= go.opentelemetry.io/otel v1.0.0-RC2/go.mod h1:w1thVQ7qbAy8MHb0IFj8a5Q2QU0l2ksf8u/CN8m3NOM=
@ -215,85 +208,60 @@ go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2L
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-20190423024810-112230192c58/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=

View File

@ -1,4 +1,4 @@
//go:build windows //go:build windows && cgo
package ingress package ingress

View File

@ -113,7 +113,7 @@ func ParseIngressFromConfigAndCLI(conf *config.Configuration, c *cli.Context, lo
// If no token is provided, the probability of NOT being a remotely managed tunnel is higher. // If no token is provided, the probability of NOT being a remotely managed tunnel is higher.
// So, we should warn the user that no ingress rules were found, because remote configuration will most likely not exist. // So, we should warn the user that no ingress rules were found, because remote configuration will most likely not exist.
if !c.IsSet("token") { if !c.IsSet("token") {
log.Warn().Msgf(ErrNoIngressRulesCLI.Error()) log.Warn().Msg(ErrNoIngressRulesCLI.Error())
} }
return newDefaultOrigin(c, log), nil return newDefaultOrigin(c, log), nil
} }
@ -378,17 +378,17 @@ func validateHostname(r config.UnvalidatedIngressRule, ruleIndex, totalRules int
} }
// ONLY the last rule should catch all hostnames. // ONLY the last rule should catch all hostnames.
if !isLastRule && isCatchAllRule { if !isLastRule && isCatchAllRule {
return errRuleShouldNotBeCatchAll{index: ruleIndex, hostname: r.Hostname} return ruleShouldNotBeCatchAllError{index: ruleIndex, hostname: r.Hostname}
} }
return nil return nil
} }
type errRuleShouldNotBeCatchAll struct { type ruleShouldNotBeCatchAllError struct {
index int index int
hostname string hostname string
} }
func (e errRuleShouldNotBeCatchAll) Error() string { func (e ruleShouldNotBeCatchAllError) Error() string {
return fmt.Sprintf("Rule #%d is matching the hostname '%s', but "+ return fmt.Sprintf("Rule #%d is matching the hostname '%s', but "+
"this will match every hostname, meaning the rules which follow it "+ "this will match every hostname, meaning the rules which follow it "+
"will never be triggered.", e.index+1, e.hostname) "will never be triggered.", e.index+1, e.hostname)

View File

@ -66,7 +66,7 @@ func (o *httpService) SetOriginServerName(req *http.Request) {
} }
return tls.Client(conn, &tls.Config{ return tls.Client(conn, &tls.Config{
RootCAs: o.transport.TLSClientConfig.RootCAs, RootCAs: o.transport.TLSClientConfig.RootCAs,
InsecureSkipVerify: o.transport.TLSClientConfig.InsecureSkipVerify, InsecureSkipVerify: o.transport.TLSClientConfig.InsecureSkipVerify, // nolint: gosec
ServerName: req.Host, ServerName: req.Host,
}), nil }), nil
} }
@ -74,7 +74,7 @@ func (o *httpService) SetOriginServerName(req *http.Request) {
func (o *statusCode) RoundTrip(_ *http.Request) (*http.Response, error) { func (o *statusCode) RoundTrip(_ *http.Request) (*http.Response, error) {
if o.defaultResp { if o.defaultResp {
o.log.Warn().Msgf(ErrNoIngressRulesCLI.Error()) o.log.Warn().Msg(ErrNoIngressRulesCLI.Error())
} }
resp := &http.Response{ resp := &http.Response{
StatusCode: o.code, StatusCode: o.code,
@ -114,7 +114,6 @@ func (o *tcpOverWSService) EstablishConnection(ctx context.Context, dest string,
streamHandler: o.streamHandler, streamHandler: o.streamHandler,
} }
return originConn, nil return originConn, nil
} }
func (o *socksProxyOverWSService) EstablishConnection(_ context.Context, _ string, _ *zerolog.Logger) (OriginConnection, error) { func (o *socksProxyOverWSService) EstablishConnection(_ context.Context, _ string, _ *zerolog.Logger) (OriginConnection, error) {

View File

@ -53,7 +53,7 @@ func TestUpdateConfiguration(t *testing.T) {
initConfig := &Config{ initConfig := &Config{
Ingress: &ingress.Ingress{}, Ingress: &ingress.Ingress{},
} }
orchestrator, err := NewOrchestrator(context.Background(), initConfig, testTags, []ingress.Rule{ingress.NewManagementRule(management.New("management.argotunnel.com", false, "1.1.1.1:80", uuid.Nil, "", &testLogger, nil))}, &testLogger) orchestrator, err := NewOrchestrator(t.Context(), initConfig, testTags, []ingress.Rule{ingress.NewManagementRule(management.New("management.argotunnel.com", false, "1.1.1.1:80", uuid.Nil, "", &testLogger, nil))}, &testLogger)
require.NoError(t, err) require.NoError(t, err)
initOriginProxy, err := orchestrator.GetOriginProxy() initOriginProxy, err := orchestrator.GetOriginProxy()
require.NoError(t, err) require.NoError(t, err)
@ -182,7 +182,7 @@ func TestUpdateConfiguration_FromMigration(t *testing.T) {
initConfig := &Config{ initConfig := &Config{
Ingress: &ingress.Ingress{}, Ingress: &ingress.Ingress{},
} }
orchestrator, err := NewOrchestrator(context.Background(), initConfig, testTags, []ingress.Rule{}, &testLogger) orchestrator, err := NewOrchestrator(t.Context(), initConfig, testTags, []ingress.Rule{}, &testLogger)
require.NoError(t, err) require.NoError(t, err)
initOriginProxy, err := orchestrator.GetOriginProxy() initOriginProxy, err := orchestrator.GetOriginProxy()
require.NoError(t, err) require.NoError(t, err)
@ -208,7 +208,7 @@ func TestUpdateConfiguration_WithoutIngressRule(t *testing.T) {
initConfig := &Config{ initConfig := &Config{
Ingress: &ingress.Ingress{}, Ingress: &ingress.Ingress{},
} }
orchestrator, err := NewOrchestrator(context.Background(), initConfig, testTags, []ingress.Rule{}, &testLogger) orchestrator, err := NewOrchestrator(t.Context(), initConfig, testTags, []ingress.Rule{}, &testLogger)
require.NoError(t, err) require.NoError(t, err)
initOriginProxy, err := orchestrator.GetOriginProxy() initOriginProxy, err := orchestrator.GetOriginProxy()
require.NoError(t, err) require.NoError(t, err)
@ -300,7 +300,7 @@ func TestConcurrentUpdateAndRead(t *testing.T) {
} }
) )
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
defer cancel() defer cancel()
orchestrator, err := NewOrchestrator(ctx, initConfig, testTags, []ingress.Rule{}, &testLogger) orchestrator, err := NewOrchestrator(ctx, initConfig, testTags, []ingress.Rule{}, &testLogger)
@ -393,7 +393,7 @@ func TestConcurrentUpdateAndRead(t *testing.T) {
// TestOverrideWarpRoutingConfigWithLocalValues tests that if a value is defined in the Config.ConfigurationFlags, // TestOverrideWarpRoutingConfigWithLocalValues tests that if a value is defined in the Config.ConfigurationFlags,
// it will override the value that comes from the remote result. // it will override the value that comes from the remote result.
func TestOverrideWarpRoutingConfigWithLocalValues(t *testing.T) { func TestOverrideWarpRoutingConfigWithLocalValues(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
defer cancel() defer cancel()
assertMaxActiveFlows := func(orchestrator *Orchestrator, expectedValue uint64) { assertMaxActiveFlows := func(orchestrator *Orchestrator, expectedValue uint64) {
@ -580,7 +580,7 @@ func TestClosePreviousProxies(t *testing.T) {
} }
) )
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
orchestrator, err := NewOrchestrator(ctx, initConfig, testTags, []ingress.Rule{}, &testLogger) orchestrator, err := NewOrchestrator(ctx, initConfig, testTags, []ingress.Rule{}, &testLogger)
require.NoError(t, err) require.NoError(t, err)
@ -641,7 +641,7 @@ func TestPersistentConnection(t *testing.T) {
initConfig := &Config{ initConfig := &Config{
Ingress: &ingress.Ingress{}, Ingress: &ingress.Ingress{},
} }
orchestrator, err := NewOrchestrator(context.Background(), initConfig, testTags, []ingress.Rule{}, &testLogger) orchestrator, err := NewOrchestrator(t.Context(), initConfig, testTags, []ingress.Rule{}, &testLogger)
require.NoError(t, err) require.NoError(t, err)
wsOrigin := httptest.NewServer(http.HandlerFunc(wsEcho)) wsOrigin := httptest.NewServer(http.HandlerFunc(wsEcho))
@ -674,7 +674,7 @@ func TestPersistentConnection(t *testing.T) {
tcpReqReader, tcpReqWriter := io.Pipe() tcpReqReader, tcpReqWriter := io.Pipe()
tcpRespReadWriter := newRespReadWriteFlusher() tcpRespReadWriter := newRespReadWriteFlusher()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
defer cancel() defer cancel()
var wg sync.WaitGroup var wg sync.WaitGroup

View File

@ -148,7 +148,7 @@ func (w *mockSSERespWriter) ReadBytes() []byte {
func TestProxySingleOrigin(t *testing.T) { func TestProxySingleOrigin(t *testing.T) {
log := zerolog.Nop() log := zerolog.Nop()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
flagSet := flag.NewFlagSet(t.Name(), flag.PanicOnError) flagSet := flag.NewFlagSet(t.Name(), flag.PanicOnError)
flagSet.Bool("hello-world", true, "") flagSet.Bool("hello-world", true, "")
@ -190,7 +190,7 @@ func testProxyWebsocket(proxy connection.OriginProxy) func(t *testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
// WSRoute is a websocket echo handler // WSRoute is a websocket echo handler
const testTimeout = 5 * time.Second * 1000 const testTimeout = 5 * time.Second * 1000
ctx, cancel := context.WithTimeout(context.Background(), testTimeout) ctx, cancel := context.WithTimeout(t.Context(), testTimeout)
defer cancel() defer cancel()
readPipe, writePipe := io.Pipe() readPipe, writePipe := io.Pipe()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("http://localhost:8080%s", hello.WSRoute), readPipe) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("http://localhost:8080%s", hello.WSRoute), readPipe)
@ -257,7 +257,7 @@ func testProxySSE(proxy connection.OriginProxy) func(t *testing.T) {
pushFreq = time.Millisecond * 10 pushFreq = time.Millisecond * 10
) )
responseWriter := newMockSSERespWriter() responseWriter := newMockSSERespWriter()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("http://localhost:8080%s?freq=%s", hello.SSERoute, pushFreq), nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("http://localhost:8080%s?freq=%s", hello.SSERoute, pushFreq), nil)
require.NoError(t, err) require.NoError(t, err)
@ -365,7 +365,7 @@ func runIngressTestScenarios(t *testing.T, unvalidatedIngress []config.Unvalidat
log := zerolog.Nop() log := zerolog.Nop()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
require.NoError(t, ingress.StartOrigins(&log, ctx.Done())) require.NoError(t, ingress.StartOrigins(&log, ctx.Done()))
proxy := NewOriginProxy(ingress, noWarpRouting, testTags, cfdflow.NewLimiter(0), time.Duration(0), &log) proxy := NewOriginProxy(ingress, noWarpRouting, testTags, cfdflow.NewLimiter(0), time.Duration(0), &log)
@ -494,7 +494,7 @@ func TestConnections(t *testing.T) {
err bool err bool
} }
var tests = []struct { tests := []struct {
name string name string
args args args args
want want want want
@ -686,7 +686,7 @@ func TestConnections(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
ln, err := net.Listen("tcp", "127.0.0.1:0") ln, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err) require.NoError(t, err)
// Starts origin service // Starts origin service
@ -755,6 +755,7 @@ func newWSRequestBody(data []byte) *requestBody {
pw: pw, pw: pw,
} }
} }
func newTCPRequestBody(data []byte) *requestBody { func newTCPRequestBody(data []byte) *requestBody {
pr, pw := io.Pipe() pr, pw := io.Pipe()
go func() { go func() {
@ -973,12 +974,12 @@ func runEchoTCPService(t *testing.T, l net.Listener) {
} }
func runEchoWSService(t *testing.T, l net.Listener) { func runEchoWSService(t *testing.T, l net.Listener) {
var upgrader = gorillaWS.Upgrader{ upgrader := gorillaWS.Upgrader{
ReadBufferSize: 10, ReadBufferSize: 10,
WriteBufferSize: 10, WriteBufferSize: 10,
} }
var ws = func(w http.ResponseWriter, r *http.Request) { ws := func(w http.ResponseWriter, r *http.Request) {
header := make(http.Header) header := make(http.Header)
for k, vs := range r.Header { for k, vs := range r.Header {
if k == "Test-Cloudflared-Echo" { if k == "Test-Cloudflared-Echo" {

View File

@ -136,7 +136,7 @@ func TestDatagramConnServe_ApplicationClosed(t *testing.T) {
quic := newMockQuicConn() quic := newMockQuicConn()
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DialUDPAddrPort, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DialUDPAddrPort, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second)
defer cancel() defer cancel()
err := conn.Serve(ctx) err := conn.Serve(ctx)
if !errors.Is(err, context.DeadlineExceeded) { if !errors.Is(err, context.DeadlineExceeded) {
@ -147,12 +147,12 @@ func TestDatagramConnServe_ApplicationClosed(t *testing.T) {
func TestDatagramConnServe_ConnectionClosed(t *testing.T) { func TestDatagramConnServe_ConnectionClosed(t *testing.T) {
log := zerolog.Nop() log := zerolog.Nop()
quic := newMockQuicConn() quic := newMockQuicConn()
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second)
defer cancel() defer cancel()
quic.ctx = ctx quic.ctx = ctx
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DialUDPAddrPort, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DialUDPAddrPort, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
err := conn.Serve(context.Background()) err := conn.Serve(t.Context())
if !errors.Is(err, context.DeadlineExceeded) { if !errors.Is(err, context.DeadlineExceeded) {
t.Fatal(err) t.Fatal(err)
} }
@ -163,7 +163,7 @@ func TestDatagramConnServe_ReceiveDatagramError(t *testing.T) {
quic := &mockQuicConnReadError{err: net.ErrClosed} quic := &mockQuicConnReadError{err: net.ErrClosed}
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DialUDPAddrPort, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DialUDPAddrPort, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
err := conn.Serve(context.Background()) err := conn.Serve(t.Context())
if !errors.Is(err, net.ErrClosed) { if !errors.Is(err, net.ErrClosed) {
t.Fatal(err) t.Fatal(err)
} }
@ -178,7 +178,7 @@ func TestDatagramConnServe_SessionRegistrationRateLimit(t *testing.T) {
conn := v3.NewDatagramConn(quic, sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
defer cancel() defer cancel()
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -230,7 +230,7 @@ func TestDatagramConnServe_ErrorDatagramTypes(t *testing.T) {
quic.send <- test.input quic.send <- test.input
conn := v3.NewDatagramConn(quic, &mockSessionManager{}, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &mockSessionManager{}, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second)
defer cancel() defer cancel()
err := conn.Serve(ctx) err := conn.Serve(ctx)
// we cancel the Serve method to check to see if the log output was written since the unsupported datagram // we cancel the Serve method to check to see if the log output was written since the unsupported datagram
@ -272,7 +272,7 @@ func TestDatagramConnServe_RegisterSession_SessionManagerError(t *testing.T) {
conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -307,7 +307,7 @@ func TestDatagramConnServe(t *testing.T) {
conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -356,7 +356,7 @@ func TestDatagramConnServeDecodeMultipleICMPInParallel(t *testing.T) {
conn := v3.NewDatagramConn(quic, &sessionManager, router, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &sessionManager, router, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -435,7 +435,7 @@ func TestDatagramConnServe_RegisterTwice(t *testing.T) {
conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -499,14 +499,14 @@ func TestDatagramConnServe_MigrateConnection(t *testing.T) {
conn2 := v3.NewDatagramConn(quic2, &sessionManager, &noopICMPRouter{}, 1, &noopMetrics{}, &log) conn2 := v3.NewDatagramConn(quic2, &sessionManager, &noopICMPRouter{}, 1, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
done <- conn.Serve(ctx) done <- conn.Serve(ctx)
}() }()
ctx2, cancel2 := context.WithCancelCause(context.Background()) ctx2, cancel2 := context.WithCancelCause(t.Context())
defer cancel2(errors.New("other error")) defer cancel2(errors.New("other error"))
done2 := make(chan error, 1) done2 := make(chan error, 1)
go func() { go func() {
@ -580,7 +580,7 @@ func TestDatagramConnServe_Payload_GetSessionError(t *testing.T) {
conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -608,7 +608,7 @@ func TestDatagramConnServe_Payload(t *testing.T) {
conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &sessionManager, &noopICMPRouter{}, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -637,7 +637,7 @@ func TestDatagramConnServe_ICMPDatagram_TTLDecremented(t *testing.T) {
conn := v3.NewDatagramConn(quic, &mockSessionManager{}, router, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &mockSessionManager{}, router, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -683,7 +683,7 @@ func TestDatagramConnServe_ICMPDatagram_TTLExceeded(t *testing.T) {
conn := v3.NewDatagramConn(quic, &mockSessionManager{}, router, 0, &noopMetrics{}, &log) conn := v3.NewDatagramConn(quic, &mockSessionManager{}, router, 0, &noopMetrics{}, &log)
// Setup the muxer // Setup the muxer
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(errors.New("other error")) defer cancel(errors.New("other error"))
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {

View File

@ -93,7 +93,7 @@ func testSessionServe_Origin(t *testing.T, payload []byte) {
session := v3.NewSession(testRequestID, 3*time.Second, origin, testOriginAddr, testLocalAddr, &eyeball, &noopMetrics{}, &log) session := v3.NewSession(testRequestID, 3*time.Second, origin, testOriginAddr, testLocalAddr, &eyeball, &noopMetrics{}, &log)
defer session.Close() defer session.Close()
ctx, cancel := context.WithCancelCause(context.Background()) ctx, cancel := context.WithCancelCause(t.Context())
defer cancel(context.Canceled) defer cancel(context.Canceled)
done := make(chan error) done := make(chan error)
go func() { go func() {
@ -143,7 +143,7 @@ func TestSessionServe_OriginTooLarge(t *testing.T) {
done := make(chan error) done := make(chan error)
go func() { go func() {
done <- session.Serve(context.Background()) done <- session.Serve(t.Context())
}() }()
// Attempt to write a payload too large from the origin // Attempt to write a payload too large from the origin
@ -173,7 +173,7 @@ func TestSessionServe_Migrate(t *testing.T) {
defer session.Close() defer session.Close()
done := make(chan error) done := make(chan error)
eyeball1Ctx, cancel := context.WithCancelCause(context.Background()) eyeball1Ctx, cancel := context.WithCancelCause(t.Context())
go func() { go func() {
done <- session.Serve(eyeball1Ctx) done <- session.Serve(eyeball1Ctx)
}() }()
@ -181,7 +181,7 @@ func TestSessionServe_Migrate(t *testing.T) {
// Migrate the session to a new connection before origin sends data // Migrate the session to a new connection before origin sends data
eyeball2 := newMockEyeball() eyeball2 := newMockEyeball()
eyeball2.connID = 1 eyeball2.connID = 1
eyeball2Ctx := context.Background() eyeball2Ctx := t.Context()
session.Migrate(&eyeball2, eyeball2Ctx, &log) session.Migrate(&eyeball2, eyeball2Ctx, &log)
// Cancel the origin eyeball context; this should not cancel the session // Cancel the origin eyeball context; this should not cancel the session
@ -230,7 +230,7 @@ func TestSessionServe_Migrate_CloseContext2(t *testing.T) {
defer session.Close() defer session.Close()
done := make(chan error) done := make(chan error)
eyeball1Ctx, cancel := context.WithCancelCause(context.Background()) eyeball1Ctx, cancel := context.WithCancelCause(t.Context())
go func() { go func() {
done <- session.Serve(eyeball1Ctx) done <- session.Serve(eyeball1Ctx)
}() }()
@ -238,7 +238,7 @@ func TestSessionServe_Migrate_CloseContext2(t *testing.T) {
// Migrate the session to a new connection before origin sends data // Migrate the session to a new connection before origin sends data
eyeball2 := newMockEyeball() eyeball2 := newMockEyeball()
eyeball2.connID = 1 eyeball2.connID = 1
eyeball2Ctx, cancel2 := context.WithCancelCause(context.Background()) eyeball2Ctx, cancel2 := context.WithCancelCause(t.Context())
session.Migrate(&eyeball2, eyeball2Ctx, &log) session.Migrate(&eyeball2, eyeball2Ctx, &log)
// Cancel the origin eyeball context; this should not cancel the session // Cancel the origin eyeball context; this should not cancel the session
@ -316,7 +316,7 @@ func TestSessionServe_IdleTimeout(t *testing.T) {
defer server.Close() defer server.Close()
closeAfterIdle := 2 * time.Second closeAfterIdle := 2 * time.Second
session := v3.NewSession(testRequestID, closeAfterIdle, origin, testOriginAddr, testLocalAddr, &noopEyeball{}, &noopMetrics{}, &log) session := v3.NewSession(testRequestID, closeAfterIdle, origin, testOriginAddr, testLocalAddr, &noopEyeball{}, &noopMetrics{}, &log)
err := session.Serve(context.Background()) err := session.Serve(t.Context())
if !errors.Is(err, v3.SessionIdleErr{}) { if !errors.Is(err, v3.SessionIdleErr{}) {
t.Fatal(err) t.Fatal(err)
} }
@ -342,7 +342,7 @@ func TestSessionServe_ParentContextCanceled(t *testing.T) {
closeAfterIdle := 10 * time.Second closeAfterIdle := 10 * time.Second
session := v3.NewSession(testRequestID, closeAfterIdle, origin, testOriginAddr, testLocalAddr, &noopEyeball{}, &noopMetrics{}, &log) session := v3.NewSession(testRequestID, closeAfterIdle, origin, testOriginAddr, testLocalAddr, &noopEyeball{}, &noopMetrics{}, &log)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) ctx, cancel := context.WithTimeout(t.Context(), 2*time.Second)
defer cancel() defer cancel()
err := session.Serve(ctx) err := session.Serve(ctx)
if !errors.Is(err, context.DeadlineExceeded) { if !errors.Is(err, context.DeadlineExceeded) {
@ -366,7 +366,7 @@ func TestSessionServe_ReadErrors(t *testing.T) {
log := zerolog.Nop() log := zerolog.Nop()
origin := newTestErrOrigin(net.ErrClosed, nil) origin := newTestErrOrigin(net.ErrClosed, nil)
session := v3.NewSession(testRequestID, 30*time.Second, &origin, testOriginAddr, testLocalAddr, &noopEyeball{}, &noopMetrics{}, &log) session := v3.NewSession(testRequestID, 30*time.Second, &origin, testOriginAddr, testLocalAddr, &noopEyeball{}, &noopMetrics{}, &log)
err := session.Serve(context.Background()) err := session.Serve(t.Context())
if !errors.Is(err, net.ErrClosed) { if !errors.Is(err, net.ErrClosed) {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -96,7 +96,7 @@ func (p *UpdateConfigurationResponse) Unmarshal(s proto.UpdateConfigurationRespo
return err return err
} }
if respErr != "" { if respErr != "" {
p.Err = fmt.Errorf(respErr) p.Err = fmt.Errorf("%s", respErr)
} }
return nil return nil
} }

View File

@ -127,7 +127,7 @@ func (p *RegisterUdpSessionResponse) Unmarshal(s proto.RegisterUdpSessionRespons
return err return err
} }
if respErr != "" { if respErr != "" {
p.Err = fmt.Errorf(respErr) p.Err = fmt.Errorf("%s", respErr)
} }
p.Spans, err = s.Spans() p.Spans, err = s.Spans()
if err != nil { if err != nil {
@ -164,7 +164,7 @@ func (c SessionManager_PogsClient) RegisterUdpSession(ctx context.Context, sessi
} }
p.SetDstPort(dstPort) p.SetDstPort(dstPort)
p.SetCloseAfterIdleHint(int64(closeAfterIdleHint)) p.SetCloseAfterIdleHint(int64(closeAfterIdleHint))
p.SetTraceContext(traceContext) _ = p.SetTraceContext(traceContext)
return nil return nil
}) })
result, err := promise.Result().Struct() result, err := promise.Result().Struct()

View File

@ -22,7 +22,7 @@ const (
) )
func TestConnectRequestData(t *testing.T) { func TestConnectRequestData(t *testing.T) {
var tests = []struct { tests := []struct {
name string name string
hostname string hostname string
connectionType pogs.ConnectionType connectionType pogs.ConnectionType
@ -62,7 +62,7 @@ func TestConnectRequestData(t *testing.T) {
} }
func TestConnectResponseMeta(t *testing.T) { func TestConnectResponseMeta(t *testing.T) {
var tests = []struct { tests := []struct {
name string name string
err error err error
metadata []pogs.Metadata metadata []pogs.Metadata
@ -106,7 +106,7 @@ func TestConnectResponseMeta(t *testing.T) {
func TestRegisterUdpSession(t *testing.T) { func TestRegisterUdpSession(t *testing.T) {
unregisterMessage := "closed by eyeball" unregisterMessage := "closed by eyeball"
var tests = []struct { tests := []struct {
name string name string
sessionRPCServer mockSessionRPCServer sessionRPCServer mockSessionRPCServer
}{ }{
@ -140,29 +140,29 @@ func TestRegisterUdpSession(t *testing.T) {
sessionRegisteredChan := make(chan struct{}) sessionRegisteredChan := make(chan struct{})
go func() { go func() {
ss := NewCloudflaredServer(nil, test.sessionRPCServer, nil, 10*time.Second) ss := NewCloudflaredServer(nil, test.sessionRPCServer, nil, 10*time.Second)
err := ss.Serve(context.Background(), serverStream) err := ss.Serve(t.Context(), serverStream)
assert.NoError(t, err) assert.NoError(t, err)
serverStream.Close() serverStream.Close()
close(sessionRegisteredChan) close(sessionRegisteredChan)
}() }()
rpcClientStream, err := NewCloudflaredClient(context.Background(), clientStream, 5*time.Second) rpcClientStream, err := NewCloudflaredClient(t.Context(), clientStream, 5*time.Second)
require.NoError(t, err) require.NoError(t, err)
reg, err := rpcClientStream.RegisterUdpSession(context.Background(), test.sessionRPCServer.sessionID, test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext) reg, err := rpcClientStream.RegisterUdpSession(t.Context(), test.sessionRPCServer.sessionID, test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, reg.Err) require.NoError(t, reg.Err)
// Different sessionID, the RPC server should reject the registration // Different sessionID, the RPC server should reject the registration
reg, err = rpcClientStream.RegisterUdpSession(context.Background(), uuid.New(), test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext) reg, err = rpcClientStream.RegisterUdpSession(t.Context(), uuid.New(), test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext)
require.NoError(t, err) require.NoError(t, err)
require.Error(t, reg.Err) require.Error(t, reg.Err)
require.NoError(t, rpcClientStream.UnregisterUdpSession(context.Background(), test.sessionRPCServer.sessionID, unregisterMessage)) require.NoError(t, rpcClientStream.UnregisterUdpSession(t.Context(), test.sessionRPCServer.sessionID, unregisterMessage))
// Different sessionID, the RPC server should reject the unregistration // Different sessionID, the RPC server should reject the unregistration
require.Error(t, rpcClientStream.UnregisterUdpSession(context.Background(), uuid.New(), unregisterMessage)) require.Error(t, rpcClientStream.UnregisterUdpSession(t.Context(), uuid.New(), unregisterMessage))
rpcClientStream.Close() rpcClientStream.Close()
<-sessionRegisteredChan <-sessionRegisteredChan
@ -185,14 +185,14 @@ func TestManageConfiguration(t *testing.T) {
updatedChan := make(chan struct{}) updatedChan := make(chan struct{})
go func() { go func() {
server := NewCloudflaredServer(nil, nil, configRPCServer, 10*time.Second) server := NewCloudflaredServer(nil, nil, configRPCServer, 10*time.Second)
err := server.Serve(context.Background(), serverStream) err := server.Serve(t.Context(), serverStream)
assert.NoError(t, err) assert.NoError(t, err)
serverStream.Close() serverStream.Close()
close(updatedChan) close(updatedChan)
}() }()
ctx, cancel := context.WithTimeout(context.Background(), time.Second) ctx, cancel := context.WithTimeout(t.Context(), time.Second)
defer cancel() defer cancel()
rpcClientStream, err := NewCloudflaredClient(ctx, clientStream, 5*time.Second) rpcClientStream, err := NewCloudflaredClient(ctx, clientStream, 5*time.Second)
require.NoError(t, err) require.NoError(t, err)

View File

@ -1,3 +1,32 @@
## Changed
- Defined a custom error, ErrUnexpectedSignatureAlgorithm, returned when a JWS
header contains an unsupported signature algorithm.
# v4.0.4
## Fixed
- Reverted "Allow unmarshalling JSONWebKeySets with unsupported key types" as a
breaking change. See #136 / #137.
# v4.0.3
## Changed
- Allow unmarshalling JSONWebKeySets with unsupported key types (#130)
- Document that OpaqueKeyEncrypter can't be implemented (for now) (#129)
- Dependency updates
# v4.0.2
## Changed
- Improved documentation of Verify() to note that JSONWebKeySet is a supported
argument type (#104)
- Defined exported error values for missing x5c header and unsupported elliptic
curves error cases (#117)
# v4.0.1 # v4.0.1
## Fixed ## Fixed

View File

@ -7,9 +7,3 @@ When submitting code, please make every effort to follow existing conventions
and style in order to keep the code as readable as possible. Please also make and style in order to keep the code as readable as possible. Please also make
sure all tests pass by running `go test`, and format your code with `go fmt`. sure all tests pass by running `go test`, and format your code with `go fmt`.
We also recommend using `golint` and `errcheck`. We also recommend using `golint` and `errcheck`.
Before your code can be accepted into the project you must also sign the
Individual Contributor License Agreement. We use [cla-assistant.io][1] and you
will be prompted to sign once a pull request is opened.
[1]: https://cla-assistant.io/

View File

@ -9,14 +9,6 @@ Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. This includes support for JSON Web Encryption, and Encryption set of standards. This includes support for JSON Web Encryption,
JSON Web Signature, and JSON Web Token standards. JSON Web Signature, and JSON Web Token standards.
**Disclaimer**: This library contains encryption software that is subject to
the U.S. Export Administration Regulations. You may not export, re-export,
transfer or download this code or any part of it in violation of any United
States law, directive or regulation. In particular this software may not be
exported or re-exported in any form or on any media to Iran, North Sudan,
Syria, Cuba, or North Korea, or to denied persons or entities mentioned on any
US maintained blocked list.
## Overview ## Overview
The implementation follows the The implementation follows the
@ -109,6 +101,6 @@ allows attaching a key id.
Examples can be found in the Godoc Examples can be found in the Godoc
reference for this package. The reference for this package. The
[`jose-util`](https://github.com/go-jose/go-jose/tree/v4/jose-util) [`jose-util`](https://github.com/go-jose/go-jose/tree/main/jose-util)
subdirectory also contains a small command-line utility which might be useful subdirectory also contains a small command-line utility which might be useful
as an example as well. as an example as well.

View File

@ -459,7 +459,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
return nil, fmt.Errorf("go-jose/go-jose: unsupported crit header") return nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
} }
key := tryJWKS(decryptionKey, obj.Header) key, err := tryJWKS(decryptionKey, obj.Header)
if err != nil {
return nil, err
}
decrypter, err := newDecrypter(key) decrypter, err := newDecrypter(key)
if err != nil { if err != nil {
return nil, err return nil, err
@ -529,7 +532,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: unsupported crit header") return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
} }
key := tryJWKS(decryptionKey, obj.Header) key, err := tryJWKS(decryptionKey, obj.Header)
if err != nil {
return -1, Header{}, nil, err
}
decrypter, err := newDecrypter(key) decrypter, err := newDecrypter(key)
if err != nil { if err != nil {
return -1, Header{}, nil, err return -1, Header{}, nil, err

View File

@ -288,10 +288,11 @@ func ParseEncryptedCompact(
keyAlgorithms []KeyAlgorithm, keyAlgorithms []KeyAlgorithm,
contentEncryption []ContentEncryption, contentEncryption []ContentEncryption,
) (*JSONWebEncryption, error) { ) (*JSONWebEncryption, error) {
parts := strings.Split(input, ".") // Five parts is four separators
if len(parts) != 5 { if strings.Count(input, ".") != 4 {
return nil, fmt.Errorf("go-jose/go-jose: compact JWE format must have five parts") return nil, fmt.Errorf("go-jose/go-jose: compact JWE format must have five parts")
} }
parts := strings.SplitN(input, ".", 5)
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0]) rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil { if err != nil {

View File

@ -239,10 +239,10 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
keyPub = key keyPub = key
} }
} else { } else {
err = fmt.Errorf("go-jose/go-jose: unknown curve %s'", raw.Crv) return fmt.Errorf("go-jose/go-jose: unknown curve %s'", raw.Crv)
} }
default: default:
err = fmt.Errorf("go-jose/go-jose: unknown json web key type '%s'", raw.Kty) return fmt.Errorf("go-jose/go-jose: unknown json web key type '%s'", raw.Kty)
} }
if err != nil { if err != nil {
@ -779,7 +779,13 @@ func (key rawJSONWebKey) symmetricKey() ([]byte, error) {
return key.K.bytes(), nil return key.K.bytes(), nil
} }
func tryJWKS(key interface{}, headers ...Header) interface{} { var (
// ErrJWKSKidNotFound is returned when a JWKS does not contain a JWK with a
// key ID which matches one in the provided tokens headers.
ErrJWKSKidNotFound = errors.New("go-jose/go-jose: JWK with matching kid not found in JWK Set")
)
func tryJWKS(key interface{}, headers ...Header) (interface{}, error) {
var jwks JSONWebKeySet var jwks JSONWebKeySet
switch jwksType := key.(type) { switch jwksType := key.(type) {
@ -788,9 +794,11 @@ func tryJWKS(key interface{}, headers ...Header) interface{} {
case JSONWebKeySet: case JSONWebKeySet:
jwks = jwksType jwks = jwksType
default: default:
return key // If the specified key is not a JWKS, return as is.
return key, nil
} }
// Determine the KID to search for from the headers.
var kid string var kid string
for _, header := range headers { for _, header := range headers {
if header.KeyID != "" { if header.KeyID != "" {
@ -799,14 +807,17 @@ func tryJWKS(key interface{}, headers ...Header) interface{} {
} }
} }
// If no KID is specified in the headers, reject.
if kid == "" { if kid == "" {
return key return nil, ErrJWKSKidNotFound
} }
// Find the JWK with the matching KID. If no JWK with the specified KID is
// found, reject.
keys := jwks.Key(kid) keys := jwks.Key(kid)
if len(keys) == 0 { if len(keys) == 0 {
return key return nil, ErrJWKSKidNotFound
} }
return keys[0].Key return keys[0].Key, nil
} }

View File

@ -75,7 +75,14 @@ type Signature struct {
original *rawSignatureInfo original *rawSignatureInfo
} }
// ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization. // ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization. Validation fails if
// the JWS is signed with an algorithm that isn't in the provided list of signature algorithms.
// Applications should decide for themselves which signature algorithms are acceptable. If you're
// not sure which signature algorithms your application might receive, consult the documentation of
// the program which provides them or the protocol that you are implementing. You can also try
// getting an example JWS and decoding it with a tool like https://jwt.io to see what its "alg"
// header parameter indicates. The signature on the JWS does not get validated during parsing. Call
// Verify() after parsing to validate the signature and obtain the payload.
// //
// https://datatracker.ietf.org/doc/html/rfc7515#section-7 // https://datatracker.ietf.org/doc/html/rfc7515#section-7
func ParseSigned( func ParseSigned(
@ -90,7 +97,14 @@ func ParseSigned(
return parseSignedCompact(signature, nil, signatureAlgorithms) return parseSignedCompact(signature, nil, signatureAlgorithms)
} }
// ParseSignedCompact parses a message in JWS Compact Serialization. // ParseSignedCompact parses a message in JWS Compact Serialization. Validation fails if the JWS is
// signed with an algorithm that isn't in the provided list of signature algorithms. Applications
// should decide for themselves which signature algorithms are acceptable.If you're not sure which
// signature algorithms your application might receive, consult the documentation of the program
// which provides them or the protocol that you are implementing. You can also try getting an
// example JWS and decoding it with a tool like https://jwt.io to see what its "alg" header
// parameter indicates. The signature on the JWS does not get validated during parsing. Call
// Verify() after parsing to validate the signature and obtain the payload.
// //
// https://datatracker.ietf.org/doc/html/rfc7515#section-7.1 // https://datatracker.ietf.org/doc/html/rfc7515#section-7.1
func ParseSignedCompact( func ParseSignedCompact(
@ -101,6 +115,15 @@ func ParseSignedCompact(
} }
// ParseDetached parses a signed message in compact serialization format with detached payload. // ParseDetached parses a signed message in compact serialization format with detached payload.
// Validation fails if the JWS is signed with an algorithm that isn't in the provided list of
// signature algorithms. Applications should decide for themselves which signature algorithms are
// acceptable. If you're not sure which signature algorithms your application might receive, consult
// the documentation of the program which provides them or the protocol that you are implementing.
// You can also try getting an example JWS and decoding it with a tool like https://jwt.io to see
// what its "alg" header parameter indicates. The signature on the JWS does not get validated during
// parsing. Call Verify() after parsing to validate the signature and obtain the payload.
//
// https://datatracker.ietf.org/doc/html/rfc7515#appendix-F
func ParseDetached( func ParseDetached(
signature string, signature string,
payload []byte, payload []byte,
@ -181,6 +204,25 @@ func containsSignatureAlgorithm(haystack []SignatureAlgorithm, needle SignatureA
return false return false
} }
// ErrUnexpectedSignatureAlgorithm is returned when the signature algorithm in
// the JWS header does not match one of the expected algorithms.
type ErrUnexpectedSignatureAlgorithm struct {
// Got is the signature algorithm found in the JWS header.
Got SignatureAlgorithm
expected []SignatureAlgorithm
}
func (e *ErrUnexpectedSignatureAlgorithm) Error() string {
return fmt.Sprintf("unexpected signature algorithm %q; expected %q", e.Got, e.expected)
}
func newErrUnexpectedSignatureAlgorithm(got SignatureAlgorithm, expected []SignatureAlgorithm) error {
return &ErrUnexpectedSignatureAlgorithm{
Got: got,
expected: expected,
}
}
// sanitized produces a cleaned-up JWS object from the raw JSON. // sanitized produces a cleaned-up JWS object from the raw JSON.
func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgorithm) (*JSONWebSignature, error) { func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgorithm) (*JSONWebSignature, error) {
if len(signatureAlgorithms) == 0 { if len(signatureAlgorithms) == 0 {
@ -236,8 +278,7 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
alg := SignatureAlgorithm(signature.Header.Algorithm) alg := SignatureAlgorithm(signature.Header.Algorithm)
if !containsSignatureAlgorithm(signatureAlgorithms, alg) { if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q", return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
alg, signatureAlgorithms)
} }
if signature.header != nil { if signature.header != nil {
@ -285,8 +326,7 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm) alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
if !containsSignatureAlgorithm(signatureAlgorithms, alg) { if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q", return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
alg, signatureAlgorithms)
} }
if obj.Signatures[i].header != nil { if obj.Signatures[i].header != nil {
@ -327,10 +367,11 @@ func parseSignedCompact(
payload []byte, payload []byte,
signatureAlgorithms []SignatureAlgorithm, signatureAlgorithms []SignatureAlgorithm,
) (*JSONWebSignature, error) { ) (*JSONWebSignature, error) {
parts := strings.Split(input, ".") // Three parts is two separators
if len(parts) != 3 { if strings.Count(input, ".") != 2 {
return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts") return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
} }
parts := strings.SplitN(input, ".", 3)
if parts[1] != "" && payload != nil { if parts[1] != "" && payload != nil {
return nil, fmt.Errorf("go-jose/go-jose: payload is not detached") return nil, fmt.Errorf("go-jose/go-jose: payload is not detached")

View File

@ -83,6 +83,9 @@ func (o *opaqueVerifier) verifyPayload(payload []byte, signature []byte, alg Sig
} }
// OpaqueKeyEncrypter is an interface that supports encrypting keys with an opaque key. // OpaqueKeyEncrypter is an interface that supports encrypting keys with an opaque key.
//
// Note: this cannot currently be implemented outside this package because of its
// unexported method.
type OpaqueKeyEncrypter interface { type OpaqueKeyEncrypter interface {
// KeyID returns the kid // KeyID returns the kid
KeyID() string KeyID() string

View File

@ -71,6 +71,12 @@ var (
// ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a // ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a
// nonce header parameter was included in an unprotected header object. // nonce header parameter was included in an unprotected header object.
ErrUnprotectedNonce = errors.New("go-jose/go-jose: Nonce parameter included in unprotected header") ErrUnprotectedNonce = errors.New("go-jose/go-jose: Nonce parameter included in unprotected header")
// ErrMissingX5cHeader indicates that the JWT header is missing x5c headers.
ErrMissingX5cHeader = errors.New("go-jose/go-jose: no x5c header present in message")
// ErrUnsupportedEllipticCurve indicates unsupported or unknown elliptic curve has been found.
ErrUnsupportedEllipticCurve = errors.New("go-jose/go-jose: unsupported/unknown elliptic curve")
) )
// Key management algorithms // Key management algorithms
@ -199,7 +205,7 @@ type Header struct {
// not be validated with the given verify options. // not be validated with the given verify options.
func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) { func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) {
if len(h.certificates) == 0 { if len(h.certificates) == 0 {
return nil, errors.New("go-jose/go-jose: no x5c header present in message") return nil, ErrMissingX5cHeader
} }
leaf := h.certificates[0] leaf := h.certificates[0]
@ -501,7 +507,7 @@ func curveName(crv elliptic.Curve) (string, error) {
case elliptic.P521(): case elliptic.P521():
return "P-521", nil return "P-521", nil
default: default:
return "", fmt.Errorf("go-jose/go-jose: unsupported/unknown elliptic curve") return "", ErrUnsupportedEllipticCurve
} }
} }

View File

@ -358,6 +358,8 @@ func (ctx *genericSigner) Options() SignerOptions {
// - *rsa.PublicKey // - *rsa.PublicKey
// - *JSONWebKey // - *JSONWebKey
// - JSONWebKey // - JSONWebKey
// - *JSONWebKeySet
// - JSONWebKeySet
// - []byte (an HMAC key) // - []byte (an HMAC key)
// - Any type that implements the OpaqueVerifier interface. // - Any type that implements the OpaqueVerifier interface.
// //
@ -388,7 +390,10 @@ func (obj JSONWebSignature) UnsafePayloadWithoutVerification() []byte {
// The verificationKey argument must have one of the types allowed for the // The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify(). // verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error { func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error {
key := tryJWKS(verificationKey, obj.headers()...) key, err := tryJWKS(verificationKey, obj.headers()...)
if err != nil {
return err
}
verifier, err := newVerifier(key) verifier, err := newVerifier(key)
if err != nil { if err != nil {
return err return err
@ -453,7 +458,10 @@ func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signa
// The verificationKey argument must have one of the types allowed for the // The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify(). // verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) { func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) {
key := tryJWKS(verificationKey, obj.headers()...) key, err := tryJWKS(verificationKey, obj.headers()...)
if err != nil {
return -1, Signature{}, err
}
verifier, err := newVerifier(key) verifier, err := newVerifier(key)
if err != nil { if err != nil {
return -1, Signature{}, err return -1, Signature{}, err

View File

@ -21,6 +21,7 @@ import (
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/hmac" "crypto/hmac"
"crypto/pbkdf2"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
@ -30,8 +31,6 @@ import (
"hash" "hash"
"io" "io"
"golang.org/x/crypto/pbkdf2"
josecipher "github.com/go-jose/go-jose/v4/cipher" josecipher "github.com/go-jose/go-jose/v4/cipher"
) )
@ -330,7 +329,10 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
// derive key // derive key
keyLen, h := getPbkdf2Params(alg) keyLen, h := getPbkdf2Params(alg)
key := pbkdf2.Key(ctx.key, salt, ctx.p2c, keyLen, h) key, err := pbkdf2.Key(h, string(ctx.key), salt, ctx.p2c, keyLen)
if err != nil {
return recipientInfo{}, nil
}
// use AES cipher with derived key // use AES cipher with derived key
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)
@ -432,7 +434,10 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
// derive key // derive key
keyLen, h := getPbkdf2Params(alg) keyLen, h := getPbkdf2Params(alg)
key := pbkdf2.Key(ctx.key, salt, p2c, keyLen, h) key, err := pbkdf2.Key(h, string(ctx.key), salt, p2c, keyLen)
if err != nil {
return nil, err
}
// use AES cipher with derived key // use AES cipher with derived key
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)

View File

@ -1,6 +1,7 @@
# A minimal logging API for Go # A minimal logging API for Go
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr) [![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-logr/logr)](https://goreportcard.com/report/github.com/go-logr/logr)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)
logr offers an(other) opinion on how Go programs and libraries can do logging logr offers an(other) opinion on how Go programs and libraries can do logging

View File

@ -240,11 +240,10 @@ type Formatter struct {
prefix string prefix string
values []any values []any
valuesStr string valuesStr string
parentValuesStr string
depth int depth int
opts *Options opts *Options
group string // for slog groups groupName string // for slog groups
groupDepth int groups []groupDef
} }
// outputFormat indicates which outputFormat to use. // outputFormat indicates which outputFormat to use.
@ -257,6 +256,13 @@ const (
outputJSON outputJSON
) )
// groupDef represents a saved group. The values may be empty, but we don't
// know if we need to render the group until the final record is rendered.
type groupDef struct {
name string
values string
}
// PseudoStruct is a list of key-value pairs that gets logged as a struct. // PseudoStruct is a list of key-value pairs that gets logged as a struct.
type PseudoStruct []any type PseudoStruct []any
@ -264,76 +270,102 @@ type PseudoStruct []any
func (f Formatter) render(builtins, args []any) string { func (f Formatter) render(builtins, args []any) string {
// Empirically bytes.Buffer is faster than strings.Builder for this. // Empirically bytes.Buffer is faster than strings.Builder for this.
buf := bytes.NewBuffer(make([]byte, 0, 1024)) buf := bytes.NewBuffer(make([]byte, 0, 1024))
if f.outputFormat == outputJSON { if f.outputFormat == outputJSON {
buf.WriteByte('{') // for the whole line buf.WriteByte('{') // for the whole record
} }
// Render builtins
vals := builtins vals := builtins
if hook := f.opts.RenderBuiltinsHook; hook != nil { if hook := f.opts.RenderBuiltinsHook; hook != nil {
vals = hook(f.sanitize(vals)) vals = hook(f.sanitize(vals))
} }
f.flatten(buf, vals, false, false) // keys are ours, no need to escape f.flatten(buf, vals, false) // keys are ours, no need to escape
continuing := len(builtins) > 0 continuing := len(builtins) > 0
if f.parentValuesStr != "" { // Turn the inner-most group into a string
if continuing { argsStr := func() string {
buf.WriteByte(f.comma()) buf := bytes.NewBuffer(make([]byte, 0, 1024))
}
buf.WriteString(f.parentValuesStr)
continuing = true
}
groupDepth := f.groupDepth
if f.group != "" {
if f.valuesStr != "" || len(args) != 0 {
if continuing {
buf.WriteByte(f.comma())
}
buf.WriteString(f.quoted(f.group, true)) // escape user-provided keys
buf.WriteByte(f.colon())
buf.WriteByte('{') // for the group
continuing = false
} else {
// The group was empty
groupDepth--
}
}
if f.valuesStr != "" {
if continuing {
buf.WriteByte(f.comma())
}
buf.WriteString(f.valuesStr)
continuing = true
}
vals = args vals = args
if hook := f.opts.RenderArgsHook; hook != nil { if hook := f.opts.RenderArgsHook; hook != nil {
vals = hook(f.sanitize(vals)) vals = hook(f.sanitize(vals))
} }
f.flatten(buf, vals, continuing, true) // escape user-provided keys f.flatten(buf, vals, true) // escape user-provided keys
for i := 0; i < groupDepth; i++ { return buf.String()
buf.WriteByte('}') // for the groups }()
// Render the stack of groups from the inside out.
bodyStr := f.renderGroup(f.groupName, f.valuesStr, argsStr)
for i := len(f.groups) - 1; i >= 0; i-- {
grp := &f.groups[i]
if grp.values == "" && bodyStr == "" {
// no contents, so we must elide the whole group
continue
}
bodyStr = f.renderGroup(grp.name, grp.values, bodyStr)
}
if bodyStr != "" {
if continuing {
buf.WriteByte(f.comma())
}
buf.WriteString(bodyStr)
} }
if f.outputFormat == outputJSON { if f.outputFormat == outputJSON {
buf.WriteByte('}') // for the whole line buf.WriteByte('}') // for the whole record
} }
return buf.String() return buf.String()
} }
// flatten renders a list of key-value pairs into a buffer. If continuing is // renderGroup returns a string representation of the named group with rendered
// true, it assumes that the buffer has previous values and will emit a // values and args. If the name is empty, this will return the values and args,
// separator (which depends on the output format) before the first pair it // joined. If the name is not empty, this will return a single key-value pair,
// writes. If escapeKeys is true, the keys are assumed to have // where the value is a grouping of the values and args. If the values and
// non-JSON-compatible characters in them and must be evaluated for escapes. // args are both empty, this will return an empty string, even if the name was
// specified.
func (f Formatter) renderGroup(name string, values string, args string) string {
buf := bytes.NewBuffer(make([]byte, 0, 1024))
needClosingBrace := false
if name != "" && (values != "" || args != "") {
buf.WriteString(f.quoted(name, true)) // escape user-provided keys
buf.WriteByte(f.colon())
buf.WriteByte('{')
needClosingBrace = true
}
continuing := false
if values != "" {
buf.WriteString(values)
continuing = true
}
if args != "" {
if continuing {
buf.WriteByte(f.comma())
}
buf.WriteString(args)
}
if needClosingBrace {
buf.WriteByte('}')
}
return buf.String()
}
// flatten renders a list of key-value pairs into a buffer. If escapeKeys is
// true, the keys are assumed to have non-JSON-compatible characters in them
// and must be evaluated for escapes.
// //
// This function returns a potentially modified version of kvList, which // This function returns a potentially modified version of kvList, which
// ensures that there is a value for every key (adding a value if needed) and // ensures that there is a value for every key (adding a value if needed) and
// that each key is a string (substituting a key if needed). // that each key is a string (substituting a key if needed).
func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, continuing bool, escapeKeys bool) []any { func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, escapeKeys bool) []any {
// This logic overlaps with sanitize() but saves one type-cast per key, // This logic overlaps with sanitize() but saves one type-cast per key,
// which can be measurable. // which can be measurable.
if len(kvList)%2 != 0 { if len(kvList)%2 != 0 {
@ -354,7 +386,7 @@ func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, continuing bool, esc
} }
v := kvList[i+1] v := kvList[i+1]
if i > 0 || continuing { if i > 0 {
if f.outputFormat == outputJSON { if f.outputFormat == outputJSON {
buf.WriteByte(f.comma()) buf.WriteByte(f.comma())
} else { } else {
@ -766,46 +798,17 @@ func (f Formatter) sanitize(kvList []any) []any {
// startGroup opens a new group scope (basically a sub-struct), which locks all // startGroup opens a new group scope (basically a sub-struct), which locks all
// the current saved values and starts them anew. This is needed to satisfy // the current saved values and starts them anew. This is needed to satisfy
// slog. // slog.
func (f *Formatter) startGroup(group string) { func (f *Formatter) startGroup(name string) {
// Unnamed groups are just inlined. // Unnamed groups are just inlined.
if group == "" { if name == "" {
return return
} }
// Any saved values can no longer be changed. n := len(f.groups)
buf := bytes.NewBuffer(make([]byte, 0, 1024)) f.groups = append(f.groups[:n:n], groupDef{f.groupName, f.valuesStr})
continuing := false
if f.parentValuesStr != "" {
buf.WriteString(f.parentValuesStr)
continuing = true
}
if f.group != "" && f.valuesStr != "" {
if continuing {
buf.WriteByte(f.comma())
}
buf.WriteString(f.quoted(f.group, true)) // escape user-provided keys
buf.WriteByte(f.colon())
buf.WriteByte('{') // for the group
continuing = false
}
if f.valuesStr != "" {
if continuing {
buf.WriteByte(f.comma())
}
buf.WriteString(f.valuesStr)
}
// NOTE: We don't close the scope here - that's done later, when a log line
// is actually rendered (because we have N scopes to close).
f.parentValuesStr = buf.String()
// Start collecting new values. // Start collecting new values.
f.group = group f.groupName = name
f.groupDepth++
f.valuesStr = "" f.valuesStr = ""
f.values = nil f.values = nil
} }
@ -900,7 +903,7 @@ func (f *Formatter) AddValues(kvList []any) {
// Pre-render values, so we don't have to do it on each Info/Error call. // Pre-render values, so we don't have to do it on each Info/Error call.
buf := bytes.NewBuffer(make([]byte, 0, 1024)) buf := bytes.NewBuffer(make([]byte, 0, 1024))
f.flatten(buf, vals, false, true) // escape user-provided keys f.flatten(buf, vals, true) // escape user-provided keys
f.valuesStr = buf.String() f.valuesStr = buf.String()
} }

View File

@ -1,5 +1,24 @@
# Changelog # Changelog
## Release 3.2.3 (2022-11-29)
### Changed
- Updated docs (thanks @book987 @aJetHorn @neelayu @pellizzetti @apricote @SaigyoujiYuyuko233 @AlekSi)
- #348: Updated huandu/xstrings which fixed a snake case bug (thanks @yxxhero)
- #353: Updated masterminds/semver which included bug fixes
- #354: Updated golang.org/x/crypto which included bug fixes
## Release 3.2.2 (2021-02-04)
This is a re-release of 3.2.1 to satisfy something with the Go module system.
## Release 3.2.1 (2021-02-04)
### Changed
- Upgraded `Masterminds/goutils` to `v1.1.1`. see the [Security Advisory](https://github.com/Masterminds/goutils/security/advisories/GHSA-xg2h-wx96-xgxr)
## Release 3.2.0 (2020-12-14) ## Release 3.2.0 (2020-12-14)
### Added ### Added

View File

@ -1,4 +1,4 @@
# Slim-Sprig: Template functions for Go templates [![GoDoc](https://godoc.org/github.com/go-task/slim-sprig?status.svg)](https://godoc.org/github.com/go-task/slim-sprig) [![Go Report Card](https://goreportcard.com/badge/github.com/go-task/slim-sprig)](https://goreportcard.com/report/github.com/go-task/slim-sprig) # Slim-Sprig: Template functions for Go templates [![Go Reference](https://pkg.go.dev/badge/github.com/go-task/slim-sprig/v3.svg)](https://pkg.go.dev/github.com/go-task/slim-sprig/v3)
Slim-Sprig is a fork of [Sprig](https://github.com/Masterminds/sprig), but with Slim-Sprig is a fork of [Sprig](https://github.com/Masterminds/sprig), but with
all functions that depend on external (non standard library) or crypto packages all functions that depend on external (non standard library) or crypto packages

View File

@ -1,6 +1,6 @@
# https://taskfile.dev # https://taskfile.dev
version: '2' version: '3'
tasks: tasks:
default: default:

View File

@ -122,6 +122,7 @@ func (p *Profile) preEncode() {
} }
p.defaultSampleTypeX = addString(strings, p.DefaultSampleType) p.defaultSampleTypeX = addString(strings, p.DefaultSampleType)
p.docURLX = addString(strings, p.DocURL)
p.stringTable = make([]string, len(strings)) p.stringTable = make([]string, len(strings))
for s, i := range strings { for s, i := range strings {
@ -156,6 +157,7 @@ func (p *Profile) encode(b *buffer) {
encodeInt64Opt(b, 12, p.Period) encodeInt64Opt(b, 12, p.Period)
encodeInt64s(b, 13, p.commentX) encodeInt64s(b, 13, p.commentX)
encodeInt64(b, 14, p.defaultSampleTypeX) encodeInt64(b, 14, p.defaultSampleTypeX)
encodeInt64Opt(b, 15, p.docURLX)
} }
var profileDecoder = []decoder{ var profileDecoder = []decoder{
@ -237,6 +239,8 @@ var profileDecoder = []decoder{
func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) }, func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
// int64 defaultSampleType = 14 // int64 defaultSampleType = 14
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) }, func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
// string doc_link = 15;
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).docURLX) },
} }
// postDecode takes the unexported fields populated by decode (with // postDecode takes the unexported fields populated by decode (with
@ -384,6 +388,7 @@ func (p *Profile) postDecode() error {
p.commentX = nil p.commentX = nil
p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err) p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
p.DocURL, err = getString(p.stringTable, &p.docURLX, err)
p.stringTable = nil p.stringTable = nil
return err return err
} }
@ -530,6 +535,7 @@ func (p *Line) decoder() []decoder {
func (p *Line) encode(b *buffer) { func (p *Line) encode(b *buffer) {
encodeUint64Opt(b, 1, p.functionIDX) encodeUint64Opt(b, 1, p.functionIDX)
encodeInt64Opt(b, 2, p.Line) encodeInt64Opt(b, 2, p.Line)
encodeInt64Opt(b, 3, p.Column)
} }
var lineDecoder = []decoder{ var lineDecoder = []decoder{
@ -538,6 +544,8 @@ var lineDecoder = []decoder{
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) }, func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
// optional int64 line = 2 // optional int64 line = 2
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) }, func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
// optional int64 column = 3
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Column) },
} }
func (p *Function) decoder() []decoder { func (p *Function) decoder() []decoder {

View File

@ -56,7 +56,7 @@ func javaCPUProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte
} }
// Strip out addresses for better merge. // Strip out addresses for better merge.
if err = p.Aggregate(true, true, true, true, false); err != nil { if err = p.Aggregate(true, true, true, true, false, false); err != nil {
return nil, err return nil, err
} }
@ -99,7 +99,7 @@ func parseJavaProfile(b []byte) (*Profile, error) {
} }
// Strip out addresses for better merge. // Strip out addresses for better merge.
if err = p.Aggregate(true, true, true, true, false); err != nil { if err = p.Aggregate(true, true, true, true, false, false); err != nil {
return nil, err return nil, err
} }

View File

@ -326,12 +326,13 @@ func (l *Location) key() locationKey {
key.addr -= l.Mapping.Start key.addr -= l.Mapping.Start
key.mappingID = l.Mapping.ID key.mappingID = l.Mapping.ID
} }
lines := make([]string, len(l.Line)*2) lines := make([]string, len(l.Line)*3)
for i, line := range l.Line { for i, line := range l.Line {
if line.Function != nil { if line.Function != nil {
lines[i*2] = strconv.FormatUint(line.Function.ID, 16) lines[i*2] = strconv.FormatUint(line.Function.ID, 16)
} }
lines[i*2+1] = strconv.FormatInt(line.Line, 16) lines[i*2+1] = strconv.FormatInt(line.Line, 16)
lines[i*2+2] = strconv.FormatInt(line.Column, 16)
} }
key.lines = strings.Join(lines, "|") key.lines = strings.Join(lines, "|")
return key return key
@ -418,6 +419,7 @@ func (pm *profileMerger) mapLine(src Line) Line {
ln := Line{ ln := Line{
Function: pm.mapFunction(src.Function), Function: pm.mapFunction(src.Function),
Line: src.Line, Line: src.Line,
Column: src.Column,
} }
return ln return ln
} }
@ -474,6 +476,7 @@ func combineHeaders(srcs []*Profile) (*Profile, error) {
var timeNanos, durationNanos, period int64 var timeNanos, durationNanos, period int64
var comments []string var comments []string
seenComments := map[string]bool{} seenComments := map[string]bool{}
var docURL string
var defaultSampleType string var defaultSampleType string
for _, s := range srcs { for _, s := range srcs {
if timeNanos == 0 || s.TimeNanos < timeNanos { if timeNanos == 0 || s.TimeNanos < timeNanos {
@ -492,6 +495,9 @@ func combineHeaders(srcs []*Profile) (*Profile, error) {
if defaultSampleType == "" { if defaultSampleType == "" {
defaultSampleType = s.DefaultSampleType defaultSampleType = s.DefaultSampleType
} }
if docURL == "" {
docURL = s.DocURL
}
} }
p := &Profile{ p := &Profile{
@ -507,6 +513,7 @@ func combineHeaders(srcs []*Profile) (*Profile, error) {
Comments: comments, Comments: comments,
DefaultSampleType: defaultSampleType, DefaultSampleType: defaultSampleType,
DocURL: docURL,
} }
copy(p.SampleType, srcs[0].SampleType) copy(p.SampleType, srcs[0].SampleType)
return p, nil return p, nil

View File

@ -39,6 +39,7 @@ type Profile struct {
Location []*Location Location []*Location
Function []*Function Function []*Function
Comments []string Comments []string
DocURL string
DropFrames string DropFrames string
KeepFrames string KeepFrames string
@ -53,6 +54,7 @@ type Profile struct {
encodeMu sync.Mutex encodeMu sync.Mutex
commentX []int64 commentX []int64
docURLX int64
dropFramesX int64 dropFramesX int64
keepFramesX int64 keepFramesX int64
stringTable []string stringTable []string
@ -145,6 +147,7 @@ type Location struct {
type Line struct { type Line struct {
Function *Function Function *Function
Line int64 Line int64
Column int64
functionIDX uint64 functionIDX uint64
} }
@ -436,7 +439,7 @@ func (p *Profile) CheckValid() error {
// Aggregate merges the locations in the profile into equivalence // Aggregate merges the locations in the profile into equivalence
// classes preserving the request attributes. It also updates the // classes preserving the request attributes. It also updates the
// samples to point to the merged locations. // samples to point to the merged locations.
func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error { func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, columnnumber, address bool) error {
for _, m := range p.Mapping { for _, m := range p.Mapping {
m.HasInlineFrames = m.HasInlineFrames && inlineFrame m.HasInlineFrames = m.HasInlineFrames && inlineFrame
m.HasFunctions = m.HasFunctions && function m.HasFunctions = m.HasFunctions && function
@ -458,7 +461,7 @@ func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address
} }
// Aggregate locations // Aggregate locations
if !inlineFrame || !address || !linenumber { if !inlineFrame || !address || !linenumber || !columnnumber {
for _, l := range p.Location { for _, l := range p.Location {
if !inlineFrame && len(l.Line) > 1 { if !inlineFrame && len(l.Line) > 1 {
l.Line = l.Line[len(l.Line)-1:] l.Line = l.Line[len(l.Line)-1:]
@ -466,6 +469,12 @@ func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address
if !linenumber { if !linenumber {
for i := range l.Line { for i := range l.Line {
l.Line[i].Line = 0 l.Line[i].Line = 0
l.Line[i].Column = 0
}
}
if !columnnumber {
for i := range l.Line {
l.Line[i].Column = 0
} }
} }
if !address { if !address {
@ -548,6 +557,9 @@ func (p *Profile) String() string {
for _, c := range p.Comments { for _, c := range p.Comments {
ss = append(ss, "Comment: "+c) ss = append(ss, "Comment: "+c)
} }
if url := p.DocURL; url != "" {
ss = append(ss, fmt.Sprintf("Doc: %s", url))
}
if pt := p.PeriodType; pt != nil { if pt := p.PeriodType; pt != nil {
ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit)) ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
} }
@ -627,10 +639,11 @@ func (l *Location) string() string {
for li := range l.Line { for li := range l.Line {
lnStr := "??" lnStr := "??"
if fn := l.Line[li].Function; fn != nil { if fn := l.Line[li].Function; fn != nil {
lnStr = fmt.Sprintf("%s %s:%d s=%d", lnStr = fmt.Sprintf("%s %s:%d:%d s=%d",
fn.Name, fn.Name,
fn.Filename, fn.Filename,
l.Line[li].Line, l.Line[li].Line,
l.Line[li].Column,
fn.StartLine) fn.StartLine)
if fn.Name != fn.SystemName { if fn.Name != fn.SystemName {
lnStr = lnStr + "(" + fn.SystemName + ")" lnStr = lnStr + "(" + fn.SystemName + ")"
@ -836,10 +849,10 @@ func (p *Profile) HasFileLines() bool {
// Unsymbolizable returns true if a mapping points to a binary for which // Unsymbolizable returns true if a mapping points to a binary for which
// locations can't be symbolized in principle, at least now. Examples are // locations can't be symbolized in principle, at least now. Examples are
// "[vdso]", [vsyscall]" and some others, see the code. // "[vdso]", "[vsyscall]" and some others, see the code.
func (m *Mapping) Unsymbolizable() bool { func (m *Mapping) Unsymbolizable() bool {
name := filepath.Base(m.File) name := filepath.Base(m.File)
return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") || m.File == "//anon"
} }
// Copy makes a fully independent copy of a profile. // Copy makes a fully independent copy of a profile.

View File

@ -24,15 +24,15 @@ const (
var SingletonFormatter = New(ColorModeTerminal) var SingletonFormatter = New(ColorModeTerminal)
func F(format string, args ...interface{}) string { func F(format string, args ...any) string {
return SingletonFormatter.F(format, args...) return SingletonFormatter.F(format, args...)
} }
func Fi(indentation uint, format string, args ...interface{}) string { func Fi(indentation uint, format string, args ...any) string {
return SingletonFormatter.Fi(indentation, format, args...) return SingletonFormatter.Fi(indentation, format, args...)
} }
func Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string { func Fiw(indentation uint, maxWidth uint, format string, args ...any) string {
return SingletonFormatter.Fiw(indentation, maxWidth, format, args...) return SingletonFormatter.Fiw(indentation, maxWidth, format, args...)
} }
@ -82,6 +82,10 @@ func New(colorMode ColorMode) Formatter {
return fmt.Sprintf("\x1b[38;5;%dm", colorCode) return fmt.Sprintf("\x1b[38;5;%dm", colorCode)
} }
if _, noColor := os.LookupEnv("GINKGO_NO_COLOR"); noColor {
colorMode = ColorModeNone
}
f := Formatter{ f := Formatter{
ColorMode: colorMode, ColorMode: colorMode,
colors: map[string]string{ colors: map[string]string{
@ -111,15 +115,15 @@ func New(colorMode ColorMode) Formatter {
return f return f
} }
func (f Formatter) F(format string, args ...interface{}) string { func (f Formatter) F(format string, args ...any) string {
return f.Fi(0, format, args...) return f.Fi(0, format, args...)
} }
func (f Formatter) Fi(indentation uint, format string, args ...interface{}) string { func (f Formatter) Fi(indentation uint, format string, args ...any) string {
return f.Fiw(indentation, 0, format, args...) return f.Fiw(indentation, 0, format, args...)
} }
func (f Formatter) Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string { func (f Formatter) Fiw(indentation uint, maxWidth uint, format string, args ...any) string {
out := f.style(format) out := f.style(format)
if len(args) > 0 { if len(args) > 0 {
out = fmt.Sprintf(out, args...) out = fmt.Sprintf(out, args...)

View File

@ -2,6 +2,8 @@ package build
import ( import (
"fmt" "fmt"
"os"
"path"
"github.com/onsi/ginkgo/v2/ginkgo/command" "github.com/onsi/ginkgo/v2/ginkgo/command"
"github.com/onsi/ginkgo/v2/ginkgo/internal" "github.com/onsi/ginkgo/v2/ginkgo/internal"
@ -42,7 +44,7 @@ func buildSpecs(args []string, cliConfig types.CLIConfig, goFlagsConfig types.Go
internal.VerifyCLIAndFrameworkVersion(suites) internal.VerifyCLIAndFrameworkVersion(suites)
opc := internal.NewOrderedParallelCompiler(cliConfig.ComputedNumCompilers()) opc := internal.NewOrderedParallelCompiler(cliConfig.ComputedNumCompilers())
opc.StartCompiling(suites, goFlagsConfig) opc.StartCompiling(suites, goFlagsConfig, true)
for { for {
suiteIdx, suite := opc.Next() suiteIdx, suite := opc.Next()
@ -53,7 +55,22 @@ func buildSpecs(args []string, cliConfig types.CLIConfig, goFlagsConfig types.Go
if suite.State.Is(internal.TestSuiteStateFailedToCompile) { if suite.State.Is(internal.TestSuiteStateFailedToCompile) {
fmt.Println(suite.CompilationError.Error()) fmt.Println(suite.CompilationError.Error())
} else { } else {
fmt.Printf("Compiled %s.test\n", suite.PackageName) var testBinPath string
if len(goFlagsConfig.O) != 0 {
stat, err := os.Stat(goFlagsConfig.O)
if err != nil {
panic(err)
}
if stat.IsDir() {
testBinPath = goFlagsConfig.O + "/" + suite.PackageName + ".test"
} else {
testBinPath = goFlagsConfig.O
}
}
if len(testBinPath) == 0 {
testBinPath = path.Join(suite.Path, suite.PackageName+".test")
}
fmt.Printf("Compiled %s\n", testBinPath)
} }
} }

View File

@ -12,7 +12,7 @@ func Abort(details AbortDetails) {
panic(details) panic(details)
} }
func AbortGracefullyWith(format string, args ...interface{}) { func AbortGracefullyWith(format string, args ...any) {
Abort(AbortDetails{ Abort(AbortDetails{
ExitCode: 0, ExitCode: 0,
Error: fmt.Errorf(format, args...), Error: fmt.Errorf(format, args...),
@ -20,7 +20,7 @@ func AbortGracefullyWith(format string, args ...interface{}) {
}) })
} }
func AbortWith(format string, args ...interface{}) { func AbortWith(format string, args ...any) {
Abort(AbortDetails{ Abort(AbortDetails{
ExitCode: 1, ExitCode: 1,
Error: fmt.Errorf(format, args...), Error: fmt.Errorf(format, args...),
@ -28,7 +28,7 @@ func AbortWith(format string, args ...interface{}) {
}) })
} }
func AbortWithUsage(format string, args ...interface{}) { func AbortWithUsage(format string, args ...any) {
Abort(AbortDetails{ Abort(AbortDetails{
ExitCode: 1, ExitCode: 1,
Error: fmt.Errorf(format, args...), Error: fmt.Errorf(format, args...),

View File

@ -24,7 +24,11 @@ func (c Command) Run(args []string, additionalArgs []string) {
if err != nil { if err != nil {
AbortWithUsage(err.Error()) AbortWithUsage(err.Error())
} }
for _, arg := range args {
if len(arg) > 1 && strings.HasPrefix(arg, "-") {
AbortWith(types.GinkgoErrors.FlagAfterPositionalParameter().Error())
}
}
c.Command(args, additionalArgs) c.Command(args, additionalArgs)
} }

View File

@ -68,7 +68,6 @@ func (p Program) RunAndExit(osArgs []string) {
fmt.Fprintln(p.ErrWriter, deprecationTracker.DeprecationsReport()) fmt.Fprintln(p.ErrWriter, deprecationTracker.DeprecationsReport())
} }
p.Exiter(exitCode) p.Exiter(exitCode)
return
}() }()
args, additionalArgs := []string{}, []string{} args, additionalArgs := []string{}, []string{}
@ -157,7 +156,6 @@ func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) {
p.EmitUsage(writer) p.EmitUsage(writer)
Abort(AbortDetails{ExitCode: 1}) Abort(AbortDetails{ExitCode: 1})
} }
return
} }
func (p Program) EmitUsage(writer io.Writer) { func (p Program) EmitUsage(writer io.Writer) {

View File

@ -7,7 +7,7 @@ import (
"os" "os"
"text/template" "text/template"
sprig "github.com/go-task/slim-sprig" sprig "github.com/go-task/slim-sprig/v3"
"github.com/onsi/ginkgo/v2/ginkgo/command" "github.com/onsi/ginkgo/v2/ginkgo/command"
"github.com/onsi/ginkgo/v2/ginkgo/internal" "github.com/onsi/ginkgo/v2/ginkgo/internal"
"github.com/onsi/ginkgo/v2/types" "github.com/onsi/ginkgo/v2/types"

View File

@ -10,7 +10,7 @@ import (
"strings" "strings"
"text/template" "text/template"
sprig "github.com/go-task/slim-sprig" sprig "github.com/go-task/slim-sprig/v3"
"github.com/onsi/ginkgo/v2/ginkgo/command" "github.com/onsi/ginkgo/v2/ginkgo/command"
"github.com/onsi/ginkgo/v2/ginkgo/internal" "github.com/onsi/ginkgo/v2/ginkgo/internal"
"github.com/onsi/ginkgo/v2/types" "github.com/onsi/ginkgo/v2/types"
@ -174,6 +174,7 @@ func moduleName(modRoot string) string {
if err != nil { if err != nil {
return "" return ""
} }
defer modFile.Close()
mod := make([]byte, 128) mod := make([]byte, 128)
_, err = modFile.Read(mod) _, err = modFile.Read(mod)

View File

@ -11,7 +11,7 @@ import (
"github.com/onsi/ginkgo/v2/types" "github.com/onsi/ginkgo/v2/types"
) )
func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite { func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig, preserveSymbols bool) TestSuite {
if suite.PathToCompiledTest != "" { if suite.PathToCompiledTest != "" {
return suite return suite
} }
@ -25,6 +25,18 @@ func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite
return suite return suite
} }
if len(goFlagsConfig.O) > 0 {
userDefinedPath, err := filepath.Abs(goFlagsConfig.O)
if err != nil {
suite.State = TestSuiteStateFailedToCompile
suite.CompilationError = fmt.Errorf("Failed to compute compilation target path %s:\n%s", goFlagsConfig.O, err.Error())
return suite
}
path = userDefinedPath
}
goFlagsConfig.O = path
ginkgoInvocationPath, _ := os.Getwd() ginkgoInvocationPath, _ := os.Getwd()
ginkgoInvocationPath, _ = filepath.Abs(ginkgoInvocationPath) ginkgoInvocationPath, _ = filepath.Abs(ginkgoInvocationPath)
packagePath := suite.AbsPath() packagePath := suite.AbsPath()
@ -34,7 +46,7 @@ func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite
suite.CompilationError = fmt.Errorf("Failed to get relative path from package to the current working directory:\n%s", err.Error()) suite.CompilationError = fmt.Errorf("Failed to get relative path from package to the current working directory:\n%s", err.Error())
return suite return suite
} }
args, err := types.GenerateGoTestCompileArgs(goFlagsConfig, path, "./", pathToInvocationPath) args, err := types.GenerateGoTestCompileArgs(goFlagsConfig, "./", pathToInvocationPath, preserveSymbols)
if err != nil { if err != nil {
suite.State = TestSuiteStateFailedToCompile suite.State = TestSuiteStateFailedToCompile
suite.CompilationError = fmt.Errorf("Failed to generate go test compile flags:\n%s", err.Error()) suite.CompilationError = fmt.Errorf("Failed to generate go test compile flags:\n%s", err.Error())
@ -108,7 +120,7 @@ func NewOrderedParallelCompiler(numCompilers int) *OrderedParallelCompiler {
} }
} }
func (opc *OrderedParallelCompiler) StartCompiling(suites TestSuites, goFlagsConfig types.GoFlagsConfig) { func (opc *OrderedParallelCompiler) StartCompiling(suites TestSuites, goFlagsConfig types.GoFlagsConfig, preserveSymbols bool) {
opc.stopped = false opc.stopped = false
opc.idx = 0 opc.idx = 0
opc.numSuites = len(suites) opc.numSuites = len(suites)
@ -123,7 +135,7 @@ func (opc *OrderedParallelCompiler) StartCompiling(suites TestSuites, goFlagsCon
stopped := opc.stopped stopped := opc.stopped
opc.mutex.Unlock() opc.mutex.Unlock()
if !stopped { if !stopped {
suite = CompileSuite(suite, goFlagsConfig) suite = CompileSuite(suite, goFlagsConfig, preserveSymbols)
} }
c <- suite c <- suite
} }

View File

@ -0,0 +1,129 @@
// Copyright (c) 2015, Wade Simmons
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Package gocovmerge takes the results from multiple `go test -coverprofile`
// runs and merges them into one profile
// this file was originally taken from the gocovmerge project
// see also: https://go.shabbyrobe.org/gocovmerge
package internal
import (
"fmt"
"io"
"sort"
"golang.org/x/tools/cover"
)
func AddCoverProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile {
i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName })
if i < len(profiles) && profiles[i].FileName == p.FileName {
MergeCoverProfiles(profiles[i], p)
} else {
profiles = append(profiles, nil)
copy(profiles[i+1:], profiles[i:])
profiles[i] = p
}
return profiles
}
func DumpCoverProfiles(profiles []*cover.Profile, out io.Writer) error {
if len(profiles) == 0 {
return nil
}
if _, err := fmt.Fprintf(out, "mode: %s\n", profiles[0].Mode); err != nil {
return err
}
for _, p := range profiles {
for _, b := range p.Blocks {
if _, err := fmt.Fprintf(out, "%s:%d.%d,%d.%d %d %d\n", p.FileName, b.StartLine, b.StartCol, b.EndLine, b.EndCol, b.NumStmt, b.Count); err != nil {
return err
}
}
}
return nil
}
func MergeCoverProfiles(into *cover.Profile, merge *cover.Profile) error {
if into.Mode != merge.Mode {
return fmt.Errorf("cannot merge profiles with different modes")
}
// Since the blocks are sorted, we can keep track of where the last block
// was inserted and only look at the blocks after that as targets for merge
startIndex := 0
for _, b := range merge.Blocks {
var err error
startIndex, err = mergeProfileBlock(into, b, startIndex)
if err != nil {
return err
}
}
return nil
}
func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) (int, error) {
sortFunc := func(i int) bool {
pi := p.Blocks[i+startIndex]
return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol)
}
i := 0
if !sortFunc(i) {
i = sort.Search(len(p.Blocks)-startIndex, sortFunc)
}
i += startIndex
if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol {
if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol {
return i, fmt.Errorf("gocovmerge: overlapping merge %v %v %v", p.FileName, p.Blocks[i], pb)
}
switch p.Mode {
case "set":
p.Blocks[i].Count |= pb.Count
case "count", "atomic":
p.Blocks[i].Count += pb.Count
default:
return i, fmt.Errorf("gocovmerge: unsupported covermode '%s'", p.Mode)
}
} else {
if i > 0 {
pa := p.Blocks[i-1]
if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) {
return i, fmt.Errorf("gocovmerge: overlap before %v %v %v", p.FileName, pa, pb)
}
}
if i < len(p.Blocks)-1 {
pa := p.Blocks[i+1]
if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) {
return i, fmt.Errorf("gocovmerge: overlap after %v %v %v", p.FileName, pa, pb)
}
}
p.Blocks = append(p.Blocks, cover.ProfileBlock{})
copy(p.Blocks[i+1:], p.Blocks[i:])
p.Blocks[i] = pb
}
return i + 1, nil
}

View File

@ -1,7 +1,6 @@
package internal package internal
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
@ -12,6 +11,7 @@ import (
"github.com/google/pprof/profile" "github.com/google/pprof/profile"
"github.com/onsi/ginkgo/v2/reporters" "github.com/onsi/ginkgo/v2/reporters"
"github.com/onsi/ginkgo/v2/types" "github.com/onsi/ginkgo/v2/types"
"golang.org/x/tools/cover"
) )
func AbsPathForGeneratedAsset(assetName string, suite TestSuite, cliConfig types.CLIConfig, process int) string { func AbsPathForGeneratedAsset(assetName string, suite TestSuite, cliConfig types.CLIConfig, process int) string {
@ -144,38 +144,27 @@ func FinalizeProfilesAndReportsForSuites(suites TestSuites, cliConfig types.CLIC
return messages, nil return messages, nil
} }
//loads each profile, combines them, deletes them, stores them in destination // loads each profile, merges them, deletes them, stores them in destination
func MergeAndCleanupCoverProfiles(profiles []string, destination string) error { func MergeAndCleanupCoverProfiles(profiles []string, destination string) error {
combined := &bytes.Buffer{} var merged []*cover.Profile
modeRegex := regexp.MustCompile(`^mode: .*\n`) for _, file := range profiles {
for i, profile := range profiles { parsedProfiles, err := cover.ParseProfiles(file)
contents, err := os.ReadFile(profile)
if err != nil { if err != nil {
return fmt.Errorf("Unable to read coverage file %s:\n%s", profile, err.Error()) return err
} }
os.Remove(profile) os.Remove(file)
for _, p := range parsedProfiles {
// remove the cover mode line from every file merged = AddCoverProfile(merged, p)
// except the first one
if i > 0 {
contents = modeRegex.ReplaceAll(contents, []byte{})
} }
_, err = combined.Write(contents)
// Add a newline to the end of every file if missing.
if err == nil && len(contents) > 0 && contents[len(contents)-1] != '\n' {
_, err = combined.Write([]byte("\n"))
} }
dst, err := os.OpenFile(destination, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil { if err != nil {
return fmt.Errorf("Unable to append to coverprofile:\n%s", err.Error()) return err
} }
} defer dst.Close()
err = DumpCoverProfiles(merged, dst)
err := os.WriteFile(destination, combined.Bytes(), 0666)
if err != nil { if err != nil {
return fmt.Errorf("Unable to create combined cover profile:\n%s", err.Error()) return err
} }
return nil return nil
} }
@ -184,7 +173,7 @@ func GetCoverageFromCoverProfile(profile string) (float64, error) {
cmd := exec.Command("go", "tool", "cover", "-func", profile) cmd := exec.Command("go", "tool", "cover", "-func", profile)
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return 0, fmt.Errorf("Could not process Coverprofile %s: %s", profile, err.Error()) return 0, fmt.Errorf("Could not process Coverprofile %s: %s - %s", profile, err.Error(), string(output))
} }
re := regexp.MustCompile(`total:\s*\(statements\)\s*(\d*\.\d*)\%`) re := regexp.MustCompile(`total:\s*\(statements\)\s*(\d*\.\d*)\%`)
matches := re.FindStringSubmatch(string(output)) matches := re.FindStringSubmatch(string(output))
@ -208,6 +197,7 @@ func MergeProfiles(profilePaths []string, destination string) error {
return fmt.Errorf("Could not open profile: %s\n%s", profilePath, err.Error()) return fmt.Errorf("Could not open profile: %s\n%s", profilePath, err.Error())
} }
prof, err := profile.Parse(proFile) prof, err := profile.Parse(proFile)
_ = proFile.Close()
if err != nil { if err != nil {
return fmt.Errorf("Could not parse profile: %s\n%s", profilePath, err.Error()) return fmt.Errorf("Could not parse profile: %s\n%s", profilePath, err.Error())
} }

View File

@ -7,6 +7,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"strings" "strings"
"github.com/onsi/ginkgo/v2/types" "github.com/onsi/ginkgo/v2/types"
@ -192,7 +193,7 @@ func precompiledTestSuite(path string) (TestSuite, error) {
return TestSuite{}, errors.New("this is not a .test binary") return TestSuite{}, errors.New("this is not a .test binary")
} }
if filepath.Ext(path) == ".test" && info.Mode()&0111 == 0 { if filepath.Ext(path) == ".test" && runtime.GOOS != "windows" && info.Mode()&0111 == 0 {
return TestSuite{}, errors.New("this is not executable") return TestSuite{}, errors.New("this is not executable")
} }
@ -225,7 +226,7 @@ func suitesInDir(dir string, recurse bool) TestSuites {
files, _ := os.ReadDir(dir) files, _ := os.ReadDir(dir)
re := regexp.MustCompile(`^[^._].*_test\.go$`) re := regexp.MustCompile(`^[^._].*_test\.go$`)
for _, file := range files { for _, file := range files {
if !file.IsDir() && re.Match([]byte(file.Name())) { if !file.IsDir() && re.MatchString(file.Name()) {
suite := TestSuite{ suite := TestSuite{
Path: relPath(dir), Path: relPath(dir),
PackageName: packageNameForSuite(dir), PackageName: packageNameForSuite(dir),
@ -240,7 +241,7 @@ func suitesInDir(dir string, recurse bool) TestSuites {
if recurse { if recurse {
re = regexp.MustCompile(`^[._]`) re = regexp.MustCompile(`^[._]`)
for _, file := range files { for _, file := range files {
if file.IsDir() && !re.Match([]byte(file.Name())) { if file.IsDir() && !re.MatchString(file.Name()) {
suites = append(suites, suitesInDir(dir+"/"+file.Name(), recurse)...) suites = append(suites, suitesInDir(dir+"/"+file.Name(), recurse)...)
} }
} }
@ -271,7 +272,7 @@ func filesHaveGinkgoSuite(dir string, files []os.DirEntry) bool {
reGinkgo := regexp.MustCompile(`package ginkgo|\/ginkgo"|\/ginkgo\/v2"|\/ginkgo\/v2/dsl/`) reGinkgo := regexp.MustCompile(`package ginkgo|\/ginkgo"|\/ginkgo\/v2"|\/ginkgo\/v2/dsl/`)
for _, file := range files { for _, file := range files {
if !file.IsDir() && reTestFile.Match([]byte(file.Name())) { if !file.IsDir() && reTestFile.MatchString(file.Name()) {
contents, _ := os.ReadFile(dir + "/" + file.Name()) contents, _ := os.ReadFile(dir + "/" + file.Name())
if reGinkgo.Match(contents) { if reGinkgo.Match(contents) {
return true return true

View File

@ -3,7 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
_ "go.uber.org/automaxprocs"
"github.com/onsi/ginkgo/v2/ginkgo/build" "github.com/onsi/ginkgo/v2/ginkgo/build"
"github.com/onsi/ginkgo/v2/ginkgo/command" "github.com/onsi/ginkgo/v2/ginkgo/command"
"github.com/onsi/ginkgo/v2/ginkgo/generators" "github.com/onsi/ginkgo/v2/ginkgo/generators"

View File

@ -1,10 +1,11 @@
package outline package outline
import ( import (
"github.com/onsi/ginkgo/v2/types"
"go/ast" "go/ast"
"go/token" "go/token"
"strconv" "strconv"
"github.com/onsi/ginkgo/v2/types"
) )
const ( const (

View File

@ -28,14 +28,7 @@ func packageNameForImport(f *ast.File, path string) *string {
} }
name := spec.Name.String() name := spec.Name.String()
if name == "<nil>" { if name == "<nil>" {
// If the package name is not explicitly specified, name = "ginkgo"
// make an educated guess. This is not guaranteed to be correct.
lastSlash := strings.LastIndex(path, "/")
if lastSlash == -1 {
name = path
} else {
name = path[lastSlash+1:]
}
} }
if name == "." { if name == "." {
name = "" name = ""

View File

@ -1,10 +1,13 @@
package outline package outline
import ( import (
"bytes"
"encoding/csv"
"encoding/json" "encoding/json"
"fmt" "fmt"
"go/ast" "go/ast"
"go/token" "go/token"
"strconv"
"strings" "strings"
"golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/ast/inspector"
@ -84,9 +87,11 @@ func (o *outline) String() string {
// StringIndent returns a CSV-formated outline, but every line is indented by // StringIndent returns a CSV-formated outline, but every line is indented by
// one 'width' of spaces for every level of nesting. // one 'width' of spaces for every level of nesting.
func (o *outline) StringIndent(width int) string { func (o *outline) StringIndent(width int) string {
var b strings.Builder var b bytes.Buffer
b.WriteString("Name,Text,Start,End,Spec,Focused,Pending,Labels\n") b.WriteString("Name,Text,Start,End,Spec,Focused,Pending,Labels\n")
csvWriter := csv.NewWriter(&b)
currentIndent := 0 currentIndent := 0
pre := func(n *ginkgoNode) { pre := func(n *ginkgoNode) {
b.WriteString(fmt.Sprintf("%*s", currentIndent, "")) b.WriteString(fmt.Sprintf("%*s", currentIndent, ""))
@ -96,8 +101,22 @@ func (o *outline) StringIndent(width int) string {
} else { } else {
labels = strings.Join(n.Labels, ", ") labels = strings.Join(n.Labels, ", ")
} }
//enclosing labels in a double quoted comma separate listed so that when inmported into a CSV app the Labels column has comma separate strings
b.WriteString(fmt.Sprintf("%s,%s,%d,%d,%t,%t,%t,\"%s\"\n", n.Name, n.Text, n.Start, n.End, n.Spec, n.Focused, n.Pending, labels)) row := []string{
n.Name,
n.Text,
strconv.Itoa(n.Start),
strconv.Itoa(n.End),
strconv.FormatBool(n.Spec),
strconv.FormatBool(n.Focused),
strconv.FormatBool(n.Pending),
labels,
}
csvWriter.Write(row)
// Ensure we write to `b' before the next `b.WriteString()', which might be adding indentation
csvWriter.Flush()
currentIndent += width currentIndent += width
} }
post := func(n *ginkgoNode) { post := func(n *ginkgoNode) {
@ -106,5 +125,6 @@ func (o *outline) StringIndent(width int) string {
for _, n := range o.Nodes { for _, n := range o.Nodes {
n.Walk(pre, post) n.Walk(pre, post)
} }
return b.String() return b.String()
} }

View File

@ -107,7 +107,7 @@ OUTER_LOOP:
} }
opc := internal.NewOrderedParallelCompiler(r.cliConfig.ComputedNumCompilers()) opc := internal.NewOrderedParallelCompiler(r.cliConfig.ComputedNumCompilers())
opc.StartCompiling(suites, r.goFlagsConfig) opc.StartCompiling(suites, r.goFlagsConfig, false)
SUITE_LOOP: SUITE_LOOP:
for { for {
@ -142,7 +142,7 @@ OUTER_LOOP:
} }
if !endTime.IsZero() { if !endTime.IsZero() {
r.suiteConfig.Timeout = endTime.Sub(time.Now()) r.suiteConfig.Timeout = time.Until(endTime)
if r.suiteConfig.Timeout <= 0 { if r.suiteConfig.Timeout <= 0 {
suites[suiteIdx].State = internal.TestSuiteStateFailedDueToTimeout suites[suiteIdx].State = internal.TestSuiteStateFailedDueToTimeout
opc.StopAndDrain() opc.StopAndDrain()

View File

@ -78,7 +78,7 @@ func (d Dependencies) resolveAndAdd(deps []string, depth int) {
if err != nil { if err != nil {
continue continue
} }
if !pkg.Goroot && (!ginkgoAndGomegaFilter.Match([]byte(pkg.Dir)) || ginkgoIntegrationTestFilter.Match([]byte(pkg.Dir))) { if !pkg.Goroot && (!ginkgoAndGomegaFilter.MatchString(pkg.Dir) || ginkgoIntegrationTestFilter.MatchString(pkg.Dir)) {
d.addDepIfNotPresent(pkg.Dir, depth) d.addDepIfNotPresent(pkg.Dir, depth)
} }
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"regexp" "regexp"
"strings"
"time" "time"
) )
@ -79,7 +80,11 @@ func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Ti
continue continue
} }
if goTestRegExp.Match([]byte(info.Name())) { if isHiddenFile(info) {
continue
}
if goTestRegExp.MatchString(info.Name()) {
testHash += p.hashForFileInfo(info) testHash += p.hashForFileInfo(info)
if info.ModTime().After(testModifiedTime) { if info.ModTime().After(testModifiedTime) {
testModifiedTime = info.ModTime() testModifiedTime = info.ModTime()
@ -87,7 +92,7 @@ func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Ti
continue continue
} }
if p.watchRegExp.Match([]byte(info.Name())) { if p.watchRegExp.MatchString(info.Name()) {
codeHash += p.hashForFileInfo(info) codeHash += p.hashForFileInfo(info)
if info.ModTime().After(codeModifiedTime) { if info.ModTime().After(codeModifiedTime) {
codeModifiedTime = info.ModTime() codeModifiedTime = info.ModTime()
@ -103,6 +108,10 @@ func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Ti
return return
} }
func isHiddenFile(info os.FileInfo) bool {
return strings.HasPrefix(info.Name(), ".") || strings.HasPrefix(info.Name(), "_")
}
func (p *PackageHash) hashForFileInfo(info os.FileInfo) string { func (p *PackageHash) hashForFileInfo(info os.FileInfo) string {
return fmt.Sprintf("%s_%d_%d", info.Name(), info.Size(), info.ModTime().UnixNano()) return fmt.Sprintf("%s_%d_%d", info.Name(), info.Size(), info.ModTime().UnixNano())
} }

View File

@ -153,7 +153,7 @@ func (w *SpecWatcher) WatchSpecs(args []string, additionalArgs []string) {
} }
func (w *SpecWatcher) compileAndRun(suite internal.TestSuite, additionalArgs []string) internal.TestSuite { func (w *SpecWatcher) compileAndRun(suite internal.TestSuite, additionalArgs []string) internal.TestSuite {
suite = internal.CompileSuite(suite, w.goFlagsConfig) suite = internal.CompileSuite(suite, w.goFlagsConfig, false)
if suite.State.Is(internal.TestSuiteStateFailedToCompile) { if suite.State.Is(internal.TestSuiteStateFailedToCompile) {
fmt.Println(suite.CompilationError.Error()) fmt.Println(suite.CompilationError.Error())
return suite return suite

View File

@ -40,7 +40,7 @@ func (ic InterruptCause) String() string {
} }
type InterruptStatus struct { type InterruptStatus struct {
Channel chan interface{} Channel chan any
Level InterruptLevel Level InterruptLevel
Cause InterruptCause Cause InterruptCause
} }
@ -62,14 +62,14 @@ type InterruptHandlerInterface interface {
} }
type InterruptHandler struct { type InterruptHandler struct {
c chan interface{} c chan any
lock *sync.Mutex lock *sync.Mutex
level InterruptLevel level InterruptLevel
cause InterruptCause cause InterruptCause
client parallel_support.Client client parallel_support.Client
stop chan interface{} stop chan any
signals []os.Signal signals []os.Signal
requestAbortCheck chan interface{} requestAbortCheck chan any
} }
func NewInterruptHandler(client parallel_support.Client, signals ...os.Signal) *InterruptHandler { func NewInterruptHandler(client parallel_support.Client, signals ...os.Signal) *InterruptHandler {
@ -77,10 +77,10 @@ func NewInterruptHandler(client parallel_support.Client, signals ...os.Signal) *
signals = []os.Signal{os.Interrupt, syscall.SIGTERM} signals = []os.Signal{os.Interrupt, syscall.SIGTERM}
} }
handler := &InterruptHandler{ handler := &InterruptHandler{
c: make(chan interface{}), c: make(chan any),
lock: &sync.Mutex{}, lock: &sync.Mutex{},
stop: make(chan interface{}), stop: make(chan any),
requestAbortCheck: make(chan interface{}), requestAbortCheck: make(chan any),
client: client, client: client,
signals: signals, signals: signals,
} }
@ -98,9 +98,9 @@ func (handler *InterruptHandler) registerForInterrupts() {
signal.Notify(signalChannel, handler.signals...) signal.Notify(signalChannel, handler.signals...)
// cross-process abort handling // cross-process abort handling
var abortChannel chan interface{} var abortChannel chan any
if handler.client != nil { if handler.client != nil {
abortChannel = make(chan interface{}) abortChannel = make(chan any)
go func() { go func() {
pollTicker := time.NewTicker(ABORT_POLLING_INTERVAL) pollTicker := time.NewTicker(ABORT_POLLING_INTERVAL)
for { for {
@ -125,7 +125,7 @@ func (handler *InterruptHandler) registerForInterrupts() {
}() }()
} }
go func(abortChannel chan interface{}) { go func(abortChannel chan any) {
var interruptCause InterruptCause var interruptCause InterruptCause
for { for {
select { select {
@ -151,7 +151,7 @@ func (handler *InterruptHandler) registerForInterrupts() {
} }
if handler.level != oldLevel { if handler.level != oldLevel {
close(handler.c) close(handler.c)
handler.c = make(chan interface{}) handler.c = make(chan any)
} }
handler.lock.Unlock() handler.lock.Unlock()
} }

View File

@ -30,7 +30,7 @@ type Server interface {
Close() Close()
Address() string Address() string
RegisterAlive(node int, alive func() bool) RegisterAlive(node int, alive func() bool)
GetSuiteDone() chan interface{} GetSuiteDone() chan any
GetOutputDestination() io.Writer GetOutputDestination() io.Writer
SetOutputDestination(io.Writer) SetOutputDestination(io.Writer)
} }

View File

@ -34,7 +34,7 @@ func (client *httpClient) Close() error {
return nil return nil
} }
func (client *httpClient) post(path string, data interface{}) error { func (client *httpClient) post(path string, data any) error {
var body io.Reader var body io.Reader
if data != nil { if data != nil {
encoded, err := json.Marshal(data) encoded, err := json.Marshal(data)
@ -54,7 +54,7 @@ func (client *httpClient) post(path string, data interface{}) error {
return nil return nil
} }
func (client *httpClient) poll(path string, data interface{}) error { func (client *httpClient) poll(path string, data any) error {
for { for {
resp, err := http.Get(client.serverHost + path) resp, err := http.Get(client.serverHost + path)
if err != nil { if err != nil {
@ -153,10 +153,7 @@ func (client *httpClient) PostAbort() error {
func (client *httpClient) ShouldAbort() bool { func (client *httpClient) ShouldAbort() bool {
err := client.poll("/abort", nil) err := client.poll("/abort", nil)
if err == ErrorGone { return err == ErrorGone
return true
}
return false
} }
func (client *httpClient) Write(p []byte) (int, error) { func (client *httpClient) Write(p []byte) (int, error) {

View File

@ -75,7 +75,7 @@ func (server *httpServer) Address() string {
return "http://" + server.listener.Addr().String() return "http://" + server.listener.Addr().String()
} }
func (server *httpServer) GetSuiteDone() chan interface{} { func (server *httpServer) GetSuiteDone() chan any {
return server.handler.done return server.handler.done
} }
@ -96,7 +96,7 @@ func (server *httpServer) RegisterAlive(node int, alive func() bool) {
// //
// The server will forward all received messages to Ginkgo reporters registered with `RegisterReporters` // The server will forward all received messages to Ginkgo reporters registered with `RegisterReporters`
func (server *httpServer) decode(writer http.ResponseWriter, request *http.Request, object interface{}) bool { func (server *httpServer) decode(writer http.ResponseWriter, request *http.Request, object any) bool {
defer request.Body.Close() defer request.Body.Close()
if json.NewDecoder(request.Body).Decode(object) != nil { if json.NewDecoder(request.Body).Decode(object) != nil {
writer.WriteHeader(http.StatusBadRequest) writer.WriteHeader(http.StatusBadRequest)

View File

@ -35,7 +35,7 @@ func (client *rpcClient) Close() error {
return client.client.Close() return client.client.Close()
} }
func (client *rpcClient) poll(method string, data interface{}) error { func (client *rpcClient) poll(method string, data any) error {
for { for {
err := client.client.Call(method, voidSender, data) err := client.client.Call(method, voidSender, data)
if err == nil { if err == nil {

View File

@ -25,7 +25,7 @@ type RPCServer struct {
handler *ServerHandler handler *ServerHandler
} }
//Create a new server, automatically selecting a port // Create a new server, automatically selecting a port
func newRPCServer(parallelTotal int, reporter reporters.Reporter) (*RPCServer, error) { func newRPCServer(parallelTotal int, reporter reporters.Reporter) (*RPCServer, error) {
listener, err := net.Listen("tcp", "127.0.0.1:0") listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { if err != nil {
@ -37,7 +37,7 @@ func newRPCServer(parallelTotal int, reporter reporters.Reporter) (*RPCServer, e
}, nil }, nil
} }
//Start the server. You don't need to `go s.Start()`, just `s.Start()` // Start the server. You don't need to `go s.Start()`, just `s.Start()`
func (server *RPCServer) Start() { func (server *RPCServer) Start() {
rpcServer := rpc.NewServer() rpcServer := rpc.NewServer()
rpcServer.RegisterName("Server", server.handler) //register the handler's methods as the server rpcServer.RegisterName("Server", server.handler) //register the handler's methods as the server
@ -48,17 +48,17 @@ func (server *RPCServer) Start() {
go httpServer.Serve(server.listener) go httpServer.Serve(server.listener)
} }
//Stop the server // Stop the server
func (server *RPCServer) Close() { func (server *RPCServer) Close() {
server.listener.Close() server.listener.Close()
} }
//The address the server can be reached it. Pass this into the `ForwardingReporter`. // The address the server can be reached it. Pass this into the `ForwardingReporter`.
func (server *RPCServer) Address() string { func (server *RPCServer) Address() string {
return server.listener.Addr().String() return server.listener.Addr().String()
} }
func (server *RPCServer) GetSuiteDone() chan interface{} { func (server *RPCServer) GetSuiteDone() chan any {
return server.handler.done return server.handler.done
} }

View File

@ -18,7 +18,7 @@ var voidSender Void
// It handles all the business logic to avoid duplication between the two servers // It handles all the business logic to avoid duplication between the two servers
type ServerHandler struct { type ServerHandler struct {
done chan interface{} done chan any
outputDestination io.Writer outputDestination io.Writer
reporter reporters.Reporter reporter reporters.Reporter
alives []func() bool alives []func() bool
@ -46,7 +46,7 @@ func newServerHandler(parallelTotal int, reporter reporters.Reporter) *ServerHan
parallelTotal: parallelTotal, parallelTotal: parallelTotal,
outputDestination: os.Stdout, outputDestination: os.Stdout,
done: make(chan interface{}), done: make(chan any),
} }
} }

View File

@ -182,10 +182,31 @@ func (r *DefaultReporter) WillRun(report types.SpecReport) {
r.emitBlock(r.f(r.codeLocationBlock(report, "{{/}}", v.Is(types.VerbosityLevelVeryVerbose), false))) r.emitBlock(r.f(r.codeLocationBlock(report, "{{/}}", v.Is(types.VerbosityLevelVeryVerbose), false)))
} }
func (r *DefaultReporter) wrapTextBlock(sectionName string, fn func()) {
r.emitBlock("\n")
if r.conf.GithubOutput {
r.emitBlock(r.fi(1, "::group::%s", sectionName))
} else {
r.emitBlock(r.fi(1, "{{gray}}%s >>{{/}}", sectionName))
}
fn()
if r.conf.GithubOutput {
r.emitBlock(r.fi(1, "::endgroup::"))
} else {
r.emitBlock(r.fi(1, "{{gray}}<< %s{{/}}", sectionName))
}
}
func (r *DefaultReporter) DidRun(report types.SpecReport) { func (r *DefaultReporter) DidRun(report types.SpecReport) {
v := r.conf.Verbosity() v := r.conf.Verbosity()
inParallel := report.RunningInParallel inParallel := report.RunningInParallel
//should we completely omit this spec?
if report.State.Is(types.SpecStateSkipped) && r.conf.SilenceSkips {
return
}
header := r.specDenoter header := r.specDenoter
if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) {
header = fmt.Sprintf("[%s]", report.LeafNodeType) header = fmt.Sprintf("[%s]", report.LeafNodeType)
@ -262,9 +283,12 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
} }
} }
// If we have no content to show, jsut emit the header and return // If we have no content to show, just emit the header and return
if !reportHasContent { if !reportHasContent {
r.emit(r.f(highlightColor + header + "{{/}}")) r.emit(r.f(highlightColor + header + "{{/}}"))
if r.conf.ForceNewlines {
r.emit("\n")
}
return return
} }
@ -283,26 +307,23 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
//Emit Stdout/Stderr Output //Emit Stdout/Stderr Output
if showSeparateStdSection { if showSeparateStdSection {
r.emitBlock("\n") r.wrapTextBlock("Captured StdOut/StdErr Output", func() {
r.emitBlock(r.fi(1, "{{gray}}Captured StdOut/StdErr Output >>{{/}}"))
r.emitBlock(r.fi(1, "%s", report.CapturedStdOutErr)) r.emitBlock(r.fi(1, "%s", report.CapturedStdOutErr))
r.emitBlock(r.fi(1, "{{gray}}<< Captured StdOut/StdErr Output{{/}}")) })
} }
if showSeparateVisibilityAlwaysReportsSection { if showSeparateVisibilityAlwaysReportsSection {
r.emitBlock("\n") r.wrapTextBlock("Report Entries", func() {
r.emitBlock(r.fi(1, "{{gray}}Report Entries >>{{/}}"))
for _, entry := range report.ReportEntries.WithVisibility(types.ReportEntryVisibilityAlways) { for _, entry := range report.ReportEntries.WithVisibility(types.ReportEntryVisibilityAlways) {
r.emitReportEntry(1, entry) r.emitReportEntry(1, entry)
} }
r.emitBlock(r.fi(1, "{{gray}}<< Report Entries{{/}}")) })
} }
if showTimeline { if showTimeline {
r.emitBlock("\n") r.wrapTextBlock("Timeline", func() {
r.emitBlock(r.fi(1, "{{gray}}Timeline >>{{/}}"))
r.emitTimeline(1, report, timeline) r.emitTimeline(1, report, timeline)
r.emitBlock(r.fi(1, "{{gray}}<< Timeline{{/}}")) })
} }
// Emit Failure Message // Emit Failure Message
@ -405,7 +426,15 @@ func (r *DefaultReporter) emitShortFailure(indent uint, state types.SpecState, f
func (r *DefaultReporter) emitFailure(indent uint, state types.SpecState, failure types.Failure, includeAdditionalFailure bool) { func (r *DefaultReporter) emitFailure(indent uint, state types.SpecState, failure types.Failure, includeAdditionalFailure bool) {
highlightColor := r.highlightColorForState(state) highlightColor := r.highlightColorForState(state)
r.emitBlock(r.fi(indent, highlightColor+"[%s] %s{{/}}", r.humanReadableState(state), failure.Message)) r.emitBlock(r.fi(indent, highlightColor+"[%s] %s{{/}}", r.humanReadableState(state), failure.Message))
if r.conf.GithubOutput {
level := "error"
if state.Is(types.SpecStateSkipped) {
level = "notice"
}
r.emitBlock(r.fi(indent, "::%s file=%s,line=%d::%s %s", level, failure.Location.FileName, failure.Location.LineNumber, failure.FailureNodeType, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT)))
} else {
r.emitBlock(r.fi(indent, highlightColor+"In {{bold}}[%s]{{/}}"+highlightColor+" at: {{bold}}%s{{/}} {{gray}}@ %s{{/}}\n", failure.FailureNodeType, failure.Location, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) r.emitBlock(r.fi(indent, highlightColor+"In {{bold}}[%s]{{/}}"+highlightColor+" at: {{bold}}%s{{/}} {{gray}}@ %s{{/}}\n", failure.FailureNodeType, failure.Location, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT)))
}
if failure.ForwardedPanic != "" { if failure.ForwardedPanic != "" {
r.emitBlock("\n") r.emitBlock("\n")
r.emitBlock(r.fi(indent, highlightColor+"%s{{/}}", failure.ForwardedPanic)) r.emitBlock(r.fi(indent, highlightColor+"%s{{/}}", failure.ForwardedPanic))
@ -656,11 +685,11 @@ func (r *DefaultReporter) _emit(s string, block bool, isDelimiter bool) {
} }
/* Rendering text */ /* Rendering text */
func (r *DefaultReporter) f(format string, args ...interface{}) string { func (r *DefaultReporter) f(format string, args ...any) string {
return r.formatter.F(format, args...) return r.formatter.F(format, args...)
} }
func (r *DefaultReporter) fi(indentation uint, format string, args ...interface{}) string { func (r *DefaultReporter) fi(indentation uint, format string, args ...any) string {
return r.formatter.Fi(indentation, format, args...) return r.formatter.Fi(indentation, format, args...)
} }

View File

@ -18,6 +18,7 @@ func GenerateJSONReport(report types.Report, destination string) error {
if err != nil { if err != nil {
return err return err
} }
defer f.Close()
enc := json.NewEncoder(f) enc := json.NewEncoder(f)
enc.SetIndent("", " ") enc.SetIndent("", " ")
err = enc.Encode([]types.Report{ err = enc.Encode([]types.Report{
@ -26,7 +27,7 @@ func GenerateJSONReport(report types.Report, destination string) error {
if err != nil { if err != nil {
return err return err
} }
return f.Close() return nil
} }
// MergeJSONReports produces a single JSON-formatted report at the passed in destination by merging the JSON-formatted reports provided in sources // MergeJSONReports produces a single JSON-formatted report at the passed in destination by merging the JSON-formatted reports provided in sources
@ -57,11 +58,12 @@ func MergeAndCleanupJSONReports(sources []string, destination string) ([]string,
if err != nil { if err != nil {
return messages, err return messages, err
} }
defer f.Close()
enc := json.NewEncoder(f) enc := json.NewEncoder(f)
enc.SetIndent("", " ") enc.SetIndent("", " ")
err = enc.Encode(allReports) err = enc.Encode(allReports)
if err != nil { if err != nil {
return messages, err return messages, err
} }
return messages, f.Close() return messages, nil
} }

View File

@ -15,6 +15,7 @@ import (
"fmt" "fmt"
"os" "os"
"path" "path"
"regexp"
"strings" "strings"
"github.com/onsi/ginkgo/v2/config" "github.com/onsi/ginkgo/v2/config"
@ -104,6 +105,8 @@ type JUnitProperty struct {
Value string `xml:"value,attr"` Value string `xml:"value,attr"`
} }
var ownerRE = regexp.MustCompile(`(?i)^owner:(.*)$`)
type JUnitTestCase struct { type JUnitTestCase struct {
// Name maps onto the full text of the spec - equivalent to "[SpecReport.LeafNodeType] SpecReport.FullText()" // Name maps onto the full text of the spec - equivalent to "[SpecReport.LeafNodeType] SpecReport.FullText()"
Name string `xml:"name,attr"` Name string `xml:"name,attr"`
@ -113,6 +116,8 @@ type JUnitTestCase struct {
Status string `xml:"status,attr"` Status string `xml:"status,attr"`
// Time is the time in seconds to execute the spec - maps onto SpecReport.RunTime // Time is the time in seconds to execute the spec - maps onto SpecReport.RunTime
Time float64 `xml:"time,attr"` Time float64 `xml:"time,attr"`
// Owner is the owner the spec - is set if a label matching Label("owner:X") is provided. The last matching label is used as the owner, thereby allowing specs to override owners specified in container nodes.
Owner string `xml:"owner,attr,omitempty"`
//Skipped is populated with a message if the test was skipped or pending //Skipped is populated with a message if the test was skipped or pending
Skipped *JUnitSkipped `xml:"skipped,omitempty"` Skipped *JUnitSkipped `xml:"skipped,omitempty"`
//Error is populated if the test panicked or was interrupted //Error is populated if the test panicked or was interrupted
@ -172,6 +177,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
{"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")}, {"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")},
{"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")}, {"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")},
{"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)}, {"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)},
{"FailOnEmpty", fmt.Sprintf("%t", report.SuiteConfig.FailOnEmpty)},
{"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)}, {"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)},
{"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)}, {"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)},
{"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)}, {"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)},
@ -195,6 +201,12 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
if len(labels) > 0 && !config.OmitSpecLabels { if len(labels) > 0 && !config.OmitSpecLabels {
name = name + " [" + strings.Join(labels, ", ") + "]" name = name + " [" + strings.Join(labels, ", ") + "]"
} }
owner := ""
for _, label := range labels {
if matches := ownerRE.FindStringSubmatch(label); len(matches) == 2 {
owner = matches[1]
}
}
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
test := JUnitTestCase{ test := JUnitTestCase{
@ -202,6 +214,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
Classname: report.SuiteDescription, Classname: report.SuiteDescription,
Status: spec.State.String(), Status: spec.State.String(),
Time: spec.RunTime.Seconds(), Time: spec.RunTime.Seconds(),
Owner: owner,
} }
if !spec.State.Is(config.OmitTimelinesForSpecState) { if !spec.State.Is(config.OmitTimelinesForSpecState) {
test.SystemErr = systemErrForUnstructuredReporters(spec) test.SystemErr = systemErrForUnstructuredReporters(spec)
@ -312,6 +325,7 @@ func MergeAndCleanupJUnitReports(sources []string, dst string) ([]string, error)
continue continue
} }
err = xml.NewDecoder(f).Decode(&report) err = xml.NewDecoder(f).Decode(&report)
_ = f.Close()
if err != nil { if err != nil {
messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error())) messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error()))
continue continue

View File

@ -149,7 +149,7 @@ func PruneStack(fullStackTrace string, skip int) string {
re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
for i := 0; i < len(stack)/2; i++ { for i := 0; i < len(stack)/2; i++ {
// We filter out based on the source code file name. // We filter out based on the source code file name.
if !re.Match([]byte(stack[i*2+1])) { if !re.MatchString(stack[i*2+1]) {
prunedStack = append(prunedStack, stack[i*2]) prunedStack = append(prunedStack, stack[i*2])
prunedStack = append(prunedStack, stack[i*2+1]) prunedStack = append(prunedStack, stack[i*2+1])
} }

View File

@ -25,6 +25,7 @@ type SuiteConfig struct {
SkipFiles []string SkipFiles []string
LabelFilter string LabelFilter string
FailOnPending bool FailOnPending bool
FailOnEmpty bool
FailFast bool FailFast bool
FlakeAttempts int FlakeAttempts int
MustPassRepeatedly int MustPassRepeatedly int
@ -89,6 +90,9 @@ type ReporterConfig struct {
VeryVerbose bool VeryVerbose bool
FullTrace bool FullTrace bool
ShowNodeEvents bool ShowNodeEvents bool
GithubOutput bool
SilenceSkips bool
ForceNewlines bool
JSONReport string JSONReport string
JUnitReport string JUnitReport string
@ -155,7 +159,7 @@ func (g CLIConfig) ComputedProcs() int {
n := 1 n := 1
if g.Parallel { if g.Parallel {
n = runtime.NumCPU() n = runtime.GOMAXPROCS(-1)
if n > 4 { if n > 4 {
n = n - 1 n = n - 1
} }
@ -168,7 +172,7 @@ func (g CLIConfig) ComputedNumCompilers() int {
return g.NumCompilers return g.NumCompilers
} }
return runtime.NumCPU() return runtime.GOMAXPROCS(-1)
} }
// Configuration for the Ginkgo CLI capturing available go flags // Configuration for the Ginkgo CLI capturing available go flags
@ -198,6 +202,7 @@ type GoFlagsConfig struct {
A bool A bool
ASMFlags string ASMFlags string
BuildMode string BuildMode string
BuildVCS bool
Compiler string Compiler string
GCCGoFlags string GCCGoFlags string
GCFlags string GCFlags string
@ -215,6 +220,7 @@ type GoFlagsConfig struct {
ToolExec string ToolExec string
Work bool Work bool
X bool X bool
O string
} }
func NewDefaultGoFlagsConfig() GoFlagsConfig { func NewDefaultGoFlagsConfig() GoFlagsConfig {
@ -225,6 +231,10 @@ func (g GoFlagsConfig) BinaryMustBePreserved() bool {
return g.BlockProfile != "" || g.CPUProfile != "" || g.MemProfile != "" || g.MutexProfile != "" return g.BlockProfile != "" || g.CPUProfile != "" || g.MemProfile != "" || g.MutexProfile != ""
} }
func (g GoFlagsConfig) NeedsSymbols() bool {
return g.BinaryMustBePreserved()
}
// Configuration that were deprecated in 2.0 // Configuration that were deprecated in 2.0
type deprecatedConfig struct { type deprecatedConfig struct {
DebugParallel bool DebugParallel bool
@ -251,8 +261,12 @@ var FlagSections = GinkgoFlagSections{
{Key: "filter", Style: "{{cyan}}", Heading: "Filtering Tests"}, {Key: "filter", Style: "{{cyan}}", Heading: "Filtering Tests"},
{Key: "failure", Style: "{{red}}", Heading: "Failure Handling"}, {Key: "failure", Style: "{{red}}", Heading: "Failure Handling"},
{Key: "output", Style: "{{magenta}}", Heading: "Controlling Output Formatting"}, {Key: "output", Style: "{{magenta}}", Heading: "Controlling Output Formatting"},
{Key: "code-and-coverage-analysis", Style: "{{orange}}", Heading: "Code and Coverage Analysis"}, {Key: "code-and-coverage-analysis", Style: "{{orange}}", Heading: "Code and Coverage Analysis",
{Key: "performance-analysis", Style: "{{coral}}", Heading: "Performance Analysis"}, Description: "When generating a cover files, please pass a filename {{bold}}not{{/}} a path. To specify a different directory use {{magenta}}--output-dir{{/}}.",
},
{Key: "performance-analysis", Style: "{{coral}}", Heading: "Performance Analysis",
Description: "When generating profile files, please pass filenames {{bold}}not{{/}} a path. Ginkgo will generate a profile file with the given name in the package's directory. To specify a different directory use {{magenta}}--output-dir{{/}}.",
},
{Key: "debug", Style: "{{blue}}", Heading: "Debugging Tests", {Key: "debug", Style: "{{blue}}", Heading: "Debugging Tests",
Description: "In addition to these flags, Ginkgo supports a few debugging environment variables. To change the parallel server protocol set {{blue}}GINKGO_PARALLEL_PROTOCOL{{/}} to {{bold}}HTTP{{/}}. To avoid pruning callstacks set {{blue}}GINKGO_PRUNE_STACK{{/}} to {{bold}}FALSE{{/}}."}, Description: "In addition to these flags, Ginkgo supports a few debugging environment variables. To change the parallel server protocol set {{blue}}GINKGO_PARALLEL_PROTOCOL{{/}} to {{bold}}HTTP{{/}}. To avoid pruning callstacks set {{blue}}GINKGO_PRUNE_STACK{{/}} to {{bold}}FALSE{{/}}."},
{Key: "watch", Style: "{{light-yellow}}", Heading: "Controlling Ginkgo Watch"}, {Key: "watch", Style: "{{light-yellow}}", Heading: "Controlling Ginkgo Watch"},
@ -264,7 +278,7 @@ var FlagSections = GinkgoFlagSections{
// SuiteConfigFlags provides flags for the Ginkgo test process, and CLI // SuiteConfigFlags provides flags for the Ginkgo test process, and CLI
var SuiteConfigFlags = GinkgoFlags{ var SuiteConfigFlags = GinkgoFlags{
{KeyPath: "S.RandomSeed", Name: "seed", SectionKey: "order", UsageDefaultValue: "randomly generated by Ginkgo", {KeyPath: "S.RandomSeed", Name: "seed", SectionKey: "order", UsageDefaultValue: "randomly generated by Ginkgo",
Usage: "The seed used to randomize the spec suite."}, Usage: "The seed used to randomize the spec suite.", AlwaysExport: true},
{KeyPath: "S.RandomizeAllSpecs", Name: "randomize-all", SectionKey: "order", DeprecatedName: "randomizeAllSpecs", DeprecatedDocLink: "changed-command-line-flags", {KeyPath: "S.RandomizeAllSpecs", Name: "randomize-all", SectionKey: "order", DeprecatedName: "randomizeAllSpecs", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe, Context and When containers."}, Usage: "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe, Context and When containers."},
@ -274,6 +288,8 @@ var SuiteConfigFlags = GinkgoFlags{
Usage: "If set, ginkgo will stop running a test suite after a failure occurs."}, Usage: "If set, ginkgo will stop running a test suite after a failure occurs."},
{KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags", {KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags",
Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."}, Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."},
{KeyPath: "S.FailOnEmpty", Name: "fail-on-empty", SectionKey: "failure",
Usage: "If set, ginkgo will mark the test suite as failed if no specs are run."},
{KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags", {KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."}, Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."},
@ -320,7 +336,7 @@ var ParallelConfigFlags = GinkgoFlags{
// ReporterConfigFlags provides flags for the Ginkgo test process, and CLI // ReporterConfigFlags provides flags for the Ginkgo test process, and CLI
var ReporterConfigFlags = GinkgoFlags{ var ReporterConfigFlags = GinkgoFlags{
{KeyPath: "R.NoColor", Name: "no-color", SectionKey: "output", DeprecatedName: "noColor", DeprecatedDocLink: "changed-command-line-flags", {KeyPath: "R.NoColor", Name: "no-color", SectionKey: "output", DeprecatedName: "noColor", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, suppress color output in default reporter."}, Usage: "If set, suppress color output in default reporter. You can also set the environment variable GINKGO_NO_COLOR=TRUE"},
{KeyPath: "R.Verbose", Name: "v", SectionKey: "output", {KeyPath: "R.Verbose", Name: "v", SectionKey: "output",
Usage: "If set, emits more output including GinkgoWriter contents."}, Usage: "If set, emits more output including GinkgoWriter contents."},
{KeyPath: "R.VeryVerbose", Name: "vv", SectionKey: "output", {KeyPath: "R.VeryVerbose", Name: "vv", SectionKey: "output",
@ -331,6 +347,12 @@ var ReporterConfigFlags = GinkgoFlags{
Usage: "If set, default reporter prints out the full stack trace when a failure occurs"}, Usage: "If set, default reporter prints out the full stack trace when a failure occurs"},
{KeyPath: "R.ShowNodeEvents", Name: "show-node-events", SectionKey: "output", {KeyPath: "R.ShowNodeEvents", Name: "show-node-events", SectionKey: "output",
Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"}, Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"},
{KeyPath: "R.GithubOutput", Name: "github-output", SectionKey: "output",
Usage: "If set, default reporter prints easier to manage output in Github Actions."},
{KeyPath: "R.SilenceSkips", Name: "silence-skips", SectionKey: "output",
Usage: "If set, default reporter will not print out skipped tests."},
{KeyPath: "R.ForceNewlines", Name: "force-newlines", SectionKey: "output",
Usage: "If set, default reporter will ensure a newline appears after each test."},
{KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output", {KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output",
Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."}, Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."},
@ -351,7 +373,7 @@ var ReporterConfigFlags = GinkgoFlags{
func BuildTestSuiteFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig) (GinkgoFlagSet, error) { func BuildTestSuiteFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig) (GinkgoFlagSet, error) {
flags := SuiteConfigFlags.CopyAppend(ParallelConfigFlags...).CopyAppend(ReporterConfigFlags...) flags := SuiteConfigFlags.CopyAppend(ParallelConfigFlags...).CopyAppend(ReporterConfigFlags...)
flags = flags.WithPrefix("ginkgo") flags = flags.WithPrefix("ginkgo")
bindings := map[string]interface{}{ bindings := map[string]any{
"S": suiteConfig, "S": suiteConfig,
"R": reporterConfig, "R": reporterConfig,
"D": &deprecatedConfig{}, "D": &deprecatedConfig{},
@ -499,9 +521,9 @@ var GinkgoCLIWatchFlags = GinkgoFlags{
// GoBuildFlags provides flags for the Ginkgo CLI build, run, and watch commands that capture go's build-time flags. These are passed to go test -c by the ginkgo CLI // GoBuildFlags provides flags for the Ginkgo CLI build, run, and watch commands that capture go's build-time flags. These are passed to go test -c by the ginkgo CLI
var GoBuildFlags = GinkgoFlags{ var GoBuildFlags = GinkgoFlags{
{KeyPath: "Go.Race", Name: "race", SectionKey: "code-and-coverage-analysis", {KeyPath: "Go.Race", Name: "race", SectionKey: "code-and-coverage-analysis",
Usage: "enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, linux/ppc64le and linux/arm64 (only for 48-bit VMA)."}, Usage: "enable data race detection. Supported on linux/amd64, linux/ppc64le, linux/arm64, linux/s390x, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64."},
{KeyPath: "Go.Vet", Name: "vet", UsageArgument: "list", SectionKey: "code-and-coverage-analysis", {KeyPath: "Go.Vet", Name: "vet", UsageArgument: "list", SectionKey: "code-and-coverage-analysis",
Usage: `Configure the invocation of "go vet" during "go test" to use the comma-separated list of vet checks. If list is empty, "go test" runs "go vet" with a curated list of checks believed to be always worth addressing. If list is "off", "go test" does not run "go vet" at all. Available checks can be found by running 'go doc cmd/vet'`}, Usage: `Configure the invocation of "go vet" during "go test" to use the comma-separated list of vet checks. If list is empty (by explicitly passing --vet=""), "go test" runs "go vet" with a curated list of checks believed to be always worth addressing. If list is "off", "go test" does not run "go vet" at all. Available checks can be found by running 'go doc cmd/vet'`},
{KeyPath: "Go.Cover", Name: "cover", SectionKey: "code-and-coverage-analysis", {KeyPath: "Go.Cover", Name: "cover", SectionKey: "code-and-coverage-analysis",
Usage: "Enable coverage analysis. Note that because coverage works by annotating the source code before compilation, compilation and test failures with coverage enabled may report line numbers that don't correspond to the original sources."}, Usage: "Enable coverage analysis. Note that because coverage works by annotating the source code before compilation, compilation and test failures with coverage enabled may report line numbers that don't correspond to the original sources."},
{KeyPath: "Go.CoverMode", Name: "covermode", UsageArgument: "set,count,atomic", SectionKey: "code-and-coverage-analysis", {KeyPath: "Go.CoverMode", Name: "covermode", UsageArgument: "set,count,atomic", SectionKey: "code-and-coverage-analysis",
@ -515,6 +537,8 @@ var GoBuildFlags = GinkgoFlags{
Usage: "arguments to pass on each go tool asm invocation."}, Usage: "arguments to pass on each go tool asm invocation."},
{KeyPath: "Go.BuildMode", Name: "buildmode", UsageArgument: "mode", SectionKey: "go-build", {KeyPath: "Go.BuildMode", Name: "buildmode", UsageArgument: "mode", SectionKey: "go-build",
Usage: "build mode to use. See 'go help buildmode' for more."}, Usage: "build mode to use. See 'go help buildmode' for more."},
{KeyPath: "Go.BuildVCS", Name: "buildvcs", SectionKey: "go-build",
Usage: "adds version control information."},
{KeyPath: "Go.Compiler", Name: "compiler", UsageArgument: "name", SectionKey: "go-build", {KeyPath: "Go.Compiler", Name: "compiler", UsageArgument: "name", SectionKey: "go-build",
Usage: "name of compiler to use, as in runtime.Compiler (gccgo or gc)."}, Usage: "name of compiler to use, as in runtime.Compiler (gccgo or gc)."},
{KeyPath: "Go.GCCGoFlags", Name: "gccgoflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", {KeyPath: "Go.GCCGoFlags", Name: "gccgoflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build",
@ -549,12 +573,14 @@ var GoBuildFlags = GinkgoFlags{
Usage: "print the name of the temporary work directory and do not delete it when exiting."}, Usage: "print the name of the temporary work directory and do not delete it when exiting."},
{KeyPath: "Go.X", Name: "x", SectionKey: "go-build", {KeyPath: "Go.X", Name: "x", SectionKey: "go-build",
Usage: "print the commands."}, Usage: "print the commands."},
{KeyPath: "Go.O", Name: "o", SectionKey: "go-build",
Usage: "output binary path (including name)."},
} }
// GoRunFlags provides flags for the Ginkgo CLI run, and watch commands that capture go's run-time flags. These are passed to the compiled test binary by the ginkgo CLI // GoRunFlags provides flags for the Ginkgo CLI run, and watch commands that capture go's run-time flags. These are passed to the compiled test binary by the ginkgo CLI
var GoRunFlags = GinkgoFlags{ var GoRunFlags = GinkgoFlags{
{KeyPath: "Go.CoverProfile", Name: "coverprofile", UsageArgument: "file", SectionKey: "code-and-coverage-analysis", {KeyPath: "Go.CoverProfile", Name: "coverprofile", UsageArgument: "file", SectionKey: "code-and-coverage-analysis",
Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover.`}, Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover. Must be passed a filename, not a path. Use output-dir to control the location of the output.`},
{KeyPath: "Go.BlockProfile", Name: "blockprofile", UsageArgument: "file", SectionKey: "performance-analysis", {KeyPath: "Go.BlockProfile", Name: "blockprofile", UsageArgument: "file", SectionKey: "performance-analysis",
Usage: `Write a goroutine blocking profile to the specified file when all tests are complete. Preserves test binary.`}, Usage: `Write a goroutine blocking profile to the specified file when all tests are complete. Preserves test binary.`},
{KeyPath: "Go.BlockProfileRate", Name: "blockprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis", {KeyPath: "Go.BlockProfileRate", Name: "blockprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis",
@ -582,6 +608,22 @@ func VetAndInitializeCLIAndGoConfig(cliConfig CLIConfig, goFlagsConfig GoFlagsCo
errors = append(errors, GinkgoErrors.BothRepeatAndUntilItFails()) errors = append(errors, GinkgoErrors.BothRepeatAndUntilItFails())
} }
if strings.ContainsRune(goFlagsConfig.CoverProfile, os.PathSeparator) {
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--coverprofile", goFlagsConfig.CoverProfile))
}
if strings.ContainsRune(goFlagsConfig.CPUProfile, os.PathSeparator) {
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--cpuprofile", goFlagsConfig.CPUProfile))
}
if strings.ContainsRune(goFlagsConfig.MemProfile, os.PathSeparator) {
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--memprofile", goFlagsConfig.MemProfile))
}
if strings.ContainsRune(goFlagsConfig.BlockProfile, os.PathSeparator) {
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--blockprofile", goFlagsConfig.BlockProfile))
}
if strings.ContainsRune(goFlagsConfig.MutexProfile, os.PathSeparator) {
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--mutexprofile", goFlagsConfig.MutexProfile))
}
//initialize the output directory //initialize the output directory
if cliConfig.OutputDir != "" { if cliConfig.OutputDir != "" {
err := os.MkdirAll(cliConfig.OutputDir, 0777) err := os.MkdirAll(cliConfig.OutputDir, 0777)
@ -602,7 +644,7 @@ func VetAndInitializeCLIAndGoConfig(cliConfig CLIConfig, goFlagsConfig GoFlagsCo
} }
// GenerateGoTestCompileArgs is used by the Ginkgo CLI to generate command line arguments to pass to the go test -c command when compiling the test // GenerateGoTestCompileArgs is used by the Ginkgo CLI to generate command line arguments to pass to the go test -c command when compiling the test
func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, destination string, packageToBuild string, pathToInvocationPath string) ([]string, error) { func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, packageToBuild string, pathToInvocationPath string, preserveSymbols bool) ([]string, error) {
// if the user has set the CoverProfile run-time flag make sure to set the build-time cover flag to make sure // if the user has set the CoverProfile run-time flag make sure to set the build-time cover flag to make sure
// the built test binary can generate a coverprofile // the built test binary can generate a coverprofile
if goFlagsConfig.CoverProfile != "" { if goFlagsConfig.CoverProfile != "" {
@ -625,10 +667,14 @@ func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, destination string,
goFlagsConfig.CoverPkg = strings.Join(adjustedCoverPkgs, ",") goFlagsConfig.CoverPkg = strings.Join(adjustedCoverPkgs, ",")
} }
args := []string{"test", "-c", "-o", destination, packageToBuild} if !goFlagsConfig.NeedsSymbols() && goFlagsConfig.LDFlags == "" && !preserveSymbols {
goFlagsConfig.LDFlags = "-w -s"
}
args := []string{"test", "-c", packageToBuild}
goArgs, err := GenerateFlagArgs( goArgs, err := GenerateFlagArgs(
GoBuildFlags, GoBuildFlags,
map[string]interface{}{ map[string]any{
"Go": &goFlagsConfig, "Go": &goFlagsConfig,
}, },
) )
@ -647,7 +693,7 @@ func GenerateGinkgoTestRunArgs(suiteConfig SuiteConfig, reporterConfig ReporterC
flags = flags.CopyAppend(ParallelConfigFlags.WithPrefix("ginkgo")...) flags = flags.CopyAppend(ParallelConfigFlags.WithPrefix("ginkgo")...)
flags = flags.CopyAppend(ReporterConfigFlags.WithPrefix("ginkgo")...) flags = flags.CopyAppend(ReporterConfigFlags.WithPrefix("ginkgo")...)
flags = flags.CopyAppend(GoRunFlags.WithPrefix("test")...) flags = flags.CopyAppend(GoRunFlags.WithPrefix("test")...)
bindings := map[string]interface{}{ bindings := map[string]any{
"S": &suiteConfig, "S": &suiteConfig,
"R": &reporterConfig, "R": &reporterConfig,
"Go": &goFlagsConfig, "Go": &goFlagsConfig,
@ -659,7 +705,7 @@ func GenerateGinkgoTestRunArgs(suiteConfig SuiteConfig, reporterConfig ReporterC
// GenerateGoTestRunArgs is used by the Ginkgo CLI to generate command line arguments to pass to the compiled non-Ginkgo test binary // GenerateGoTestRunArgs is used by the Ginkgo CLI to generate command line arguments to pass to the compiled non-Ginkgo test binary
func GenerateGoTestRunArgs(goFlagsConfig GoFlagsConfig) ([]string, error) { func GenerateGoTestRunArgs(goFlagsConfig GoFlagsConfig) ([]string, error) {
flags := GoRunFlags.WithPrefix("test") flags := GoRunFlags.WithPrefix("test")
bindings := map[string]interface{}{ bindings := map[string]any{
"Go": &goFlagsConfig, "Go": &goFlagsConfig,
} }
@ -681,7 +727,7 @@ func BuildRunCommandFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterCo
flags = flags.CopyAppend(GoBuildFlags...) flags = flags.CopyAppend(GoBuildFlags...)
flags = flags.CopyAppend(GoRunFlags...) flags = flags.CopyAppend(GoRunFlags...)
bindings := map[string]interface{}{ bindings := map[string]any{
"S": suiteConfig, "S": suiteConfig,
"R": reporterConfig, "R": reporterConfig,
"C": cliConfig, "C": cliConfig,
@ -702,7 +748,7 @@ func BuildWatchCommandFlagSet(suiteConfig *SuiteConfig, reporterConfig *Reporter
flags = flags.CopyAppend(GoBuildFlags...) flags = flags.CopyAppend(GoBuildFlags...)
flags = flags.CopyAppend(GoRunFlags...) flags = flags.CopyAppend(GoRunFlags...)
bindings := map[string]interface{}{ bindings := map[string]any{
"S": suiteConfig, "S": suiteConfig,
"R": reporterConfig, "R": reporterConfig,
"C": cliConfig, "C": cliConfig,
@ -718,7 +764,7 @@ func BuildBuildCommandFlagSet(cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig
flags := GinkgoCLISharedFlags flags := GinkgoCLISharedFlags
flags = flags.CopyAppend(GoBuildFlags...) flags = flags.CopyAppend(GoBuildFlags...)
bindings := map[string]interface{}{ bindings := map[string]any{
"C": cliConfig, "C": cliConfig,
"Go": goFlagsConfig, "Go": goFlagsConfig,
"D": &deprecatedConfig{}, "D": &deprecatedConfig{},
@ -742,7 +788,7 @@ func BuildBuildCommandFlagSet(cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig
func BuildLabelsCommandFlagSet(cliConfig *CLIConfig) (GinkgoFlagSet, error) { func BuildLabelsCommandFlagSet(cliConfig *CLIConfig) (GinkgoFlagSet, error) {
flags := GinkgoCLISharedFlags.SubsetWithNames("r", "skip-package") flags := GinkgoCLISharedFlags.SubsetWithNames("r", "skip-package")
bindings := map[string]interface{}{ bindings := map[string]any{
"C": cliConfig, "C": cliConfig,
} }

View File

@ -113,7 +113,7 @@ type DeprecatedSpecFailure struct {
type DeprecatedSpecMeasurement struct { type DeprecatedSpecMeasurement struct {
Name string Name string
Info interface{} Info any
Order int Order int
Results []float64 Results []float64

View File

@ -88,7 +88,7 @@ body of a {{bold}}Describe{{/}}, {{bold}}Context{{/}}, or {{bold}}When{{/}}.`, n
} }
} }
func (g ginkgoErrors) CaughtPanicDuringABuildPhase(caughtPanic interface{}, cl CodeLocation) error { func (g ginkgoErrors) CaughtPanicDuringABuildPhase(caughtPanic any, cl CodeLocation) error {
return GinkgoError{ return GinkgoError{
Heading: "Assertion or Panic detected during tree construction", Heading: "Assertion or Panic detected during tree construction",
Message: formatter.F( Message: formatter.F(
@ -189,7 +189,7 @@ func (g ginkgoErrors) InvalidDeclarationOfFlakeAttemptsAndMustPassRepeatedly(cl
} }
} }
func (g ginkgoErrors) UnknownDecorator(cl CodeLocation, nodeType NodeType, decorator interface{}) error { func (g ginkgoErrors) UnknownDecorator(cl CodeLocation, nodeType NodeType, decorator any) error {
return GinkgoError{ return GinkgoError{
Heading: "Unknown Decorator", Heading: "Unknown Decorator",
Message: formatter.F(`[%s] node was passed an unknown decorator: '%#v'`, nodeType, decorator), Message: formatter.F(`[%s] node was passed an unknown decorator: '%#v'`, nodeType, decorator),
@ -345,7 +345,7 @@ func (g ginkgoErrors) PushingCleanupInCleanupNode(cl CodeLocation) error {
} }
/* ReportEntry errors */ /* ReportEntry errors */
func (g ginkgoErrors) TooManyReportEntryValues(cl CodeLocation, arg interface{}) error { func (g ginkgoErrors) TooManyReportEntryValues(cl CodeLocation, arg any) error {
return GinkgoError{ return GinkgoError{
Heading: "Too Many ReportEntry Values", Heading: "Too Many ReportEntry Values",
Message: formatter.F(`{{bold}}AddGinkgoReport{{/}} can only be given one value. Got unexpected value: %#v`, arg), Message: formatter.F(`{{bold}}AddGinkgoReport{{/}} can only be given one value. Got unexpected value: %#v`, arg),
@ -505,6 +505,15 @@ func (g ginkgoErrors) IncorrectVariadicParameterTypeToTableFunction(expected, ac
} }
} }
func (g ginkgoErrors) ContextsCannotBeUsedInSubtreeTables(cl CodeLocation) error {
return GinkgoError{
Heading: "Contexts cannot be used in subtree tables",
Message: "You''ve defined a subtree body function that accepts a context but did not provide one in the table entry. Ginkgo SpecContexts can only be passed in to subject and setup nodes - so if you are trying to implement a spec timeout you should request a context in the It function within your subtree body function, not in the subtree body function itself.",
CodeLocation: cl,
DocLink: "table-specs",
}
}
/* Parallel Synchronization errors */ /* Parallel Synchronization errors */
func (g ginkgoErrors) AggregatedReportUnavailableDueToNodeDisappearing() error { func (g ginkgoErrors) AggregatedReportUnavailableDueToNodeDisappearing() error {
@ -530,7 +539,7 @@ func (g ginkgoErrors) SynchronizedBeforeSuiteDisappearedOnProc1() error {
/* Configuration errors */ /* Configuration errors */
func (g ginkgoErrors) UnknownTypePassedToRunSpecs(value interface{}) error { func (g ginkgoErrors) UnknownTypePassedToRunSpecs(value any) error {
return GinkgoError{ return GinkgoError{
Heading: "Unknown Type passed to RunSpecs", Heading: "Unknown Type passed to RunSpecs",
Message: fmt.Sprintf("RunSpecs() accepts labels, and configuration of type types.SuiteConfig and/or types.ReporterConfig.\n You passed in: %v", value), Message: fmt.Sprintf("RunSpecs() accepts labels, and configuration of type types.SuiteConfig and/or types.ReporterConfig.\n You passed in: %v", value),
@ -620,6 +629,20 @@ func (g ginkgoErrors) BothRepeatAndUntilItFails() error {
} }
} }
func (g ginkgoErrors) ExpectFilenameNotPath(flag string, path string) error {
return GinkgoError{
Heading: fmt.Sprintf("%s expects a filename but was given a path: %s", flag, path),
Message: fmt.Sprintf("%s takes a filename, not a path. Use --output-dir to specify a directory to collect all test outputs.", flag),
}
}
func (g ginkgoErrors) FlagAfterPositionalParameter() error {
return GinkgoError{
Heading: "Malformed arguments - detected a flag after the package liste",
Message: "Make sure all flags appear {{bold}}after{{/}} the Ginkgo subcommand and {{bold}}before{{/}} your list of packages (or './...').\n{{gray}}e.g. 'ginkgo run -p my_package' is valid but `ginkgo -p run my_package` is not.\n{{gray}}e.g. 'ginkgo -p -vet=\"\" ./...' is valid but 'ginkgo -p ./... -vet=\"\"' is not{{/}}",
}
}
/* Stack-Trace parsing errors */ /* Stack-Trace parsing errors */
func (g ginkgoErrors) FailedToParseStackTrace(message string) error { func (g ginkgoErrors) FailedToParseStackTrace(message string) error {

Some files were not shown because too many files have changed in this diff Show More