Skip to content

[#182] Fix YAML quoting gaps in ManifestBuilder export#190

Merged
bguidolim merged 1 commit intomainfrom
feature/182-yaml-quoting-gaps
Mar 1, 2026
Merged

[#182] Fix YAML quoting gaps in ManifestBuilder export#190
bguidolim merged 1 commit intomainfrom
feature/182-yaml-quoting-gaps

Conversation

@bguidolim
Copy link
Copy Markdown
Collaborator

@bguidolim bguidolim commented Mar 1, 2026

Closes #182

Context

ManifestBuilder emits several string values into generated techpack.yaml without YAML quoting. User-controlled strings containing #, : , &, newlines, or tabs produce invalid YAML that silently breaks on mcs pack add.

Changes

  • Harden yamlQuote(): detect and escape \n and \t control characters
  • Quote high-risk fields: metadata description and author (via quoted: true), component description and MCP url (via yamlQuote())
  • Defense-in-depth: quote sectionIdentifier, contentFile, prompt key, MCP command, source/destination, and settingsFile
  • Sanitize MCP server IDs: apply sanitizeID() to server names at construction time
  • 4 new round-trip tests: special characters in metadata, newlines/tabs, URL fragments, component descriptions with #

Test plan

  • swift test --filter MCSTests.ManifestBuilderTests — 7/7 pass (3 existing + 4 new)
  • swift test — 585/585 pass, zero regressions

Copilot AI review requested due to automatic review settings March 1, 2026 23:13
@bguidolim bguidolim force-pushed the feature/182-yaml-quoting-gaps branch from ed38378 to fd8c067 Compare March 1, 2026 23:17
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens ManifestBuilder’s YAML serialization so user-controlled strings can’t accidentally generate invalid techpack.yaml, improving reliability of mcs pack add and related manifest loading/validation.

Changes:

  • Extended yamlQuote() to detect and escape newline/tab characters.
  • Applied quoting to additional high-risk manifest fields (metadata, templates, prompts, MCP config, file paths, settingsFile).
  • Added 4 round-trip tests covering special characters, control characters, URL fragments, and component descriptions.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
Sources/mcs/Export/ManifestBuilder.swift Expands YAML quoting/escaping and applies it across more emitted manifest fields.
Tests/MCSTests/ManifestBuilderTests.swift Adds new round-trip tests validating YAML quoting edge cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -441,7 +441,7 @@ struct ManifestBuilder {
}

yaml.line(" - id: \(comp.id)")
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Component id is emitted without YAML quoting/escaping. For MCP server components the id is built from the discovered server name (mcp-\(server.name)), which can contain user-controlled characters like : , #, or tabs/newlines; those can make the YAML invalid even though description is now quoted. Consider applying yamlQuote to comp.id during rendering (or sanitizing the MCP server name when forming the id) to close this remaining quoting gap.

Suggested change
yaml.line(" - id: \(comp.id)")
yaml.line(" - id: \(yamlQuote(comp.id))")

Copilot uses AI. Check for mistakes.
@@ -332,9 +332,9 @@ struct ManifestBuilder {
yaml.keyValue("schemaVersion", manifest.schemaVersion)
yaml.keyValue("identifier", manifest.identifier)
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

identifier is user-provided (ExportCommand prompts for it) and is still emitted without YAML quoting/escaping. If the user enters values containing YAML-significant sequences (e.g. : , #, leading &, etc.), the generated techpack.yaml can still become invalid YAML. Consider passing quoted: true here (or running it through yamlQuote) so parsing succeeds and schema validation can fail with a clearer error instead of a YAML decode failure.

Suggested change
yaml.keyValue("identifier", manifest.identifier)
yaml.keyValue("identifier", manifest.identifier, quoted: true)

Copilot uses AI. Check for mistakes.
- Add \n and \t detection and escaping to yamlQuote()
- Quote metadata description, author, component descriptions, URLs, and hookEvent
- Sanitize MCP server names in component IDs via sanitizeID()
- Add 4 round-trip tests for special characters, newlines, and URL fragments
@bguidolim bguidolim force-pushed the feature/182-yaml-quoting-gaps branch from fd8c067 to c907522 Compare March 1, 2026 23:24
@bguidolim bguidolim merged commit 75cbf24 into main Mar 1, 2026
3 checks passed
@bguidolim bguidolim deleted the feature/182-yaml-quoting-gaps branch March 1, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

YAML quoting gaps in ManifestBuilder export output

2 participants