Problem
render_rich passes cell values to Rich without escaping, so any user-authored string containing square brackets is read as Rich markup. Bracket prefixes are a common naming convention for pipes and automation rules, so this hits real data.
Evidence
pipefy automation list on a pipe whose rules use bracketed names:
'[on hold] escalate' printed 'escalate' <-- prefix silently deleted
'[blue] team notify' printed 'team notify' <-- prefix silently deleted
'Notify [/marketing] team' CRASH exit 1 MarkupError
'[HR] Performance Evaluation' survives
'[SLA/2h] warn' survives
rich.errors.MarkupError: closing tag '[/marketing]' at position 7 doesn't match any open tag.
Whether a name breaks depends on whether the bracketed text happens to parse as a Rich tag, so a smoke test with one sample name will not catch it.
packages/cli/src/pipefy_cli/output/rich_renderer.py:49-57 — _render_list_of_dicts calls table.add_row(*(str(row.get(k, "")) for k in keys)).
- Any command that renders a list of dicts is affected, not only
automation list.
Scope
- Build the table with
markup=False, or run each cell through rich.markup.escape.
- One test with a name that deletes a tag and one with a name that raises.
Acceptance
Problem
render_richpasses cell values to Rich without escaping, so any user-authored string containing square brackets is read as Rich markup. Bracket prefixes are a common naming convention for pipes and automation rules, so this hits real data.Evidence
pipefy automation liston a pipe whose rules use bracketed names:rich.errors.MarkupError: closing tag '[/marketing]' at position 7 doesn't match any open tag.Whether a name breaks depends on whether the bracketed text happens to parse as a Rich tag, so a smoke test with one sample name will not catch it.
packages/cli/src/pipefy_cli/output/rich_renderer.py:49-57—_render_list_of_dictscallstable.add_row(*(str(row.get(k, "")) for k in keys)).automation list.Scope
markup=False, or run each cell throughrich.markup.escape.Acceptance
[on hold] escalateprints with its prefix intact.Notify [/marketing] teamprints instead of raising.