Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion cliv2/internal/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"os"
"time"

"github.com/snyk/cli/cliv2/internal/proxy/interceptor"

Expand Down Expand Up @@ -221,13 +222,55 @@ func (p *WrapperProxy) Start() error {
p.port = l.Addr().(*net.TCPAddr).Port
p.DebugLogger.Print("Wrapper proxy is listening on port: ", p.port)

// Start the server in a goroutine
serverErr := make(chan error, 1)
go func() {
_ = p.httpServer.Serve(l) // this blocks until the server stops and gives you an error which can be ignored
// http.Server.Serve will return an error if it fails to start
// or nil when the server is shut down
if serveErr := p.httpServer.Serve(l); serveErr != nil && serveErr != http.ErrServerClosed {
serverErr <- serveErr
}
}()

// Wait for the server to be ready by attempting to connect to it
// This prevents a race condition where the legacy CLI tries to connect
// before the proxy server is ready to accept connections
err = p.waitForProxyReady(serverErr)
if err != nil {
return fmt.Errorf("proxy server failed to become ready: %w", err)
}

return nil
}

// waitForProxyReady waits for the proxy server to be ready to accept connections
// by attempting to connect to it with retries. It also checks for server startup errors.
func (p *WrapperProxy) waitForProxyReady(serverErr chan error) error {
maxRetries := 10
retryDelay := 50 * time.Millisecond

for i := 0; i < maxRetries; i++ {
// Check if server failed to start
select {
case err := <-serverErr:
return fmt.Errorf("proxy server failed to start: %w", err)
default:
// Server hasn't reported an error yet, continue checking readiness
}

// Try to connect to verify the server is ready
conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", p.port), 100*time.Millisecond)
if err == nil {
conn.Close()
p.DebugLogger.Print("Proxy server is ready")
return nil
}
time.Sleep(retryDelay)
}

return fmt.Errorf("proxy server did not become ready after %d attempts", maxRetries)
}

func (p *WrapperProxy) Stop() {
err := p.httpServer.Shutdown(context.Background())
if err == nil {
Expand Down
9 changes: 3 additions & 6 deletions src/cli/commands/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ import {
} from '../../../lib/spotlight-vuln-notification';
import iacTestCommand from './iac';
import * as iacTestCommandV2 from './iac/v2';
import {
hasFeatureFlag,
hasFeatureFlagOrDefault,
} from '../../../lib/feature-flags';
import { hasFeatureFlagOrDefault } from '../../../lib/feature-flags';
import {
SCAN_USR_LIB_JARS_FEATURE_FLAG,
CONTAINER_CLI_APP_VULNS_ENABLED_FEATURE_FLAG,
Expand Down Expand Up @@ -76,8 +73,8 @@ export default async function test(
const options = setDefaultTestOptions(originalOptions);

if (originalOptions.iac) {
const iacNewEngine = await hasFeatureFlag('iacNewEngine', options);
const iacIntegratedExperience = await hasFeatureFlag(
const iacNewEngine = await hasFeatureFlagOrDefault('iacNewEngine', options);
const iacIntegratedExperience = await hasFeatureFlagOrDefault(
'iacIntegratedExperience',
options,
);
Expand Down