Skip to content

[plan] Fix single-quote escaping bug in formatYAMLValue YAML step generator #21133

@github-actions

Description

@github-actions

Context

Identified in Sergo Audit Discussion #20993 — YAML Step Generator Audit + Context-Propagation Revisit (2026-03-14, score 8/10).

Problem

formatYAMLValue in pkg/workflow/runtime_step_generator.go wraps all string values in YAML single quotes via fmt.Sprintf("'%s'", v) without ever escaping embedded ' characters as ''. Per the YAML spec, single-quoted scalars represent a literal ' only via ''. Any user-configured ExtraFields value or engine version string containing a single quote will produce syntactically invalid workflow YAML at GitHub Actions parse time — with no error at gh aw compile time.

Affected locations:

  • pkg/workflow/runtime_step_generator.go:162–174formatYAMLValue string case: fmt.Sprintf("'%s'", v)
  • pkg/workflow/runtime_step_generator.go:125 — version field: fmt.Sprintf(" %s: '%s'", runtime.VersionField, version)
  • pkg/workflow/runtime_step_generator.go:206 — default case: fmt.Sprintf("'%v'", v)

Impact: Users who include single-quote characters in any runtime.setup.with.* field or engine version string silently receive broken generated workflow YAML.

Approach

  1. Add a singleQuoteYAML helper function in runtime_step_generator.go:
    // singleQuoteYAML escapes a string for use in a YAML single-quoted scalar.
    // The only escape in single-quoted YAML is '' for a literal single quote.
    func singleQuoteYAML(s string) string {
        return "'" + strings.ReplaceAll(s, "'", "''") + "'"
    }
  2. Replace all three unescaped fmt.Sprintf("'%s'", v) / fmt.Sprintf("'%v'", v) occurrences with calls to singleQuoteYAML.
  3. Update the version field formatting on line 125 to use singleQuoteYAML(version).

Files to Modify

  • pkg/workflow/runtime_step_generator.go — add helper, fix 3 call sites
  • pkg/workflow/runtime_step_generator_test.go — add unit tests

Acceptance Criteria

  • singleQuoteYAML helper exists and is tested: singleQuoteYAML("it's")"'it''s'", singleQuoteYAML("O'Brien")"'O''Brien'"
  • All three unescaped quote sites replaced with singleQuoteYAML
  • Generated workflow YAML containing ExtraFields with single quotes round-trips through gopkg.in/yaml.v3 without error
  • make agent-finish passes (build, test, lint, fmt)

Generated by Plan Command for issue #discussion #20993 ·

  • expires on Mar 17, 2026, 11:03 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions