diff --git a/.github/workflows/go1.21.yml b/.github/workflows/go1.21.yml new file mode 100644 index 0000000000..38312250c8 --- /dev/null +++ b/.github/workflows/go1.21.yml @@ -0,0 +1,24 @@ +# Runs the whole test suite using go1.21 +name: alltests-go1.21 +on: + pull_request: + push: + branches: + - "release/**" + - "fullbuild" + - "alltestsbuild" + +jobs: + test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - uses: magnetikonline/action-golang-cache@v4 + with: + go-version: ~1.21 + cache-key-suffix: "-alltests-go1.21" + + # We cannot run buildtool tests using an unexpected version of Go because the + # tests check whether we're using the expected version of Go 😂😂😂😂. + - run: go test -race -tags shaping $(go list ./...|grep -v 'internal/cmd/buildtool') diff --git a/Readme.md b/Readme.md index 8bbed67b80..228bb09a96 100644 --- a/Readme.md +++ b/Readme.md @@ -60,9 +60,10 @@ Debian/Ubuntu. Once `ooniprobe` is installed, refer to the ## Developer instructions -This repository requires _exactly_ the Go version mentioned by the -[GOVERSION](GOVERSION) file (i.e., go1.20.12). Using a different version of -Go _may_ work as intended but is not recommended: we depend +This repository _should really_ use the Go version mentioned by the +[GOVERSION](GOVERSION) file (i.e., go1.20.12). Using a later version of +Go _should_ work as intended. Using an older version of Go is +_definitely not recommended_ and _may not even compile_. Here's why: we rely on packages forked from the standard library; so, it is more robust to use the same version of Go from which we forked those packages from. diff --git a/internal/feature/psiphonfeat/doc.go b/internal/feature/psiphonfeat/doc.go new file mode 100644 index 0000000000..2c63f0f937 --- /dev/null +++ b/internal/feature/psiphonfeat/doc.go @@ -0,0 +1,4 @@ +// Package psiphonfeat implements the psiphon feature. When it is possible +// to enable this feature, we are able to start psiphon tunnels. Otherwise, it's +// not possible to start psiphon tunnels. +package psiphonfeat diff --git a/internal/feature/psiphonfeat/psiphon_enabled.go b/internal/feature/psiphonfeat/psiphon_enabled.go new file mode 100644 index 0000000000..6adc0222a4 --- /dev/null +++ b/internal/feature/psiphonfeat/psiphon_enabled.go @@ -0,0 +1,31 @@ +//go:build !go1.21 && !ooni_feature_disable_psiphon + +package psiphonfeat + +import ( + "context" + + "github.com/Psiphon-Labs/psiphon-tunnel-core/ClientLibrary/clientlib" +) + +// Enabled indicates whether this feature is enabled. +const Enabled = true + +// Start attempts to start the Psiphon tunnel and returns either a Tunnel or an error. +func Start(ctx context.Context, config []byte, workdir string) (Tunnel, error) { + tun, err := clientlib.StartTunnel(ctx, config, "", clientlib.Parameters{ + DataRootDirectory: &workdir}, nil, nil) + if err != nil { + return nil, err + } + return &tunnel{tun}, nil +} + +type tunnel struct { + *clientlib.PsiphonTunnel +} + +// GetSOCKSProxyPort implements Tunnel. +func (t *tunnel) GetSOCKSProxyPort() int { + return t.SOCKSProxyPort +} diff --git a/internal/feature/psiphonfeat/psiphon_otherwise.go b/internal/feature/psiphonfeat/psiphon_otherwise.go new file mode 100644 index 0000000000..9793121712 --- /dev/null +++ b/internal/feature/psiphonfeat/psiphon_otherwise.go @@ -0,0 +1,13 @@ +//go:build go1.21 || ooni_feature_disable_psiphon + +package psiphonfeat + +import "context" + +// Enabled indicates whether this feature is enabled. +const Enabled = false + +// Start attempts to start the Psiphon tunnel and returns either a Tunnel or an error. +func Start(ctx context.Context, config []byte, workdir string) (Tunnel, error) { + return nil, ErrFeatureNotEnabled +} diff --git a/internal/feature/psiphonfeat/tunnel.go b/internal/feature/psiphonfeat/tunnel.go new file mode 100644 index 0000000000..f7a339d115 --- /dev/null +++ b/internal/feature/psiphonfeat/tunnel.go @@ -0,0 +1,15 @@ +package psiphonfeat + +import "errors" + +// Tunnel is the interface implementing the Psiphon tunnel. +type Tunnel interface { + // Stop stops a running Psiphon tunnel. + Stop() + + // GetSOCKSProxyPort returns the SOCKS5 port used by the tunnel. + GetSOCKSProxyPort() int +} + +// ErrFeatureNotEnabled indicates that the Psiphon feature is not enabled in this build. +var ErrFeatureNotEnabled = errors.New("psiphonfeat: not enabled") diff --git a/internal/tunnel/psiphon.go b/internal/tunnel/psiphon.go index 322668df74..62c58d4470 100644 --- a/internal/tunnel/psiphon.go +++ b/internal/tunnel/psiphon.go @@ -8,14 +8,13 @@ import ( "path/filepath" "time" - "github.com/Psiphon-Labs/psiphon-tunnel-core/ClientLibrary/clientlib" + "github.com/ooni/probe-cli/v3/internal/feature/psiphonfeat" ) // mockableStartPsiphon allows us to test for psiphon startup failures. var mockableStartPsiphon = func( - ctx context.Context, config []byte, workdir string) (*clientlib.PsiphonTunnel, error) { - return clientlib.StartTunnel(ctx, config, "", clientlib.Parameters{ - DataRootDirectory: &workdir}, nil, nil) + ctx context.Context, config []byte, workdir string) (psiphonfeat.Tunnel, error) { + return psiphonfeat.Start(ctx, config, workdir) } // psiphonTunnel is a psiphon tunnel @@ -24,7 +23,7 @@ type psiphonTunnel struct { bootstrapTime time.Duration // tunnel is the underlying psiphon tunnel - tunnel *clientlib.PsiphonTunnel + tunnel psiphonfeat.Tunnel } // psiphonMakeWorkingDir creates the working directory @@ -81,7 +80,7 @@ func (t *psiphonTunnel) SOCKS5ProxyURL() *url.URL { return &url.URL{ Scheme: "socks5", Host: net.JoinHostPort( - "127.0.0.1", fmt.Sprintf("%d", t.tunnel.SOCKSProxyPort)), + "127.0.0.1", fmt.Sprintf("%d", t.tunnel.GetSOCKSProxyPort())), } } diff --git a/internal/tunnel/psiphon_integration_test.go b/internal/tunnel/psiphon_integration_test.go index 40e680cd27..4151fe5dd0 100644 --- a/internal/tunnel/psiphon_integration_test.go +++ b/internal/tunnel/psiphon_integration_test.go @@ -7,6 +7,7 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/engine" + "github.com/ooni/probe-cli/v3/internal/feature/psiphonfeat" "github.com/ooni/probe-cli/v3/internal/tunnel" ) @@ -14,6 +15,9 @@ func TestPsiphonStartStop(t *testing.T) { if testing.Short() { t.Skip("skip test in short mode") } + if !psiphonfeat.Enabled { + t.Skip("psiphon feature not enabled") + } tunnelDir, err := ioutil.TempDir("testdata", "psiphon") if err != nil { t.Fatal(err) diff --git a/internal/tunnel/psiphon_test.go b/internal/tunnel/psiphon_test.go index 1573a837bd..b39210d210 100644 --- a/internal/tunnel/psiphon_test.go +++ b/internal/tunnel/psiphon_test.go @@ -6,7 +6,7 @@ import ( "os" "testing" - "github.com/Psiphon-Labs/psiphon-tunnel-core/ClientLibrary/clientlib" + "github.com/ooni/probe-cli/v3/internal/feature/psiphonfeat" ) func TestPsiphonWithCancelledContext(t *testing.T) { @@ -87,7 +87,7 @@ func TestPsiphonStartFailure(t *testing.T) { mockableStartPsiphon = oldStartPsiphon }() mockableStartPsiphon = func(ctx context.Context, config []byte, - workdir string) (*clientlib.PsiphonTunnel, error) { + workdir string) (psiphonfeat.Tunnel, error) { return nil, expected } tunnel, _, err := psiphonStart(context.Background(), &Config{