Skip to content

fix(labels): escape single quotes in custom label descriptions#2320

Open
gvago wants to merge 2 commits intomainfrom
fix/custom-labels-quote-escape
Open

fix(labels): escape single quotes in custom label descriptions#2320
gvago wants to merge 2 commits intomainfrom
fix/custom-labels-quote-escape

Conversation

@gvago
Copy link
Copy Markdown

@gvago gvago commented Apr 14, 2026

Summary

  • Bug: set_custom_labels() in pr_agent/algo/utils.py wraps label descriptions in single quotes without escaping. A description like Don't merge produces the malformed string 'Don't merge', breaking the generated custom_labels_class Enum schema sent to the LLM.
  • Fix: Added .replace("'", "\\'") to escape single quotes in descriptions before they are wrapped in single-quote delimiters. This is chained after the existing .replace('\n', '\\n') call on line 959.
  • Affects both pr_description.py and pr_generate_labels.py since both call the shared set_custom_labels() utility.

Test plan

  • Configure a custom label with a single-quote in its description (e.g., description = "Don't merge this")
  • Run /describe or /generate_labels and verify the generated custom_labels_class contains properly escaped strings
  • Verify labels without single quotes still work unchanged

🤖 Generated with Claude Code

When custom label descriptions contain single quotes (e.g., "Don't merge"),
the generated `custom_labels_class` Enum produces malformed Python string
literals. This adds `.replace("'", "\\'")` to escape embedded single quotes
before wrapping the description in single-quote delimiters.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Escape single quotes in custom label descriptions

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Escape single quotes in custom label descriptions
• Prevents malformed Python string literals in generated Enum
• Fixes labels with apostrophes like "Don't merge"
Diagram
flowchart LR
  A["Custom label description<br/>with single quote"] -->|escape single quotes| B["Properly formatted<br/>Python string literal"]
  B -->|generate Enum| C["Valid custom_labels_class"]
Loading

Grey Divider

File Changes

1. pr_agent/algo/utils.py 🐞 Bug fix +1/-1

Escape single quotes in label descriptions

• Added .replace("'", "\\'") to escape single quotes in label descriptions
• Chained after existing newline replacement on line 960
• Prevents malformed Python string literals in generated Enum schema

pr_agent/algo/utils.py


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 14, 2026

Code Review by Qodo

🐞 Bugs (2)   📘 Rule violations (1)   📎 Requirement gaps (0)
🐞\ ≡ Correctness (2) ⭐ New (2)
📘\ ⚙ Maintainability (1) ⭐ New (1)

Grey Divider


Action required

1. v['description'] not validated📘
Description
set_custom_labels() indexes v['description'] and calls string methods on it without validating
that v is a dict and description is a non-null string. A malformed or missing description in
user-provided custom_labels can raise KeyError/AttributeError and break label generation.
Code

pr_agent/algo/utils.py[959]

+        description = "'" + v['description'].strip('\n').replace('\n', '\\n').replace("'", "\\'") + "'"
Evidence
The checklist requires defensive validation of external/user-provided configuration values and
robust handling of edge cases. The changed line directly indexes v['description'] and calls
.strip()/.replace() with no type/null checks or safe access, so unexpected shapes in
custom_labels can crash at runtime.

Rule 3: Robust Error Handling
pr_agent/algo/utils.py[959-959]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`set_custom_labels()` assumes each `labels.items()` value is a dict with a string `description`, and calls string methods without null/type checks. This can crash on malformed user configuration.
## Issue Context
`labels` comes from `get_settings().get('custom_labels', {})`, which is user-configured input.
## Fix Focus Areas
- pr_agent/algo/utils.py[959-959]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. New single-quoted literals added 📘
Description
The newly added string literals use single quotes (e.g., v.get('description', '') and
.strip('\n')) which conflicts with the repository convention in this checklist to prefer double
quotes. This can introduce style/lint inconsistencies in touched code.
Code

pr_agent/algo/utils.py[R959-960]

+        description = v.get('description', '') if isinstance(v, dict) else str(v)
+        description = "'" + description.strip('\n').replace('\n', '\\n').replace("'", "\\'") + "'"
Evidence
PR Compliance ID 8 requires adhering to the repository formatting conventions, including preferring
double quotes for string literals. The added code introduces multiple new single-quoted literals.

AGENTS.md
pr_agent/algo/utils.py[959-960]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New code introduces single-quoted string literals where the checklist requires double quotes.

## Issue Context
To avoid style drift and potential formatter/linter noise, keep new literals aligned with the configured convention.

## Fix Focus Areas
- pr_agent/algo/utils.py[959-960]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Silent empty descriptions 🐞
Description
set_custom_labels() now defaults to an empty string when a custom label entry has no
description, producing Label Enum members with empty values. This silently removes the label
meaning that the prompt instructs the LLM to rely on, making misconfigurations hard to detect and
reducing labeling quality.
Code

pr_agent/algo/utils.py[R959-960]

+        description = v.get('description', '') if isinstance(v, dict) else str(v)
+        description = "'" + description.strip('\n').replace('\n', '\\n').replace("'", "\\'") + "'"
Evidence
The PR changes behavior from v['description'] (fail-fast if missing) to v.get('description','')
(silent empty), and the prompts explicitly instruct the model to use the Enum value (description) to
understand label meaning; the repo’s custom label template also defines labels with a description
field.

pr_agent/algo/utils.py[941-966]
pr_agent/settings/pr_custom_labels.toml[17-34]
pr_agent/settings/custom_labels.toml[2-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`set_custom_labels()` now silently uses an empty string when a label entry is missing `description`, producing Enum values that provide no meaning to the LLM. This should be treated as a configuration error (fail-fast) or at least fall back to a non-empty value (e.g., the label name) while logging a clear warning.

### Issue Context
The LLM prompt for labels explicitly says to use the `Label` value field to understand the label meaning; empty values degrade label selection and make misconfiguration hard to debug.

### Fix Focus Areas
- pr_agent/algo/utils.py[941-966]
- pr_agent/settings/pr_custom_labels.toml[17-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Invalid Enum member names 🐞
Description
Enum member identifiers are derived from label names by only lowercasing and replacing spaces, so
labels containing characters like : generate malformed Label Enum definitions in the prompt
schema. This can break the schema shown to the LLM for documented label names such as `Main
topic:performance`.
Code

pr_agent/algo/utils.py[R962-963]

        variables["custom_labels_class"] += f"\n    {k.lower().replace(' ', '_')} = {description}"
        labels_minimal_to_labels_dict[k.lower().replace(' ', '_')] = k
Evidence
set_custom_labels() builds a Python-like Enum class definition string using `k.lower().replace('
', '_'), which does not sanitize characters like :` into valid identifiers. The repo documentation
explicitly gives Main topic:performance as a custom label example, which would produce an invalid
identifier (main_topic:performance) in the generated class injected into prompts.

pr_agent/algo/utils.py[954-966]
docs/docs/tools/describe.md[229-240]
pr_agent/settings/pr_custom_labels.toml[19-23]
pr_agent/settings/pr_description_prompts.toml[20-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`set_custom_labels()` generates Enum member names from arbitrary label names but only replaces spaces, so labels containing `:`, `-`, `/`, leading digits, etc. can produce invalid identifiers and a malformed Enum schema in prompts.

### Issue Context
Docs show example label names with `:` (e.g., `Main topic:performance`). The generated `custom_labels_class` is embedded into both label-generation and description prompts, so malformed Enum text can confuse the model.

### Fix Focus Areas
- pr_agent/algo/utils.py[954-966]
- docs/docs/tools/describe.md[229-240]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Grey Divider

Previous review results

Review updated until commit 9314319

Results up to commit N/A


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider
Action required
1. v['description'] not validated📘
Description
set_custom_labels() indexes v['description'] and calls string methods on it without validating
that v is a dict and description is a non-null string. A malformed or missing description in
user-provided custom_labels can raise KeyError/AttributeError and break label generation.
Code

pr_agent/algo/utils.py[959]

+        description = "'" + v['description'].strip('\n').replace('\n', '\\n').replace("'", "\\'") + "'"
Evidence
The checklist requires defensive validation of external/user-provided configuration values and
robust handling of edge cases. The changed line directly indexes v['description'] and calls
.strip()/.replace() with no type/null checks or safe access, so unexpected shapes in
custom_labels can crash at runtime.

Rule 3: Robust Error Handling
pr_agent/algo/utils.py[959-959]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`set_custom_labels()` assumes each `labels.items()` value is a dict with a string `description`, and calls string methods without null/type checks. This can crash on malformed user configuration.
## Issue Context
`labels` comes from `get_settings().get('custom_labels', {})`, which is user-configured input.
## Fix Focus Areas
- pr_agent/algo/utils.py[959-959]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider Grey Divider

Qodo Logo

Comment thread pr_agent/algo/utils.py Outdated
… key

Add defensive check so set_custom_labels() handles cases where the label
value is not a dict or is missing the 'description' key, instead of
raising a KeyError/TypeError.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 15, 2026

Persistent review updated to latest commit 9314319

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.

1 participant