diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index 15fddb4..8bd1758 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -24,7 +24,7 @@ runs: uses: actions/checkout@v4 with: repository: agynio/e2e - ref: main + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'agynio/e2e' && github.head_ref || 'main' }} path: e2e - name: Stage provider binary diff --git a/scripts/run-pipeline.sh b/scripts/run-pipeline.sh index 8cdf34e..9a4c025 100755 --- a/scripts/run-pipeline.sh +++ b/scripts/run-pipeline.sh @@ -416,7 +416,7 @@ EOF fi done - for env_name in CODEX_INIT_IMAGE AGN_INIT_IMAGE CLAUDE_INIT_IMAGE AGN_EXPOSE_INIT_IMAGE; do + for env_name in CODEX_INIT_IMAGE AGN_INIT_IMAGE CLAUDE_INIT_IMAGE AGN_EXPOSE_INIT_IMAGE EXPOSE_DEBUG_TOKEN EXPOSE_DEBUG_TOKEN_SECRET EXPOSE_DEBUG_ENDPOINT; do env_value=${!env_name:-} if [ -n "$env_value" ]; then exec_env+=("${env_name}=${env_value}") diff --git a/suites/go-core/tests/expose_test.go b/suites/go-core/tests/expose_test.go index a54a0fd..6281ef7 100644 --- a/suites/go-core/tests/expose_test.go +++ b/suites/go-core/tests/expose_test.go @@ -4,7 +4,6 @@ package tests import ( "context" - "crypto/tls" "encoding/json" "fmt" "io" @@ -27,66 +26,56 @@ import ( ) const ( - exposeTestTimeout = 8 * time.Minute - exposeCommandTimeout = 2 * time.Minute - exposeListTimeout = 30 * time.Second - exposeListEmptyTimeout = 60 * time.Second - exposeReachabilityTimeout = 90 * time.Second - exposeUnreachableTimeout = 90 * time.Second - exposeRequestTimeout = 15 * time.Second - exposeZitiRequestTimeout = 30 * time.Second - exposeDiagnosticsTimeout = 20 * time.Second - exposePort = 3000 - exposeExpectedResponse = "Hi! How are you?" - exposeStatusActive = "active" - zitiMgmtEndpointEnvKey = "ZITI_MGMT_ENDPOINT" - zitiMgmtServiceName = "ziti-mgmt" - zitiMgmtPath = "/edge/management/v1" - zitiDiagnosticsSecretName = "ziti-management-diagnostics" - zitiDiagnosticsUserKey = "username" - zitiDiagnosticsPasswordKey = "password" + exposeTestTimeout = 8 * time.Minute + exposeCommandTimeout = 2 * time.Minute + exposeListTimeout = 30 * time.Second + exposeListEmptyTimeout = 60 * time.Second + exposeReachabilityTimeout = 90 * time.Second + exposeUnreachableTimeout = 90 * time.Second + exposeRequestTimeout = 15 * time.Second + exposeZitiRequestTimeout = 30 * time.Second + exposeDiagnosticsTimeout = 20 * time.Second + exposePort = 3000 + exposeExpectedResponse = "Hi! How are you?" + exposeStatusActive = "active" + exposeDebugEndpointEnvKey = "EXPOSE_DEBUG_ENDPOINT" + exposeDebugTokenKey = "token" + exposeDebugTokenEnvKey = "EXPOSE_DEBUG_TOKEN" + exposeDebugTokenSecretKey = "EXPOSE_DEBUG_TOKEN_SECRET" ) -func TestZitiManagementEndpointDefaultUsesIngress(t *testing.T) { - t.Setenv(zitiMgmtEndpointEnvKey, "") - t.Setenv("E2E_DOMAIN", "e2e.agyn.dev") - t.Setenv("E2E_INGRESS_PORT", "30443") +func TestExposeDebugEndpointDefaultUsesService(t *testing.T) { + t.Setenv(exposeDebugEndpointEnvKey, "") + t.Setenv("E2E_NAMESPACE", "platform") - got := zitiManagementEndpoint() - want := "https://ziti-mgmt.e2e.agyn.dev:30443/edge/management/v1" + got := exposeDebugEndpoint() + want := "http://expose.platform.svc.cluster.local:8080" if got != want { - t.Fatalf("ziti management endpoint mismatch: got %q want %q", got, want) + t.Fatalf("expose debug endpoint mismatch: got %q want %q", got, want) } } -func TestZitiManagementEndpointExplicitOverride(t *testing.T) { - t.Setenv(zitiMgmtEndpointEnvKey, "https://custom.example.test:9443/edge/management/v1/") +func TestExposeDebugEndpointExplicitOverride(t *testing.T) { + t.Setenv(exposeDebugEndpointEnvKey, "http://custom.example.test:8080/") - got := zitiManagementEndpoint() - want := "https://custom.example.test:9443/edge/management/v1" + got := exposeDebugEndpoint() + want := "http://custom.example.test:8080" if got != want { - t.Fatalf("ziti management endpoint mismatch: got %q want %q", got, want) + t.Fatalf("expose debug endpoint mismatch: got %q want %q", got, want) } } -func TestZitiDiagnosticsSecretUsesPlatformNamespace(t *testing.T) { - secretNamespace, secretName := zitiDiagnosticsSecretRef() - if secretNamespace != "platform" { - t.Fatalf("ziti diagnostics secret namespace mismatch: got %q want %q", secretNamespace, "platform") +func TestExposeDebugTokenSecretExplicitRef(t *testing.T) { + t.Setenv(exposeDebugTokenSecretKey, "custom-platform/custom-secret") + secretNamespace, secretName, ok := exposeDebugTokenSecretRef() + if !ok { + t.Fatal("expected explicit secret ref") } - if secretName != zitiDiagnosticsSecretName { - t.Fatalf("ziti diagnostics secret name mismatch: got %q want %q", secretName, zitiDiagnosticsSecretName) - } -} - -func TestZitiDiagnosticsSecretUsesDevspaceNamespace(t *testing.T) { - t.Setenv("DEVSPACE_NAMESPACE", "custom-platform") - secretNamespace, secretName := zitiDiagnosticsSecretRef() if secretNamespace != "custom-platform" { - t.Fatalf("ziti diagnostics secret namespace mismatch: got %q want %q", secretNamespace, "custom-platform") + t.Fatalf("expose debug token secret namespace mismatch: got %q want %q", secretNamespace, "custom-platform") } - if secretName != zitiDiagnosticsSecretName { - t.Fatalf("ziti diagnostics secret name mismatch: got %q want %q", secretName, zitiDiagnosticsSecretName) + if secretName != "custom-secret" { + t.Fatalf("expose debug token secret name mismatch: got %q want %q", secretName, "custom-secret") } } @@ -652,18 +641,6 @@ func createZitiHTTPClient(t *testing.T) *http.Client { return httpClient } -type zitiManagementSession struct { - endpoint string - token string - client *http.Client -} - -type zitiAuthenticationResponse struct { - Data struct { - Token string `json:"token"` - } `json:"data"` -} - func logExposeTimeoutDiagnostics(t *testing.T, fixture exposeWorkloadFixture, exposure exposeEntry, exposedURL string) { t.Helper() t.Log("diagnostics: exposed service reachability timed out") @@ -673,7 +650,7 @@ func logExposeTimeoutDiagnostics(t *testing.T, fixture exposeWorkloadFixture, ex serviceName := fmt.Sprintf("exposed-%s", exposure.ID) logExposureDetails(t, exposure, serviceName, exposedURL) - logZitiExposureDiagnostics(t, diagnosticsCtx, serviceName, exposure) + logExposeDebugDiagnostics(t, diagnosticsCtx, exposure) logExposeWorkloadSidecarLogs(t, diagnosticsCtx, fixture) } @@ -701,130 +678,84 @@ func logExposureDetails(t *testing.T, exposure exposeEntry, serviceName, dialURL ) } -func logZitiExposureDiagnostics(t *testing.T, ctx context.Context, serviceName string, exposure exposeEntry) { +func logExposeDebugDiagnostics(t *testing.T, ctx context.Context, exposure exposeEntry) { t.Helper() - session, err := createZitiManagementSession(t, ctx) + token, err := exposeDebugToken(t, ctx) if err != nil { - t.Logf("diagnostics: ziti management unavailable: %v", err) + t.Logf("diagnostics: expose debug token unavailable: %v", err) return } - logZitiResource(t, ctx, session, "service", zitiFilterPath("/services", "name", serviceName)) - logZitiResource(t, ctx, session, "terminators", zitiFilterPath("/terminators", "service.name", serviceName)) - logZitiResource(t, ctx, session, "bind-policy", zitiFilterPath("/service-policies", "name", serviceName+"-bind")) - logZitiResource(t, ctx, session, "dial-policy", zitiFilterPath("/service-policies", "name", serviceName+"-dial")) - - if exposure.OpenZitiServiceID != "" { - logZitiResource(t, ctx, session, "service-by-id", "/services/"+url.PathEscape(exposure.OpenZitiServiceID)) - } - if exposure.OpenZitiBindPolicyID != "" { - logZitiResource(t, ctx, session, "bind-policy-by-id", "/service-policies/"+url.PathEscape(exposure.OpenZitiBindPolicyID)) - } - if exposure.OpenZitiDialPolicyID != "" { - logZitiResource(t, ctx, session, "dial-policy-by-id", "/service-policies/"+url.PathEscape(exposure.OpenZitiDialPolicyID)) - } -} - -func zitiFilterPath(resourcePath, field, value string) string { - return fmt.Sprintf("%s?filter=%s%%3D%%22%s%%22", resourcePath, url.QueryEscape(field), url.QueryEscape(value)) -} - -func createZitiManagementSession(t *testing.T, ctx context.Context) (zitiManagementSession, error) { - t.Helper() - username, password, err := zitiDiagnosticsCredentials(t, ctx) - if err != nil { - return zitiManagementSession{}, err - } - - endpoint := zitiManagementEndpoint() - client := &http.Client{ - Timeout: exposeRequestTimeout, - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, - } - payload := fmt.Sprintf(`{"username":%q,"password":%q}`, username, password) - request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint+"/authenticate?method=password", strings.NewReader(payload)) + endpoint := exposeDebugEndpoint() + requestURL := fmt.Sprintf("%s/debug/ziti/exposures/%s", endpoint, url.PathEscape(exposure.ID)) + request, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil) if err != nil { - return zitiManagementSession{}, fmt.Errorf("build authenticate request: %w", err) + t.Logf("diagnostics: expose debug request error: %v", err) + return } - request.Header.Set("Content-Type", "application/json") + request.Header.Set("X-Expose-Debug-Token", token) + client := &http.Client{Timeout: exposeRequestTimeout} response, err := client.Do(request) if err != nil { - return zitiManagementSession{}, fmt.Errorf("authenticate: %w", err) + t.Logf("diagnostics: expose debug query error: %v", err) + return } defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { - return zitiManagementSession{}, fmt.Errorf("read authenticate response: %w", err) - } - if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices { - return zitiManagementSession{}, fmt.Errorf("authenticate status %d body=%s", response.StatusCode, truncateLogLine(strings.TrimSpace(string(body)))) - } - - var auth zitiAuthenticationResponse - if err := json.Unmarshal(body, &auth); err != nil { - return zitiManagementSession{}, fmt.Errorf("parse authenticate response: %w", err) + t.Logf("diagnostics: expose debug read error: %v", err) + return } - token := strings.TrimSpace(auth.Data.Token) - if token == "" { - return zitiManagementSession{}, fmt.Errorf("authenticate response missing token") + trimmedBody := strings.TrimSpace(string(body)) + if trimmedBody == "" { + trimmedBody = "{}" } - return zitiManagementSession{endpoint: endpoint, token: token, client: client}, nil + t.Logf("diagnostics: expose debug status=%d body=%s", response.StatusCode, truncateLogLine(trimmedBody)) } -func zitiDiagnosticsCredentials(t *testing.T, ctx context.Context) (string, string, error) { +func exposeDebugToken(t *testing.T, ctx context.Context) (string, error) { t.Helper() - secretNamespace, secretName := zitiDiagnosticsSecretRef() + if token := strings.TrimSpace(envOrDefault(exposeDebugTokenEnvKey, "")); token != "" { + return token, nil + } + secretNamespace, secretName, ok := exposeDebugTokenSecretRef() + if !ok { + return "", fmt.Errorf("%s or %s must be set for expose debug diagnostics", exposeDebugTokenEnvKey, exposeDebugTokenSecretKey) + } secret, err := kubeClientset(t).CoreV1().Secrets(secretNamespace).Get(ctx, secretName, metav1.GetOptions{}) if err != nil { - return "", "", fmt.Errorf("get %s/%s: %w", secretNamespace, secretName, err) + return "", fmt.Errorf("get %s/%s: %w", secretNamespace, secretName, err) } - username := strings.TrimSpace(string(secret.Data[zitiDiagnosticsUserKey])) - password := strings.TrimSpace(string(secret.Data[zitiDiagnosticsPasswordKey])) - if username == "" || password == "" { - return "", "", fmt.Errorf("%s/%s missing diagnostics credentials", secretNamespace, secretName) + token := strings.TrimSpace(string(secret.Data[exposeDebugTokenKey])) + if token == "" { + return "", fmt.Errorf("%s/%s missing expose debug token", secretNamespace, secretName) } - return username, password, nil -} - -func zitiDiagnosticsSecretRef() (string, string) { - return envOrDefault("E2E_NAMESPACE", envOrDefault("DEVSPACE_NAMESPACE", "platform")), zitiDiagnosticsSecretName + return token, nil } -func zitiManagementEndpoint() string { - if explicitEndpoint := strings.TrimSpace(envOrDefault(zitiMgmtEndpointEnvKey, "")); explicitEndpoint != "" { - return strings.TrimRight(explicitEndpoint, "/") +func exposeDebugTokenSecretRef() (string, string, bool) { + ref := strings.TrimSpace(envOrDefault(exposeDebugTokenSecretKey, "")) + if ref == "" { + return "", "", false } - domain := envOrDefault("E2E_DOMAIN", envOrDefault("DOMAIN", "agyn.dev")) - port := envOrDefault("E2E_INGRESS_PORT", envOrDefault("INGRESS_PORT", envOrDefault("PORT", "2496"))) - return strings.TrimRight(fmt.Sprintf("https://%s.%s:%s%s", zitiMgmtServiceName, domain, port, zitiMgmtPath), "/") -} - -func logZitiResource(t *testing.T, ctx context.Context, session zitiManagementSession, label, path string) { - t.Helper() - request, err := http.NewRequestWithContext(ctx, http.MethodGet, session.endpoint+path, nil) - if err != nil { - t.Logf("diagnostics: ziti %s request error: %v", label, err) - return + parts := strings.Split(ref, "/") + if len(parts) == 1 { + namespace := envOrDefault("E2E_NAMESPACE", envOrDefault("DEVSPACE_NAMESPACE", "platform")) + return namespace, parts[0], true } - request.Header.Set("zt-session", session.token) - - response, err := session.client.Do(request) - if err != nil { - t.Logf("diagnostics: ziti %s query error: %v", label, err) - return - } - defer response.Body.Close() - body, err := io.ReadAll(response.Body) - if err != nil { - t.Logf("diagnostics: ziti %s read error: %v", label, err) - return + if len(parts) == 2 && strings.TrimSpace(parts[0]) != "" && strings.TrimSpace(parts[1]) != "" { + return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), true } - trimmedBody := strings.TrimSpace(string(body)) - if trimmedBody == "" { - trimmedBody = "{}" + return "", "", false +} + +func exposeDebugEndpoint() string { + if explicitEndpoint := strings.TrimSpace(envOrDefault(exposeDebugEndpointEnvKey, "")); explicitEndpoint != "" { + return strings.TrimRight(explicitEndpoint, "/") } - t.Logf("diagnostics: ziti %s status=%d body=%s", label, response.StatusCode, truncateLogLine(trimmedBody)) + namespace := envOrDefault("E2E_NAMESPACE", envOrDefault("DEVSPACE_NAMESPACE", "platform")) + return fmt.Sprintf("http://expose.%s.svc.cluster.local:8080", namespace) } func logExposeWorkloadSidecarLogs(t *testing.T, ctx context.Context, fixture exposeWorkloadFixture) { diff --git a/suites/playwright-chat-app/suite.yaml b/suites/playwright-chat-app/suite.yaml index cf24ec0..5eb9375 100644 --- a/suites/playwright-chat-app/suite.yaml +++ b/suites/playwright-chat-app/suite.yaml @@ -25,7 +25,14 @@ run: | export E2E_BASE_URL="${E2E_BASE_URL:-https://chat.${E2E_DOMAIN}}" npm ci --no-fund --no-audit - npx buf generate + mkdir -p .bin + curl -fsSL --retry 3 --retry-delay 5 \ + -o .bin/buf \ + "https://github.com/bufbuild/buf/releases/download/v1.68.4/buf-$(uname -s)-$(uname -m)" + chmod +x .bin/buf + export PATH="$PWD/.bin:$PWD/node_modules/.bin:$PATH" + buf --version + buf generate grep_tags="" if [ -n "${TAGS:-}" ]; then diff --git a/suites/playwright-tracing-app/suite.yaml b/suites/playwright-tracing-app/suite.yaml index 230c68b..adfcca5 100644 --- a/suites/playwright-tracing-app/suite.yaml +++ b/suites/playwright-tracing-app/suite.yaml @@ -25,7 +25,14 @@ run: | cd /opt/app/data npm ci --no-fund --no-audit - npx buf generate + mkdir -p .bin + curl -fsSL --retry 3 --retry-delay 5 \ + -o .bin/buf \ + "https://github.com/bufbuild/buf/releases/download/v1.68.4/buf-$(uname -s)-$(uname -m)" + chmod +x .bin/buf + export PATH="$PWD/.bin:$PWD/node_modules/.bin:$PATH" + buf --version + buf generate export E2E_DOMAIN="${E2E_DOMAIN:-agyn.dev}" export E2E_BASE_URL="${E2E_BASE_URL:-https://tracing.${E2E_DOMAIN}}" diff --git a/suites/playwright/suite.yaml b/suites/playwright/suite.yaml index 9bd5bde..e60bdce 100644 --- a/suites/playwright/suite.yaml +++ b/suites/playwright/suite.yaml @@ -24,7 +24,14 @@ run: | export E2E_BASE_URL="${E2E_BASE_URL:-https://console.${E2E_DOMAIN}}" npm ci --no-fund --no-audit - npx buf generate + mkdir -p .bin + curl -fsSL --retry 3 --retry-delay 5 \ + -o .bin/buf \ + "https://github.com/bufbuild/buf/releases/download/v1.68.4/buf-$(uname -s)-$(uname -m)" + chmod +x .bin/buf + export PATH="$PWD/.bin:$PWD/node_modules/.bin:$PATH" + buf --version + buf generate grep_tags="" if [ -n "${TAGS:-}" ]; then