Skip to content

fix(scripts): harden bash scripts — escape, compat, and error handling#1869

Merged
mnriem merged 5 commits intogithub:mainfrom
pierluigilenoci:backport/script-hardening-improvements
Mar 16, 2026
Merged

fix(scripts): harden bash scripts — escape, compat, and error handling#1869
mnriem merged 5 commits intogithub:mainfrom
pierluigilenoci:backport/script-hardening-improvements

Conversation

@pierluigilenoci
Copy link
Contributor

Summary

  • RFC 8259 JSON escape: json_escape() in common.sh now handles \b, \f, and strips remaining control characters (U+0000–U+001F), preventing malformed JSON output
  • Python exit code handling: resolve_template in common.sh now distinguishes between python3 returning empty results vs python3 failing entirely
  • Explicit return code for resolve_template: returns 1 when no template is found (was always 0); callers updated with || true to preserve non-fatal behavior under set -e
  • Doc name escaping: check-prerequisites.sh now passes doc names through json_escape in the jq-fallback path
  • Remove duplicate json_escape: create-new-feature.sh had its own copy; now uses the one from common.sh
  • Template-not-found warning: create-new-feature.sh emits a warning to stderr when the spec template is missing
  • Bash 3.2 compatibility: update-agent-context.sh moves the nested update_if_new helper to top-level (_update_if_new), avoiding scope issues on macOS default bash
  • Best-effort error accumulation: update_all_existing_agents now tracks failures with an accumulator (like the PowerShell equivalent) instead of silently discarding them — all agents are attempted and the composite result is returned

Test plan

  • Run specify init in a fresh project and verify all scripts are copied correctly
  • Run create-new-feature.sh with and without a spec template present — verify warning on stderr when missing
  • Run check-prerequisites.sh --json with doc names containing special characters
  • Run update-agent-context.sh without arguments (update-all path) and verify errors are reported
  • Verify on macOS with bash 3.2 (/bin/bash --version) that update-agent-context.sh works correctly

- common.sh: complete RFC 8259 JSON escape (\b, \f, strip control chars)
- common.sh: distinguish python3 success-empty vs failure in resolve_template
- check-prerequisites.sh: escape doc names through json_escape in fallback path
- create-new-feature.sh: remove duplicate json_escape (already in common.sh)
- create-new-feature.sh: warn on stderr when spec template is not found
- update-agent-context.sh: move nested function to top-level for bash 3.2 compat
…gent updates

- common.sh: resolve_template now returns 1 when no template is found,
  making the "not found" case explicit instead of relying on empty stdout
- setup-plan.sh, create-new-feature.sh: add || true to resolve_template
  calls so set -e does not abort on missing templates (non-fatal)
- update-agent-context.sh: accumulate errors in update_all_existing_agents
  instead of silently discarding them — all agents are attempted and the
  composite result is returned, matching the PowerShell equivalent behavior
@pierluigilenoci pierluigilenoci requested a review from mnriem as a code owner March 16, 2026 20:58
@pierluigilenoci
Copy link
Contributor Author

@mnriem @dhilipkumars, please take a look.

Copy link
Contributor

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

Hardens the repository’s bash workflow scripts by improving JSON escaping, making template resolution behavior explicit under set -e, and improving update-agent error handling/compatibility (notably for macOS bash 3.2).

Changes:

  • Strengthens json_escape() to cover additional RFC 8259 escapes and strip remaining control characters.
  • Makes resolve_template return non-zero when not found; updates call sites to avoid set -e aborts and adds a missing-template warning.
  • Refactors update-agent-context.sh to avoid nested helper scope issues on bash 3.2 and to accumulate failures while updating all agents.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
scripts/bash/update-agent-context.sh Moves update helper to top-level for bash 3.2, and accumulates per-agent update failures while attempting all updates.
scripts/bash/setup-plan.sh Adjusts resolve_template call to tolerate “not found” under set -e.
scripts/bash/create-new-feature.sh Removes duplicate JSON escape helper, tolerates missing template, and warns on stderr when creating an empty spec.
scripts/bash/common.sh Enhances JSON escaping and changes resolve_template to return 1 on “template not found”; improves python3 result handling logic.
scripts/bash/check-prerequisites.sh Ensures doc names are JSON-escaped in the jq-fallback JSON output path.

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

Copy link
Collaborator

@mnriem mnriem left a comment

Choose a reason for hiding this comment

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

Please address Copilot feedback. If not applicable, please explain why

Move the python3 command substitution in resolve_template into an
if-condition so that a non-zero exit (e.g. invalid .registry JSON)
does not abort the function under set -e. The fallback directory
scan now executes as intended regardless of caller errexit settings.
@pierluigilenoci
Copy link
Contributor Author

@mnriem Copilot's feedback has been addressed in 7601f7b — the python3 command substitution is now wrapped in an if condition, which suppresses set -e per POSIX spec and ensures the fallback directory scan runs correctly when python3 fails (e.g. invalid .registry JSON). Ready for re-review.

Copy link
Contributor

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

Hardens the Bash workflow scripts by improving JSON escaping, making template resolution safer under set -e, and improving macOS Bash 3.2 compatibility and error reporting—aligning these scripts with more robust/defensive execution in typical CI and developer shells.

Changes:

  • Strengthen json_escape() to cover additional RFC 8259 escapes and strip remaining control characters.
  • Change resolve_template() to return non-zero when not found and update callers to tolerate “not found” under set -e.
  • Refactor update-agent-context.sh agent-update flow for Bash 3.2 compatibility and best-effort error accumulation.

Reviewed changes

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

Show a summary per file
File Description
scripts/bash/common.sh Harden JSON escaping; make resolve_template safer with set -e and return 1 on “not found”.
scripts/bash/setup-plan.sh Adjust template resolution call site to tolerate resolve_template returning non-zero.
scripts/bash/create-new-feature.sh Remove duplicated json_escape; tolerate missing template and emit a warning.
scripts/bash/check-prerequisites.sh Ensure doc names are JSON-escaped in the no-jq JSON output path.
scripts/bash/update-agent-context.sh Move helper to top-level for Bash 3.2 and accumulate failures while continuing updates.

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

Copy link
Collaborator

@mnriem mnriem left a comment

Choose a reason for hiding this comment

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

Please address Copilot feedback. Hang in there we are getting there!

…level globals

- _update_if_new now records the path and sets _found_agent before calling
  update_agent_file, so that failures do not cause duplicate attempts on
  aliased paths (AMP/KIRO/BOB -> AGENTS_FILE) or false "no agent files
  found" fallback triggers
- Remove top-level initialisation of _updated_paths and _found_agent;
  they are now created exclusively inside update_all_existing_agents,
  keeping the script side-effect free when sourced
@pierluigilenoci pierluigilenoci requested a review from mnriem March 16, 2026 22:33
@pierluigilenoci
Copy link
Contributor Author

@mnriem Both new Copilot findings from the second review have been addressed in db9fb09:

  1. Dedup/found_agent ordering_update_if_new now records the path and sets _found_agent before calling update_agent_file, preventing duplicate attempts on aliased paths and false "no agent files found" fallback triggers
  2. Top-level globals — removed the top-level initialisation of _updated_paths and _found_agent; both are now created exclusively inside update_all_existing_agents, keeping the script side-effect free when sourced

Ready for re-review.

Copy link
Contributor

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 the repository’s bash workflow scripts by improving JSON escaping, making template resolution behavior explicit under set -e, and improving update-all error reporting/compatibility on older bash (macOS 3.2).

Changes:

  • Strengthen json_escape() to cover additional RFC 8259 escapes and strip remaining ASCII control characters to prevent malformed JSON output.
  • Make resolve_template() return non-zero when no template is found, and update callers to tolerate “not found” under set -e.
  • Refactor update-agent-context.sh for bash 3.2 compatibility and best-effort updates with an aggregated success/failure result.

Reviewed changes

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

Show a summary per file
File Description
scripts/bash/common.sh Harden JSON escaping and make resolve_template return code meaningful without breaking set -e execution.
scripts/bash/setup-plan.sh Update template lookup to tolerate “not found” via `
scripts/bash/create-new-feature.sh Remove duplicate json_escape, tolerate missing template, and emit a clear warning when creating an empty spec.
scripts/bash/check-prerequisites.sh Escape doc names in the jq-less JSON output path to avoid invalid JSON.
scripts/bash/update-agent-context.sh Move helper to top-level for bash 3.2 and accumulate failures while still attempting all agent updates.

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

@mnriem mnriem merged commit 9c0c144 into github:main Mar 16, 2026
12 checks passed
@mnriem
Copy link
Collaborator

mnriem commented Mar 16, 2026

@pierluigilenoci Thank you!

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.

3 participants