Skip to content

fix(issue): Handle GitHub-style #SHORTID in issue identifiers#1004

Closed
sentry[bot] wants to merge 1 commit into
mainfrom
seer/fix/issue-identifier-hash-fragment
Closed

fix(issue): Handle GitHub-style #SHORTID in issue identifiers#1004
sentry[bot] wants to merge 1 commit into
mainfrom
seer/fix/issue-identifier-hash-fragment

Conversation

@sentry
Copy link
Copy Markdown
Contributor

@sentry sentry Bot commented May 22, 2026

This PR addresses CLI-1G1, where sentry issue view commands were failing with a ValidationError: Invalid issue identifier: contains "#" (URL fragment).

Root Cause:
AI agents (like claude-code and codex) frequently pass GitHub-style issue identifiers such as org/project#SHORTID. The parseIssueArg function in src/lib/arg-parsing.ts was stripping / characters but not # before calling validateResourceId. The validateResourceId function, designed to prevent URL injection, correctly rejects # as a forbidden URL fragment character, leading to the ValidationError.

Solution:

  1. Pre-process #fragment: In parseIssueArg, before the general validateResourceId call, a new parsing step detects and extracts a trailing #fragment.
  2. Validate fragment: The extracted fragment (intended as the issue's short ID) is validated independently using validateResourceId to ensure it doesn't contain other forbidden characters.
  3. Rewrite input: The original input is then rewritten to prefix/fragment (e.g., org/project/SHORTID) or just fragment if no prefix was present. This allows the existing slash-parsing logic to correctly interpret the identifier.
  4. Improved error message: If the # is used incorrectly (e.g., multiple #s, empty fragment), a more helpful ValidationError is thrown, suggesting the correct org/project/SHORTID format.
  5. Downstream flow: Subsequent parsing steps (numeric, colon, slash, dash, suffix-only) now operate on the normalized input, ensuring the rewritten value is processed correctly.

This change allows sentry issue view to correctly parse org/project#SHORTID inputs while maintaining robust validation against malicious or malformed identifiers.

Fixes CLI-1G1

@github-actions
Copy link
Copy Markdown
Contributor

PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://cli.sentry.dev/_preview/pr-1004/

Built to branch gh-pages at 2026-05-22 10:38 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

BYK added a commit that referenced this pull request Jun 2, 2026
## Summary

AI agents (claude-code, codex) frequently pass GitHub-style issue
references such as `org/project#SHORTID`. These previously failed with:

```
ValidationError: Invalid issue identifier: contains "#" (URL fragment)
```

because `parseIssueArg` stripped `/` but not `#` before calling
`validateResourceId` (which correctly rejects `#` as a forbidden
URL-fragment character).

This supersedes #1004 and fixes the underlying issue, while fixing a
semantic bug in that draft and aligning with repo conventions,
validation, tests, and docs.

## Approach

A dedicated `parseWithHash` helper (mirroring the existing
`parseWithColon`) treats `#` as the separator before the short ID:

| Input | Result |
|---|---|
| `org/project#CLI-G` | `explicit` (org + project + suffix) |
| `org/project#123` | `explicit-org-numeric` |
| `project#CLI-G` | `project-search` |
| `#CLI-G` | bare identifier → `project-search` |
| `#123` | `numeric` |
| `#G` | `suffix-only` |

- `org/project#ID` delegates to the existing slash path, reusing the
full-short-ID prefix-match logic in `parseMultiSlashIssueArg`.
- `project#ID` is treated as a project-scoped lookup (org auto-detected)
— fixing the draft PR's bug where bare `project#ID` was misparsed as
`org/suffix`.
- Steps 2–5 of `parseIssueArg` were extracted into
`parseBareIssueIdentifier`, and `parseProjectIdentifier` is now shared
between the colon and hash parsers.

### Validation

Because the `#` path short-circuits **before** the main
`validateResourceId` guard, `parseWithHash` validates **both** the
project prefix and the fragment itself. A `:` mixed with `#` is rejected
explicitly to avoid silently swallowing the colon into a suffix (cf. the
`sentry/CLI:W9` precedent).

## Behavioral change

`parseIssueArg("CLI-G#anchor")` previously threw (treated as fragment
injection); it now parses as `project-search{ projectSlug: "cli-g",
suffix: "ANCHOR" }`. The injection-hardening test was updated to use a
fragment that still contains a forbidden character.

## Tests

- New example-based describe block covering all `#` forms and error
cases (multiple `#`, empty fragment, forbidden chars, `:`-mix, invalid
project prefix).
- New property tests: `org/project#FULL-SHORTID` ≡
`org/project/FULL-SHORTID`; `project#FULL-SHORTID` → `project-search`;
forbidden char in fragment always throws.

## Docs

- `features.md` — new "GitHub-Style (`#` separator)" subsection under
Issue ID Formats.
- `issue.md` fragment + regenerated skill reference — `#` examples.
- `issue view` `fullDescription` and the shared `<issue>` positional
`brief`.
- `issue-id.ts` module JSDoc.

## Verification

- `pnpm run typecheck` ✅
- `pnpm run lint` ✅
- `pnpm test -- test/lib` ✅ (5464 passing)
- `pnpm run generate:docs` + `pnpm run check:fragments` ✅

Fixes CLI-1G1.
@BYK
Copy link
Copy Markdown
Member

BYK commented Jun 2, 2026

Superseded by #1048.

@BYK BYK closed this Jun 2, 2026
@BYK BYK deleted the seer/fix/issue-identifier-hash-fragment branch June 2, 2026 17:26
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