From 214b00720a6c3c89e5dec8294e705e6a0da7319c Mon Sep 17 00:00:00 2001 From: eding Date: Sun, 6 Sep 2026 09:51:05 +0200 Subject: [PATCH] fix: defer webhook refresh until Tekton exists --- internal/openbao/bootstrap.go | 7 +++++++ internal/openbao/bootstrap_test.go | 21 ++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/internal/openbao/bootstrap.go b/internal/openbao/bootstrap.go index 7cdf029..5a061dc 100644 --- a/internal/openbao/bootstrap.go +++ b/internal/openbao/bootstrap.go @@ -330,6 +330,13 @@ func refreshExternalSecrets(kubeconfig string) error { if err != nil { return fmt.Errorf("refresh OpenBao secret store after seed: %w", err) } + webhook, err := kubectlOutput(kubeconfig, "get", "externalsecret", "forgejo-webhook", "-n", "tekton-pipelines", "--ignore-not-found", "-o=name") + if err != nil { + return fmt.Errorf("check Forgejo webhook ExternalSecret after OpenBao seed: %w", err) + } + if strings.TrimSpace(string(webhook)) == "" { + return nil + } _, err = kubectlOutput(kubeconfig, externalSecretRefreshArgs(timestamp)...) if err != nil { return fmt.Errorf("refresh ExternalSecrets after OpenBao seed: %w", err) diff --git a/internal/openbao/bootstrap_test.go b/internal/openbao/bootstrap_test.go index 4bc7f90..49ae22b 100644 --- a/internal/openbao/bootstrap_test.go +++ b/internal/openbao/bootstrap_test.go @@ -84,13 +84,32 @@ func TestRefreshExternalSecretsIsReadyGatedAndScoped(t *testing.T) { if len(calls) == 1 { return []byte("True"), nil } + if len(calls) == 3 { + return []byte("externalsecret.external-secrets.io/forgejo-webhook"), nil + } return nil, nil } - if err := refreshExternalSecrets("kubeconfig"); err != nil || len(calls) != 3 || !strings.Contains(calls[0], "get deployment/external-secrets") || !strings.Contains(calls[1], "annotate clustersecretstore openbao") || !strings.Contains(calls[2], "annotate externalsecret forgejo-webhook") || strings.Contains(calls[1], "--all") || strings.Contains(calls[2], "--all") { + if err := refreshExternalSecrets("kubeconfig"); err != nil || len(calls) != 4 || !strings.Contains(calls[0], "get deployment/external-secrets") || !strings.Contains(calls[1], "annotate clustersecretstore openbao") || !strings.Contains(calls[2], "get externalsecret forgejo-webhook") || !strings.Contains(calls[3], "annotate externalsecret forgejo-webhook") || strings.Contains(calls[1], "--all") || strings.Contains(calls[3], "--all") { t.Fatalf("ExternalSecret refresh was not readiness-gated and scoped: %q, %v", calls, err) } } +func TestRefreshExternalSecretsSkipsWebhookBeforeTekton(t *testing.T) { + original := kubectlOutput + t.Cleanup(func() { kubectlOutput = original }) + var calls []string + kubectlOutput = func(_ string, args ...string) ([]byte, error) { + calls = append(calls, strings.Join(args, " ")) + if len(calls) == 1 { + return []byte("True"), nil + } + return nil, nil + } + if err := refreshExternalSecrets("kubeconfig"); err != nil || len(calls) != 3 || !strings.Contains(calls[2], "--ignore-not-found") { + t.Fatalf("missing webhook ExternalSecret was not safely skipped: %q, %v", calls, err) + } +} + func TestReadRecoveryMaterialDecryptsAndValidatesBundle(t *testing.T) { original := decryptRecovery t.Cleanup(func() { decryptRecovery = original })