Skip to content

[Hackathon] fix(cli): validate non-empty and non-whitespace IDs in schedule update, test diff, test wait, test open, and test flaky #468

Closed as duplicate

Description

@grzdev

Verified against (commit SHA or released version)

commit 988c035 (main HEAD, v0.14.0)

Discord Username / User ID

3raiden/752124227720577094

What does this improvement do?

Several CLI commands that take positional resource IDs (<schedule-id>, <run-a>, <run-b>, <run-id...>, <test-id>) do not validate that those IDs are non-empty and non-whitespace before executing:

  1. schedule update <schedule-id> (runUpdate in src/commands/schedule.ts:384):
    src/commands/schedule.ts defines requireScheduleId(raw: string): string at line 500 and calls it in runGet, runDelete, runTrigger, and runRunList, but forgot to call requireScheduleId(opts.scheduleId) in runUpdate. Passing " " exits 0 under --dry-run and sends PATCH /schedules/%20%20%20 in live mode.
  2. test diff <run-a> <run-b> (runDiff in src/commands/test.ts:5746):
    Never validates opts.runA or opts.runB. Passing " " under --dry-run prints verdicts differ: =passed vs =failed and exits 0; in live mode it sends GET /runs/%20%20%20.
  3. test wait <run-id...> (runTestWait in src/commands/test.ts:9181 and runTestWaitMany in src/commands/test.ts:8675):
    Neither single-run wait nor multi-run wait validates that every <run-id> is non-empty and non-whitespace. Under --dry-run, testsprite test wait " " --dry-run and testsprite test wait " " " " --dry-run both exit 0 with synthetic pass output; in live mode they poll /runs/%20%20%20.
  4. test flaky <test-id> (runFlaky in src/commands/test.ts:15223):
    Line 15223 checks if (!opts.testId || opts.testId.length === 0) without .trim(), so whitespace-only <test-id> (" ") bypasses the guard, prints "path": "/api/cli/v1/tests/ /runs/rerun" under --dry-run with exit 0, and sends POST /tests/%20%20%20/runs/rerun in live mode.
  5. test open <test-id> (runOpen in src/commands/test.ts:6201):
    Never validates opts.testId before calling client.get('/tests/...') or constructing the browser dashboard URL. testsprite test open " " --dry-run exits 0 and outputs https://www.testsprite.com/dashboard/tests/p_dryrun_2026/test/%20%20%20.

Note: Prior issues covered read-by-id commands (#368), testlist (#381), project env (#385), test run/cancel/delete-batch (#395), and project update/credential/auto-auth/sign-in (#466), leaving these 5 commands unguarded.

Details / implementation notes

Reproduction

Tested against commit 988c0355bb05631e9c6c1785e443937ff2a88c0e, built from source with Node v24.20.0 (offline, --dry-run):

testsprite schedule update "   " --pause --dry-run
# Output: id: sch_dryrun_1 ... exit=0

testsprite test diff "   " "   " --dry-run
# Output: verdicts differ:    =passed vs    =failed ... exit=0

testsprite test wait "   " --dry-run
# Output: {"dryRun":true,"action":"test.wait","method":"GET","path":"/api/cli/v1/runs/   ?waitSeconds=25",...} exit=0

testsprite test wait "   " "   " --dry-run
# Output:      passed ... exit=0

testsprite test flaky "   " --dry-run
# Output: {"dryRun":true,"action":"test.flaky","method":"POST","path":"/api/cli/v1/tests/   /runs/rerun",...} exit=0

testsprite test open "   " --dry-run
# Output: https://www.testsprite.com/dashboard/tests/p_dryrun_2026/test/%20%20%20 exit=0

Observed: All 5 commands exit 0 on whitespace-only IDs instead of rejecting with VALIDATION_ERROR (exit 5).
Expected: Each command rejects empty or whitespace-only positional IDs up front with typed VALIDATION_ERROR (exit 5) before constructing requests or emitting dry-run responses.

Proposed Fix

  1. In src/commands/schedule.ts (runUpdate, line 384): call const scheduleId = requireScheduleId(opts.scheduleId); up front and use scheduleId in the PATCH path.
  2. In src/commands/test.ts:
    • runDiff (line 5746): validate opts.runA (requireNonEmptyId(opts.runA, '<run-a>')) and opts.runB (requireNonEmptyId(opts.runB, '<run-b>')) up front.
    • runTestWait (line 9181) and runTestWaitMany (line 8675): validate opts.runId and every item in opts.runIds with requireNonEmptyId(..., '<run-id>') up front.
    • runFlaky (line 15223): check !opts.testId || opts.testId.trim().length === 0 (and use the trimmed ID).
    • runOpen (line 6201): validate requireNonEmptyId(opts.testId, '<test-id>') up front.
  3. Add unit tests in src/commands/schedule.spec.ts and src/commands/test.spec.ts covering empty and whitespace-only IDs in both live and --dry-run modes.

Confirmations

  • I have searched existing issues and this is not a duplicate.
  • I have provided my Discord identity above for reward coordination.

Activity

  1. added
    duplicateThis issue or pull request already exists
    and removed
    needs-triageNew issue/PR awaiting first triage
    on Oct 20, 2026
  2. ruili-testsprite commented on Oct 20, 2026

    @ruili-testsprite
    Contributor

    Closing as a duplicate of #368. Its scope now covers empty and whitespace-only positional ids for every command in one change, including the commands listed here. Thanks for the report! If you'd like to work on it, comment /assign on #368.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already existshackathonCLI hackathon submissions

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions