From 53ee54327034257f49a435b0412346b24c3d8e91 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 7 Jun 2026 18:03:09 -0400 Subject: [PATCH 1/2] fix(wfctl): validate infra secret pseudo-modules --- cmd/wfctl/main_test.go | 23 +++++++++++++++++++++++ cmd/wfctl/validate.go | 8 ++++++++ 2 files changed, 31 insertions(+) diff --git a/cmd/wfctl/main_test.go b/cmd/wfctl/main_test.go index bdba56c82..079b43ec4 100644 --- a/cmd/wfctl/main_test.go +++ b/cmd/wfctl/main_test.go @@ -245,6 +245,29 @@ func TestRunValidateValid(t *testing.T) { } } +func TestRunValidateAllowsInfraSecretPseudoModules(t *testing.T) { + dir := t.TempDir() + cfg := ` +modules: + - name: required-secrets + type: secrets.requires + config: + requires: + - key: EXTERNAL_API_TOKEN + - name: generated-secrets + type: secrets.generate + config: + generate: + - key: DATABASE_URL + type: infra_output + source: database.uri +` + path := writeTestConfig(t, dir, "infra-secrets.yaml", cfg) + if err := runValidate([]string{"--allow-no-entry-points", path}); err != nil { + t.Fatalf("expected secrets pseudo-modules to validate, got: %v", err) + } +} + func TestRunValidateInvalid(t *testing.T) { dir := t.TempDir() path := writeTestConfig(t, dir, "invalid.yaml", invalidConfig) diff --git a/cmd/wfctl/validate.go b/cmd/wfctl/validate.go index adbbfb8c7..5a08236bb 100644 --- a/cmd/wfctl/validate.go +++ b/cmd/wfctl/validate.go @@ -181,6 +181,14 @@ func validateFile(cfgPath string, strict, skipUnknownTypes, allowNoEntryPoints, opts = append(opts, schema.WithAllowNoEntryPoints()) } + // Infra pseudo-modules are consumed by wfctl infra plan/align/bootstrap, + // not by the runtime engine, so keep them local to CLI validation rather + // than adding them to the engine's core module registry. + opts = append(opts, + schema.WithExtraModuleTypes("secrets.generate"), + schema.WithExtraModuleTypes("secrets.requires"), + ) + // Pass legacy DO module types through schema validation so the actionable // migration error fires below instead of a generic "unknown module type". for t := range legacydo.ModuleTypes { From ca87138d74877717b0b4b5d32ff6bcd758f41245 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 7 Jun 2026 18:11:07 -0400 Subject: [PATCH 2/2] fix(wfctl): scope secret pseudo-module validation --- cmd/wfctl/main_test.go | 36 ++++++++++++++++++++++++++++++++++++ cmd/wfctl/validate.go | 16 +++++++++------- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/cmd/wfctl/main_test.go b/cmd/wfctl/main_test.go index 079b43ec4..3c3b32247 100644 --- a/cmd/wfctl/main_test.go +++ b/cmd/wfctl/main_test.go @@ -268,6 +268,42 @@ modules: } } +func TestRunValidateRejectsInfraSecretPseudoModulesByDefault(t *testing.T) { + dir := t.TempDir() + cfg := ` +modules: + - name: required-secrets + type: secrets.requires + config: + requires: + - key: EXTERNAL_API_TOKEN + - name: server + type: http.server + config: + address: ":8080" +pipelines: + ping: + trigger: + type: http + config: + path: /ping + method: GET + steps: + - name: log + type: step.log + config: + message: pong +` + path := writeTestConfig(t, dir, "app-with-infra-secret.yaml", cfg) + err := runValidate([]string{path}) + if err == nil { + t.Fatal("expected default validation to reject infra-only secrets pseudo-modules") + } + if !strings.Contains(err.Error(), `unknown module type "secrets.requires"`) { + t.Fatalf("expected unknown secrets.requires module type error, got: %v", err) + } +} + func TestRunValidateInvalid(t *testing.T) { dir := t.TempDir() path := writeTestConfig(t, dir, "invalid.yaml", invalidConfig) diff --git a/cmd/wfctl/validate.go b/cmd/wfctl/validate.go index 5a08236bb..f863ff7a7 100644 --- a/cmd/wfctl/validate.go +++ b/cmd/wfctl/validate.go @@ -181,13 +181,15 @@ func validateFile(cfgPath string, strict, skipUnknownTypes, allowNoEntryPoints, opts = append(opts, schema.WithAllowNoEntryPoints()) } - // Infra pseudo-modules are consumed by wfctl infra plan/align/bootstrap, - // not by the runtime engine, so keep them local to CLI validation rather - // than adding them to the engine's core module registry. - opts = append(opts, - schema.WithExtraModuleTypes("secrets.generate"), - schema.WithExtraModuleTypes("secrets.requires"), - ) + if allowNoEntryPoints && !skipUnknownTypes { + // Infra pseudo-modules are consumed by wfctl infra plan/align/bootstrap, + // not by the runtime engine, so keep them scoped to infra-style CLI + // validation rather than adding them to the engine's core registry. + opts = append(opts, + schema.WithExtraModuleTypes("secrets.generate"), + schema.WithExtraModuleTypes("secrets.requires"), + ) + } // Pass legacy DO module types through schema validation so the actionable // migration error fires below instead of a generic "unknown module type".