Skip to content

feat(cli): add testsprite api for authenticated raw requests to the CLI API - #500

Closed
Shubhdeep12 wants to merge 1 commit into
TestSprite:mainfrom
Shubhdeep12:feat/api-command
Closed

Shubhdeep12 wants to merge 1 commit into
TestSprite:mainfrom
Shubhdeep12:feat/api-command

Conversation

@Shubhdeep12

@Shubhdeep12 Shubhdeep12 commented Oct 17, 2026 •

Copy link
Copy Markdown

What does this PR do?

Adds testsprite api <path>: send an authenticated request to any CLI API endpoint and print the JSON
response, in the spirit of gh api and Sentry's sentry api. It lets scripts and coding agents reach an
endpoint no command wraps yet, or a field a command does not show, without copying the API key into curl
and losing the CLI's retries, typed errors and exit codes.

$ testsprite api /me
{ "userId": "u1", "keyId": "k1", "env": "production" }

$ testsprite --output json api tests/t1 -X patch --data '{"name":"Checkout"}'
idempotency-key: cli-api-1e4e2d45-…                                        ← stderr
{ "id": "t1", "name": "Checkout" }

$ testsprite api /tests/nope            → Error: Test not found … requestId: req_9   (exit 4)
$ testsprite api https://evil.example.com/me
Field `path` is invalid: must be a path such as /tests, not a full URL. … never sends your API key to another host.   (exit 5)
$ testsprite api /tests/t1 --data '{"a":1}'
Flag `--data` is invalid: is a request body, which needs --method POST, PUT, PATCH or DELETE.   (exit 5)
  • Same client as every other command: profile, --endpoint-url, API key, retries, --debug tracing
    with redaction, error envelope, exit codes, --request-timeout.
  • The key only goes to the configured host: full URLs, ./.. and %2e%2e segments — including dots
    split by a tab, which URL parsing silently removes — are refused before anything is sent. A pasted
    /api/cli/v1 prefix and query strings work.
  • Writes are explicit: a body without a write method is an error rather than an implicit POST.
  • Writes are retry-safe: every write carries an Idempotency-Key, auto-minted and printed like
    test run's. Reusing a key with a different body is refused by the server (exit 6, listed in the help).
  • --input <file> goes through the existing guarded reader with a 5 MB cap checked before reading (an
    optional maxBytes on readSecretFileGuarded; its existing callers are unchanged). --input - explains
    that stdin is not supported.
  • --dry-run previews the request instead of a canned sample (samples exist only for routes the CLI's
    own commands call).
  • Telemetry records only the command name (api), never the path.

Files: src/commands/api.ts (new), registered in src/index.ts; src/lib/secret-file.ts (optional
maxBytes); DOCUMENTATION.md (new "Raw API requests" section + contents entry); README.md (command table
row); api --help added to the help snapshot suite.

Related issue

Closes #499

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing behavior)
  • Documentation only
  • Build / CI / chore

Checklist

  • I'm entering this PR for the Season 4 CLI Improvement Bonus.
  • PR targets the main branch.
  • Commits follow Conventional Commits.
  • npm run lint and npm run format:check pass.
  • npm run typecheck passes.
  • npm test passes and coverage stays at or above the 80% gate.
  • New behavior is covered by unit tests (mock-based; no network or credentials required).
  • No secrets, API keys, internal endpoints, or personal data are included.
  • User-facing changes are reflected in README.md / DOCUMENTATION.md where relevant.

Discord: shubhdeep_chhabra

Notes for reviewers

  • Prior art: gh api (GitHub CLI) and sentry api (getsentry/cli src/commands/api.ts). Deliberate
    difference: gh api switches to POST when fields are given; here the method must be explicit, because a
    write can start billed runs.
  • Tests (src/commands/api.test.ts, 38 cases; plus one in secret-file.test.ts for the cap):
    • path normalization: prefix stripping, query strings, pasted line breaks; full URLs (https://,
      //host, \\host, javascript:) and ./../%2E%2E/backslash/tab-split segments refused;
    • method parsing;
    • GET to the configured host with x-api-key and no idempotency key; --endpoint-url; JSON body plus an
      auto-minted key printed in JSON mode; an explicit key used and not printed; a 500 retried with the
      same key; --input; an --input file over 5 MB refused before sending; --input - explained;
      a 204 prints nothing; a server 404 keeps its envelope and exit 4;
    • seven argument errors that exit 5 without sending anything;
    • --dry-run preview;
    • Commander wiring for -X and the global flags.
  • Also verified with the built CLI against a local fake API (GET, query string, PATCH, DELETE 204, 404,
    refused URL / .. / %2e%2e, GET with a body, dry-run), and checked the server only ever received requests
    on the configured host. Input matrix run through the real URL builder: 22 path shapes (encoded and
    double-encoded dots, %2F, %5C, full-width dots, @host, host:port, tabs, line breaks), 14 body/flag
    shapes and 8 response shapes (201/202/204, empty or HTML 200, envelope-less 500, 404 envelope).
  • npm run test:coverage: 116 files, 4626 passed; api.ts 98.5% statements / 100% lines. ESLint, Prettier,
    typecheck and the security lint are clean. The eslint-disable comments for test temp files follow the
    existing spec pattern.
  • Merge note: if the --fields PR lands first, it adds --fields to the global-options footer of every
    help screen, so this PR's new api --help snapshot needs regenerating
    (npm run build && npx vitest run test/help.snapshot.test.ts -u). There is no text conflict.
  • Out of scope / follow-ups: reading the body from stdin and custom headers (e.g. If-Match for
    conditional writes) were left out to keep the surface small. Redirect handling is the shared client's
    (see [Hackathon] fix(http): a redirect forwards the API key to the next host #446).

Summary by CodeRabbit

  • New Features
    • Added testsprite api <path> for authenticated API requests using the active profile and configured host. Supports GET, POST, PUT, PATCH, and DELETE, with JSON request bodies, response output, and retry handling.
    • Write requests support idempotency keys, and dry-run previews requests without sending them. Full URLs, traversal paths, incompatible body options, and input files over 5 MB are rejected.
  • Documentation
    • Added API command usage, options, examples, and behavior details to the CLI documentation.

@github-actions

Copy link
Copy Markdown

Thanks for the PR, @Shubhdeep12! It links an issue, but that issue isn't assigned to you yet: #499 (unassigned). Per our workflow, claim the issue first by commenting /assign on it (the triage bot assigns you automatically). If it's already assigned to someone else, please coordinate with them or pick another issue — unclaimed-issue PRs are not reviewed. After fixing it, edit the PR description or push a commit to re-run this check. See CONTRIBUTING → Contribution model.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: TestSprite/testsprite-cli/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 40a7d92c-44ad-4741-9e41-4bffabf602a5
📥 Commits

Reviewing files that changed from the base of the PR and between 988c035 and 07372ac.

⛔ Files ignored due to path filters: 1
  • test/__snapshots__/help.snapshot.test.ts.snap is excluded by !**/*.snap, !**/*.snap
📒 Files selected for processing: 8
  • DOCUMENTATION.md
  • README.md
  • src/commands/api.test.ts
  • src/commands/api.ts
  • src/index.ts
  • src/lib/secret-file.test.ts
  • src/lib/secret-file.ts
  • test/help.snapshot.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 3 remain after this review.

Walkthrough

The CLI adds testsprite api <path> for authenticated requests through the shared HTTP client. The command validates paths, methods, and request bodies, supports dry-run previews, and prints response bodies when present. The change also registers the command and adds tests and documentation.

Changes

Raw API requests

Layer / File(s) Summary
Request validation and input handling
src/commands/api.ts, src/lib/secret-file.ts, src/commands/api.test.ts, src/lib/secret-file.test.ts
The command parses methods and normalizes paths. It rejects full URLs, traversal segments, invalid body options, and unsupported stdin input. File inputs have a 5 MB limit, enforced by the guarded file reader. Tests cover these validations.
Request execution and CLI integration
src/commands/api.ts, src/index.ts, src/commands/api.test.ts, DOCUMENTATION.md, README.md, test/help.snapshot.test.ts
The command sends requests through the shared client, uses idempotency keys for writes, and supports dry-run output. The root CLI registers the command. Tests cover requests, responses, errors, and command wiring. The README, reference documentation, and help snapshot include the command.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant CLI as TestSprite CLI
  participant Command as api command
  participant Client as HttpClient
  participant Host as Configured API host
  CLI->>Command: Invoke api with path and options
  Command->>Client: Send authenticated request
  Client->>Host: Send request
  Host-->>Client: Return response
  Client-->>Command: Return response body or error
  Command-->>CLI: Print response body when present
Loading
Merge Risk: ⚪ Minimal · up to 07372

The API command is mergeable after normal checks; the retry test’s short, fixed wait does not require a change.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 6 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding the authenticated raw-request testsprite api CLI command.
Linked Issues check Passed The PR implements the coding requirements in #499. It registers testsprite api, uses the shared client, and supports profile configuration, --endpoint-url, retries, error handling, exit codes, and…
Out of Scope Changes check Passed The changes stay within #499. The new command, shared guarded-reader option, registration, tests, documentation, README entry, and help coverage directly support the requested raw API feature. No unre…
Full details: Linked Issues check

Explanation

The PR implements the coding requirements in #499. It registers testsprite api, uses the shared client, and supports profile configuration, --endpoint-url, retries, error handling, exit codes, and redacted debug tracing. The implementation and tests cover safe path normalization, explicit write methods, idempotency keys, dry-run requests, guarded --input reads with a 5 MB cap, rejection of --input -, JSON responses, and empty output for 204 responses. The PR also adds documentation, command help coverage, and unit tests. The excluded help snapshot file is not needed to establish the implementation because the reviewed summary records the added help snapshot case; its contents were intentionally excluded.

Full details: Out of Scope Changes check

Explanation

The changes stay within #499. The new command, shared guarded-reader option, registration, tests, documentation, README entry, and help coverage directly support the requested raw API feature. No unrelated product behavior or dependency change is identified. The PR explicitly leaves stdin body input and custom headers out of scope, consistent with the issue and current intent.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 6 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the needs-issue PR not linked to an issue yet — please open one first and claim it (see CONTRIBUTING) label Oct 17, 2026
@github-actions

Copy link
Copy Markdown

🏆 Season 4 CLI Improvement Bonus: entry recorded. Thanks, @Shubhdeep12!

To be counted, this PR needs the following by Oct 29, 11:59 PM PT:

  • ⬜ A linked issue assigned to you: the issue this PR links isn't assigned to you yet. Claim it by commenting /assign on it.
  • ✅ Out of draft.
  • ✅ A Discord username in the description.

Rewards go to merged PRs judged a genuine improvement, and up to three bonus-eligible PRs count per person. Untick the box to withdraw the entry. This comment refreshes when you edit the PR. Full rules.

@github-actions github-actions Bot added the s4-cli-bonus Entered for the Season 4 CLI Improvement Bonus label Oct 22, 2026
@fyZhang66

Copy link
Copy Markdown
Contributor

Thanks @Shubhdeep12. Closing along with #499, which we're not taking.

@fyZhang66 fyZhang66 closed this Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-issue PR not linked to an issue yet — please open one first and claim it (see CONTRIBUTING) s4-cli-bonus Entered for the Season 4 CLI Improvement Bonus

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Hackathon] feat(cli): add testsprite api <path> — authenticated raw requests to the CLI API (like gh api)

2 participants