Skip to content

Commit d627a64

Browse files
committed
fix: address Copilot review round 10 findings
- Fix re.sub in update_file() to use a lambda replacement function instead of a replacement string, preventing backslash/group-reference corruption in generated table content - Add _escape_cell() helper to escape pipe characters and collapse newlines in markdown table cells from user-submitted data - Remove unused imports (ipaddress, sys, types) from test module - Add scripts_count validation for preset submissions (non-negative integer when provided) - Remove stale catalog-table-start/end markers from README.md since the extension workflow does not regenerate this table (catalog JSON lacks category/effect fields)
1 parent b65d14a commit d627a64

4 files changed

Lines changed: 20 additions & 12 deletions

File tree

.github/scripts/catalog-generate-table.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ def _requires_str_preset(requires: dict) -> str:
6060
return "—"
6161

6262

63+
def _escape_cell(value: str) -> str:
64+
"""Escape pipe characters and collapse whitespace for markdown table cells."""
65+
return value.replace("|", "\\|").replace("\n", " ").replace("\r", "").strip()
66+
67+
6368
def build_preset_table(catalog: dict) -> str:
6469
"""Build a markdown table for presets."""
6570
entries = catalog.get("presets", {})
@@ -69,8 +74,8 @@ def build_preset_table(catalog: dict) -> str:
6974

7075
for _id in sorted(entries):
7176
e = entries[_id]
72-
name = e.get("name", _id)
73-
desc = e.get("description", "")
77+
name = _escape_cell(e.get("name", _id))
78+
desc = _escape_cell(e.get("description", ""))
7479
provides = _provides_str_preset(e.get("provides", {}))
7580
requires = _requires_str_preset(e.get("requires", {}))
7681
repo_url = e.get("repository", "")
@@ -103,12 +108,12 @@ def build_extension_table(catalog: dict) -> str:
103108

104109
for _id in sorted(entries):
105110
e = entries[_id]
106-
name = e.get("name", _id)
107-
desc = e.get("description", "")
108-
category = e.get("category", "")
111+
name = _escape_cell(e.get("name", _id))
112+
desc = _escape_cell(e.get("description", ""))
113+
category = _escape_cell(e.get("category", ""))
109114
if category:
110115
category = f"`{category}`"
111-
effect = e.get("effect", "")
116+
effect = _escape_cell(e.get("effect", ""))
112117
repo_url = e.get("repository", "")
113118
repo_name = _repo_display_name(repo_url)
114119
lines.append(
@@ -141,7 +146,7 @@ def update_file(path: Path, table: str) -> bool:
141146
if not pattern.search(content):
142147
return False
143148

144-
new_content = pattern.sub(rf"\1\n{table}\n\2", content)
149+
new_content = pattern.sub(lambda m: f"{m.group(1)}\n{table}\n{m.group(2)}", content)
145150

146151
if new_content != content:
147152
path.write_text(new_content)

.github/scripts/catalog-validate.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,14 @@ def _add(field: str, ok: bool, msg: str, *, severity: str = "error") -> None:
544544
_add("Preset Provides", False,
545545
"At least one of Templates Provided or Commands Provided is required.")
546546
# Commands Provided is optional for presets
547+
# Validate scripts count if provided
548+
scripts_val = fields.get("scripts_count", "").strip()
549+
if scripts_val:
550+
if not scripts_val.isdigit():
551+
_add("Number of Scripts", False,
552+
f"Number of Scripts `{scripts_val}` must be a non-negative integer.")
553+
else:
554+
_add("Number of Scripts", True, f"Scripts count: {scripts_val}.")
547555

548556
# --- Tags ---
549557
ok, msg = validate_tags(fields.get("tags", ""))

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ The following community-contributed extensions are available in [`catalog.commun
193193
- `Read-only` — produces reports without modifying files
194194
- `Read+Write` — modifies files, creates artifacts, or updates specs
195195

196-
<!-- catalog-table-start -->
197196
| Extension | Purpose | Category | Effect | URL |
198197
|-----------|---------|----------|--------|-----|
199198
| Agent Assign | Assign specialized Claude Code agents to spec-kit tasks for targeted execution | `process` | Read+Write | [spec-kit-agent-assign](https://github.com/xymelon/spec-kit-agent-assign) |
@@ -275,7 +274,6 @@ The following community-contributed extensions are available in [`catalog.commun
275274
| Wireframe Visual Feedback Loop | SVG wireframe generation, review, and sign-off for spec-driven development. Approved wireframes become spec constraints honored by /speckit.plan, /speckit.tasks, and /speckit.implement | `visibility` | Read+Write | [spec-kit-extension-wireframe](https://github.com/TortoiseWolfe/spec-kit-extension-wireframe) |
276275
| Worktree Isolation | Spawn isolated git worktrees for parallel feature development without checkout switching | `process` | Read+Write | [spec-kit-worktree](https://github.com/Quratulain-bilal/spec-kit-worktree) |
277276
| Worktrees | Default-on worktree isolation for parallel agents — sibling or nested layout | `process` | Read+Write | [spec-kit-worktree-parallel](https://github.com/dango85/spec-kit-worktree-parallel) |
278-
<!-- catalog-table-end -->
279277

280278
To submit your own extension, see the [Extension Publishing Guide](extensions/EXTENSION-PUBLISHING-GUIDE.md).
281279

tests/test_catalog_validate.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
from __future__ import annotations
44

55
import importlib
6-
import ipaddress
7-
import sys
8-
import types
96
from pathlib import Path
107
from unittest.mock import patch
118

0 commit comments

Comments
 (0)