Files
github-spec-kit/extensions/bug/commands/speckit.bug.fix.md
Manfred Riem 60302fefec feat(extensions): add bundled bug triage workflow extension (#2871)
* feat(extensions): add bundled bug triage workflow extension (#2870)

Add a bundled 'bug' extension providing a three-stage bug triage workflow:

- speckit.bug.assess: triage a bug report (pasted text or URL), locate
  suspected code paths, and propose a remediation
- speckit.bug.fix: apply the proposed remediation and record what changed
- speckit.bug.test: validate the fix and record the verification result

Each bug gets its own directory under .specify/bugs/<slug>/ with one
Markdown report per stage (assessment.md, fix.md, test.md). The slug is
the only handle the three commands share; existing bug directories are
never overwritten.

Mirrors the layout of the existing bundled extensions (git, agent-context):

- extensions/bug/extension.yml, README.md, commands/
- extensions/catalog.json: register 'bug' (alphabetical, between
  agent-context and git)
- pyproject.toml: add wheel mapping to specify_cli/core_pack/extensions/bug

Closes #2870

* address Copilot review on #2871

- speckit.bug.assess.md: drop POSIX-specific 'mkdir -p' example;
  reword the prerequisite to describe the requirement (ensure BUG_DIR
  exists) without assuming a specific shell.
- speckit.bug.fix.md: fix the slug-resolution fallback wording. It
  listed '.specify/bugs/*/assessment.md' but then keyed off whether
  'exactly one bug directory' existed; now it correctly keys off whether
  exactly one matching 'assessment.md' was found and uses the slug from
  its parent directory.
- tests/extensions/bug/test_bug_extension.py: add a smoke test analogous
  to the agent-context extension's coverage. Validates the bundled
  layout, catalog registration, '_locate_bundled_extension("bug")'
  resolution, and that 'ExtensionManager.install_from_directory' installs
  the three commands.

All 333 tests in tests/extensions/, tests/test_extensions.py, and
tests/test_extension_registration.py pass.

* address Copilot review on #2871 (round 2)

- Import _locate_bundled_extension from the public 'specify_cli'
  package (it is re-exported in __init__.py) instead of the private
  'specify_cli._assets' module, so the test does not depend on internal
  module layout.
- Clarify module docstring: install_from_directory is called with
  register_commands=False, so commands are copied and recorded in the
  installed manifest but not registered with AI agents. Wording updated
  to avoid implying otherwise.

* address Copilot review on #2871 (round 3)

- tests/extensions/bug/test_bug_extension.py: read extension.yml as
  UTF-8 explicitly to avoid platform-dependent default encoding (notably
  on Windows). Matches how the README is read in the same module.
- extensions/bug/commands/speckit.bug.assess.md: add a 'Safety When
  Fetching URLs' section. Instructs the agent to treat fetched page
  content as untrusted input (no obeying embedded prompt-injection
  directives), forbids supplying credentials/secrets that a page asks
  for, scopes the fetch to the URL the user provided (no following
  redirects to other resources), and requires suspicious content to be
  quoted verbatim under an 'Unverified' heading rather than acted on.
- extensions/catalog.json: bump 'updated_at' to today (2026-06-05) so
  consumers that cache by this field invalidate when 'bug' is added.
- extensions/bug/README.md: minor grammar fix ('a reproduction that was
  not actually performed').

All 251 tests in tests/extensions/bug/, tests/test_extensions.py, and
tests/test_extension_registration.py pass.

* speckit.bug.assess: add URL Trust Policy for fetched bug-report URLs

Builds on the 'Safety When Fetching URLs' section by adding a tiered
classification rule the agent applies before any fetch:

1. Refuse outright (no fetch, no prompt) for non-http(s) schemes,
   loopback, link-local, RFC1918 private space, and known cloud
   instance-metadata endpoints (169.254.169.254, metadata.google.internal,
   100.100.100.200, metadata.azure.com). This closes the SSRF /
   internal-recon vector opened by 'paste any URL'.
2. Fetch silently for an explicit allowlist of widely-used public
   bug-report sources (github, gitlab, bitbucket, atlassian.net, linear,
   stackoverflow/stackexchange, sentry). This preserves the paste-a-URL
   ergonomics the workflow is built for.
3. Otherwise prompt once in interactive mode (default 'no', naming the
   resolved host explicitly); in automated mode skip the fetch and
   record '[UNVERIFIED - fetch skipped: host not on safe list: <host>]'
   in assessment.md so a human can decide later.

In every case, assessment.md records the verbatim URL, the resolved host,
and which branch of the policy was taken (allowlisted /
confirmed-by-user / auto-refused: <reason>) so the per-bug directory's
audit trail is complete. Preflight HEAD probes are explicitly forbidden
since the probe itself is the request the policy gates.

Execution step 1 now defers to the policy before fetching.

* speckit.bug.assess: remove 'post-redirect-resolution' inconsistency

The URL Trust Policy explicitly forbids following redirects, but the
audit-trail bullet asked the agent to record the host
'post-redirect-resolution', which contradicted that rule and could lead
agents to follow redirects unintentionally to determine what to log.

Reword both call sites to refer to the host parsed from the URL the user
supplied (no resolution implied):

- Tier-3 interactive prompt: '...naming the host parsed from the URL
  explicitly...'
- Recorded fields: 'The host parsed from that URL (no redirect following
  - see the rule above).'

No behavior change; clarification only.
2026-06-05 12:37:25 -05:00

5.2 KiB
Raw Permalink Blame History

description
description
Apply the remediation from a bug assessment and record what was changed

Fix Bug

Apply the remediation that was proposed by __SPECKIT_COMMAND_BUG_ASSESS__ and record the changes in a fix report at .specify/bugs/<slug>/fix.md. This command is only valid after an assessment exists for the given slug.

User Input

$ARGUMENTS

The user input should identify the bug to fix. Accept any of:

  • slug=<bug-slug> or --slug <bug-slug> or just a bare slug-like token.
  • A path that contains the slug (e.g. .specify/bugs/login-timeout/).
  • Nothing — fall back to context (see below).

Slug Resolution

Resolve BUG_SLUG in this order, stopping at the first match:

  1. Explicit user input — a slug passed in $ARGUMENTS (any of the forms above).
  2. Conversation context — if the current session has just run __SPECKIT_COMMAND_BUG_ASSESS__, the slug it reported is the working slug. Reuse it without re-prompting. Confirm it by checking that .specify/bugs/<slug>/assessment.md exists; if it does not, fall through.
  3. Single candidate on disk — list .specify/bugs/*/assessment.md. If exactly one matching assessment.md is found, use the slug from its parent directory.
  4. Disambiguate:
    • Interactive mode: ask the user which bug to fix and list the candidates.
    • Automated mode: stop with an error listing the candidates. Do not guess.

Once resolved, set BUG_SLUG and BUG_DIR = .specify/bugs/<BUG_SLUG>, and briefly state in your reply which resolution path was used (explicit / from context / single candidate / asked).

Prerequisites

  • BUG_DIR/assessment.md MUST exist. If it does not, stop and instruct the user to run __SPECKIT_COMMAND_BUG_ASSESS__ first.
  • If BUG_DIR/fix.md already exists, ask the user whether to overwrite it before continuing (interactive mode) or refuse (automated mode).
  • Read BUG_DIR/assessment.md in full. Treat its Proposed Remediation, Files likely to change, Tests to add or update, and Risks & Considerations sections as the contract for this command.

Execution

  1. Confirm the plan

    • Restate, in 36 bullets, what you are about to change and where, based on the assessment.
    • If the assessment's verdict is invalid, stop — there is nothing to fix. Tell the user and exit.
    • If the verdict is likely valid, needs reproduction and there are unresolved [NEEDS CLARIFICATION] items, flag them and ask the user whether to proceed in interactive mode, or stop in automated mode.
  2. Apply the remediation

    • Make the code changes described by the preferred remediation. Stay within the files listed by the assessment unless newly discovered evidence requires expanding scope (in which case, log the expansion explicitly in the report).
    • Add or update the tests called out in the assessment so the bug cannot regress silently.
    • Keep the change minimal — do not refactor unrelated code, do not introduce dependencies that the assessment did not call for.
    • If you discover the assessment was wrong (the proposed fix does not work, the root cause is elsewhere), STOP modifying code, document the new finding in the fix report under Deviations from Assessment, and recommend re-running __SPECKIT_COMMAND_BUG_ASSESS__.
  3. Run local checks

    • If the project has obvious test commands (e.g., pytest, npm test, cargo test), run the tests that exercise the changed paths. Capture pass/fail and key output.
    • Do not run destructive or network-dependent suites without the user's consent.
  4. Write the fix report

    Write to BUG_DIR/fix.md using this structure:

    # Bug Fix: <short title>
    
    - **Slug**: <BUG_SLUG>
    - **Fixed**: <ISO 8601 date>
    - **Assessment**: ./assessment.md
    - **Status**: applied | partial | not-applied
    
    ## Summary
    
    <One or two sentences describing what was changed and why.>
    
    ## Changes
    
    | File | Change | Notes |
    |------|--------|-------|
    | `path/to/file.py` | <added / modified / removed> | <short note> |
    | `path/to/test_file.py` | added test | <short note> |
    
    ## Diff Highlights (optional)
    
    <Short, illustrative snippets of the most important hunks — not a full diff dump.>
    
    ## Tests Added or Updated
    
    - `path/to/test_file.py::test_name` — <what it pins down>
    
    ## Local Verification
    
    - Commands run: `<command>` → <result, brief>
    - Manual checks: <what was verified by hand, if anything>
    
    ## Deviations from Assessment
    
    <Empty if none. Otherwise, list any places where the actual fix departed from the proposed remediation and why.>
    
    ## Follow-ups
    
    - <suggested cleanup, monitoring, doc update, etc.>
    
  5. Report back with:

    • The slug and BUG_DIR/fix.md path.
    • The status (applied, partial, not-applied).
    • The next suggested step: __SPECKIT_COMMAND_BUG_TEST__ slug=<BUG_SLUG>.

Guardrails

  • Never modify files outside the project workspace.
  • Never edit assessment.md — it is the contract you are working against. Record disagreements in fix.md under Deviations from Assessment.
  • Never delete files unless the assessment explicitly required it.
  • Never overwrite an existing fix.md without confirmation.