Repository navigation
[Hackathon] fix(project): validate non-empty and non-whitespace <project-id> across project update, credential, auto-auth, and sign-in commands #466
Description
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?
The project update, project credential, project auto-auth, project sign-in get, and project sign-in set commands accept a positional <project-id> argument but do not validate that it is non-empty and non-whitespace before executing.
When <project-id> is whitespace-only (e.g. testsprite project update " " --name demo or testsprite project sign-in get "$PROJECT_ID" when a shell variable is unset or whitespace):
- Under
--dry-run: The CLI prints canned synthetic responses (e.g.id:,projectId:, or default sign-in configuration) and exits0, giving a false-success indicator on an invalid project identifier. - In live mode: The unchecked argument is directly interpolated into REST URL paths (
/projects/%20%20%20,/projects/%20%20%20/credential,/projects/%20%20%20/auto-auth,/projects/%20%20%20/sign-in), sending malformed requests to the backend API rather than failing fast locally with a typedVALIDATION_ERROR(exit 5).
In contrast, sibling commands in the same group explicitly enforce this:
project delete(src/commands/project.ts:709) rejects withlocalValidationError('<project-id> is required')(exit 5).project docs upload(src/commands/project.ts:2114) validates non-empty trimmed ID viarequireDocsProjectId.project envcommands validate<project-id>as addressed in [Hackathon] fix(project): validate non-empty and non-whitespace <project-id> across project env commands #385 / PR fix(project): validate non-empty and non-whitespace <project-id> across project env commands #386.
Reproduction
Tested against commit 988c0355bb05631e9c6c1785e443937ff2a88c0e, built from source with Node v24.20.0 (offline, --dry-run):
testsprite project update " " --name demo --dry-run
# Output: id: updatedFields: name ... exit=0
testsprite project credential " " --type "Bearer token" --credential token123 --dry-run
# Output: projectId: authType: Bearer token ... exit=0
testsprite project auto-auth " " --method password --inject header --dry-run
# Output: projectId: enabled: true ... exit=0
testsprite project sign-in get " " --dry-run
# Output: Environment default (default) ... exit=0
testsprite project sign-in set " " --mode public --dry-run
# Output: Environment default (default) ... exit=0
Observed: All 5 commands exit 0 and report success on whitespace project identifiers.
Expected: Consistent with project delete, each command rejects with typed VALIDATION_ERROR (exit 5) before constructing requests or emitting dry-run responses: Error: Invalid request. <project-id> is required and must not be empty or whitespace-only
Details / implementation notes
Proposed Fix:
- Add a shared
requireProjectId(raw: string | undefined): stringhelper insrc/commands/project.ts(or reuse across project command modules) that throws typedlocalValidationError('<project-id> is required and must not be empty or whitespace-only')(exit 5,VALIDATION_ERROR). - Call
requireProjectIdup front in:runUpdate(src/commands/project.ts)runCredential(src/commands/project.ts)runAutoAuth(src/commands/project.ts)runSignInGet(src/commands/project-sign-in.ts)runSignInSet(src/commands/project-sign-in.ts)
- Add test coverage in
src/commands/project.test.tsandsrc/commands/project-sign-in.spec.tsasserting that empty and whitespace project IDs consistently reject with code 5 (VALIDATION_ERROR) across all 5 commands in both live and--dry-runmodes without making network calls.
Confirmations
- I have searched existing issues and this is not a duplicate.
- I have provided my Discord identity above for reward coordination.
Activity
ruili-testsprite commentedon Oct 20, 2026
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
/assignon #368.