Skip to content

wfctl validate: no cross-reference checking for DB columns, step output fields, or imported configs #368

@intel352

Description

@intel352

Summary

wfctl validate and wfctl template validate check structural correctness (valid YAML, known module/step/trigger types, step name existence) but do not validate field-level references across the data flow. When a DB column is renamed, a step output field changes, or a cross-file import breaks, there is no static check that catches it — the error only surfaces at runtime.

What is validated today

Check Status
Valid YAML syntax
Known module types
Known step types
Known trigger types
Step name references (steps.X exists)
Forward references (step references later step)
Self-references (step references itself)

What is NOT validated

Check Status Example
Step output field names steps.query.row.nonexistent_column
DB column alignment SQL returns auth_token but template reads token
Step type output schema step.db_query mode=single produces {row, found} but not checked
Cross-file import targets Imported YAML may reference pipelines/steps that don't exist
Conditional field paths field: "steps.query.found" in step.conditional — found not validated
secret_from paths secret_from: steps.load_integration.row.auth_token — not validated
backend_url_key paths backend_url_key: "row.backend_url" — not validated

Real-world example

From a production pipeline (messaging.yaml):

- name: load_integration
  type: step.db_query
  config:
    query: >
      SELECT provider_config->>'auth_token' AS auth_token, affiliate_id
      FROM messaging_integrations WHERE id = $1
    mode: single

- name: verify
  type: step.webhook_verify
  config:
    secret_from: steps.load_integration.row.auth_token  # references SQL alias

- name: upsert_texter
  type: step.db_exec
  config:
    query: >
      INSERT INTO messaging_texters_{{.steps.load_integration.row.affiliate_id}}

If someone renames the SQL alias auth_tokentoken or affiliate_idtenant_id:

  • wfctl validate passes ✅
  • wfctl template validate passes ✅ (only checks that load_integration step exists)
  • Pipeline fails at runtime with empty/wrong values

Proposed approach

1. Step type output schema registry

Each built-in step type could declare its output schema:

// step.db_query output schema depends on mode
func (s *DBQueryStep) OutputSchema(config map[string]any) map[string]FieldType {
    mode := config["mode"]
    switch mode {
    case "single":
        return map[string]FieldType{"row": Object, "found": Bool}
    case "list":
        return map[string]FieldType{"rows": Array, "count": Int}
    }
}

2. Deep template reference validation

Extend validateStepRef to walk the full dot-path:

  • steps.auth → check step exists ✅ (already done)
  • steps.auth.affiliate_id → check auth step type's output schema for affiliate_id
  • steps.query.row.column_name → check query step type's output schema for row, warn that column_name cannot be statically verified (depends on SQL)

3. SQL alias extraction (best-effort)

For step.db_query, parse the SQL SELECT clause to extract column aliases, then validate references against them. This would be best-effort (can't handle SELECT * or dynamic SQL) but would catch the most common case.

4. Cross-file import validation

When processing imports:, verify that all step names and pipeline names referenced in templates actually exist in the merged config.

References

  • Current validation: cmd/wfctl/validate.go:117-150
  • Template validation: cmd/wfctl/template_validate.go:568-646 (step name only)
  • Step ref regex: cmd/wfctl/template_validate.go:569 — stops at step name, ignores field path
  • Pipeline context types: interfaces/pipeline.go:46-60map[string]any throughout
  • Related: Template missingkey=zero silently swallows field-level typos in step references #367 (missingkey=zero silently swallows typos at runtime)

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions