Skip to content

[Hackathon] fix(cli): an unreadable credentials file crashes doctor and offline commands in the telemetry pre-action hook #465

Open

Description

@freddy-tama

Verified against (commit SHA or released version)

commit 988c035 (main, v0.14.0), built and run on Windows 11, Node 24.16.

Discord Username / User ID

gradzzz

What does this improvement do?

testsprite doctor is written to survive an unreadable credentials file. When the read fails with EPERM or EACCES (the Windows ACL lock-out from #304; #356 stops new files from being locked, but it is not on npm yet, where the latest is 0.14.0), doctor reports the problem and how to recover (doctor.ts#L103-L124).

Users never get to see that. The preAction hook resolves telemetry auth before any command's action runs, with no try/catch (index.ts#L303-L307). It calls resolveTelemetryAuth, then loadConfig, then readFileSync (credentials.ts#L194). So the raw fs error ends the process.

Reproduction: HOME/USERPROFILE point at a temp directory whose .testsprite/credentials has a deny-read entry (icacls credentials /deny %USERNAME%:(R)), and the endpoint points at a closed local port.

> testsprite doctor
Error: EPERM: operation not permitted, open '...\.testsprite\credentials'
# exit 1

> set TESTSPRITE_NO_TELEMETRY=1
> testsprite doctor
  [FAIL] Credentials   credentials file exists but cannot be read (EPERM); its ACL may be locked out by an earlier CLI version — delete the file and re-run `testsprite setup`

Commands that never need the key fail too while telemetry is on, which is the default. testsprite agent list and testsprite test lint --plan-from plan.json both print the same raw EPERM and exit 1. With TESTSPRITE_NO_TELEMETRY=1 they run normally.

telemetry.ts states the contract: "every failure is swallowed; telemetry NEVER changes a command's behavior, output, or exit code". The send path follows it; the auth lookup in the hook does not.

Details / implementation notes

  • Make the telemetry auth lookup best-effort. Any error leaves telemetryAuth unset, so no event is sent, and the command runs and reports the problem its own way:
    • doctor degrades as designed;
    • commands that need the key fail through their normal error path;
    • offline commands just work.
  • Under --debug, log the swallowed error, like the skill-nudge path does (fix(skill-nudge): log swallowed errors in debug mode #317), so it stays diagnosable.
  • Tests:
    • a credentials read that throws EPERM: doctor reports the Credentials failure instead of crashing, an offline command exits 0, and no telemetry event is sent;
    • a unit test for the best-effort lookup.

Relation to #438, which covers a credentials path that is a directory or a named pipe in the credentials reader and doctor: this issue is the hook that runs before every command. Its fix is independent (index.ts / telemetry.ts only). It covers the EPERM case that doctor already handles, and #438's "doctor reports it under Credentials" relies on it while telemetry is on.

Confirmations

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

Activity

  1. fyZhang66 commented on Oct 20, 2026

    @fyZhang66
    Contributor

    Confirmed on v0.15.0, thanks @freddy-tama. The preAction telemetry hook calls resolveTelemetryAuth without a try/catch, so an unreadable credentials file (EPERM/EACCES) crashes every command before doctor can report it. Accepted, scope:

    • Catch inside the hook, skip the beacon and log under --debug; the command runs as if telemetry were off.
    • Tests (must fail before the fix): a credentials read that throws EPERM → doctor and completion still run and no beacon is sent.

    No new dependency. Comment /assign to claim it.

  2. added
    acceptedTriaged and accepted — a PR for this will be reviewed
    on Oct 20, 2026
  3. Davidson3556 commented on Oct 21, 2026

    @Davidson3556
    Contributor

    /assign

  4. testsprite-hob commented on Oct 21, 2026

    @testsprite-hob

    Assigned to @Davidson3556. Thanks for taking this on. (0 more slots available.)

    Your open assigned issues (3/3):

  5. testsprite-hob commented on Oct 22, 2026

    @testsprite-hob

    @Davidson3556, your claim on this issue expires in about 24 hours unless you open a PR that links it (for example, Closes #465 or Part of #465). You can re-claim later with /assign if the issue is still free.

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

Metadata

Metadata

Assignees

Labels

acceptedTriaged and accepted — a PR for this will be reviewedin-progressAssigned and actively being worked on

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions