Skip to content

Commit 2e546a2

Browse files
authored
Merge pull request #884 from cipherstash/toby/doctor-preexisting-label-and-outro
stash doctor: an absent optional package is a skipped check, not a pass
2 parents ca73000 + ac46a5a commit 2e546a2

5 files changed

Lines changed: 36 additions & 9 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'stash': patch
3+
---
4+
5+
`stash doctor` no longer reports "All checks passed." when `@cipherstash/stack`
6+
is absent. The package is an optional peer, so running `doctor` before `stash
7+
init` skips the encryption check entirely — the row already said so, but the
8+
outro claimed a pass for a check that never ran. It now ends with "stash doctor
9+
could not run every check.", the same line an unprobeable install gets, and
10+
still exits 0: an absent optional package is recoverable, not a failure.

‎packages/cli/src/commands/doctor/index.ts‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface Probe {
3737

3838
const PROBES: Probe[] = [
3939
{
40-
label: 'Encryption engine (@cipherstash/stack → protect-ffi)',
40+
label: messages.doctor.encryptionProbeLabel,
4141
pkg: '@cipherstash/stack',
4242
subpath: './diagnostics',
4343
optional: true,
@@ -52,7 +52,7 @@ const PROBES: Probe[] = [
5252
},
5353
},
5454
{
55-
label: 'Auth (@cipherstash/auth)',
55+
label: messages.doctor.authProbeLabel,
5656
pkg: '@cipherstash/auth',
5757
async force() {
5858
// No counterpart call needed. This package's entry is `module.exports =
@@ -116,7 +116,12 @@ export async function doctorCommand(): Promise<void> {
116116
? messages.doctor.notInstalledOptional
117117
: messages.doctor.notInstalled,
118118
)
119-
if (!probe.optional) failed = true
119+
// The row stays green — absence before `stash init` is expected, and
120+
// the detail already says so — but the check did not RUN, which is the
121+
// same thing the too-old arm below records. Without this the outro said
122+
// every check passed while one of the two never executed.
123+
if (probe.optional) incomplete = true
124+
else failed = true
120125
} else if (isSubpathUnavailable(err, probe)) {
121126
report('warn', probe.label, messages.doctor.cannotProbe)
122127
incomplete = true

‎packages/cli/src/messages.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ export const messages = {
3535
title: 'stash doctor',
3636
/** Leader of the platform check line; the `<platform>-<arch>` is appended. */
3737
platformLabel: 'Platform',
38+
/**
39+
* Probe row labels. Here rather than inline in `commands/doctor/index.ts`
40+
* because both E2E suites match a row as `<label> — <detail>`: the detail
41+
* halves were already constants while the labels were copied into each
42+
* suite, so a copy tweak broke the tests from a file they don't name.
43+
*/
44+
encryptionProbeLabel:
45+
'Encryption engine (@cipherstash/stack → protect-ffi)',
46+
authProbeLabel: 'Auth (@cipherstash/auth)',
3847
allChecksPassed: 'All checks passed.',
3948
/** Row detail when a probe reached the loader and no platform binary was there. */
4049
nativeBinaryMissing: 'native binary missing',

‎packages/cli/tests/e2e/doctor-missing-binary.e2e.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ interface Target {
3535
const TARGETS: Target[] = [
3636
{
3737
pkg: '@cipherstash/protect-ffi',
38-
label: 'Encryption engine (@cipherstash/stack → protect-ffi)',
38+
label: messages.doctor.encryptionProbeLabel,
3939
// `src/load.cts`'s debug arm — a local cargo build sitting beside `lib/`.
4040
// A contributor who has run `pnpm run debug` has one, and without this the
4141
// fixture would load the binding it means to be missing.
4242
extra: String.raw`|(?:^|[\\/])index\.node$`,
4343
},
4444
{
4545
pkg: '@cipherstash/auth',
46-
label: 'Auth (@cipherstash/auth)',
46+
label: messages.doctor.authProbeLabel,
4747
// napi's local-build arm, tried before the platform package.
4848
extra: String.raw`|(?:^|[\\/])stack-auth-node\.node$`,
4949
},

‎packages/cli/tests/e2e/doctor-probe-classification.e2e.test.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ import { render } from '../helpers/pty.js'
2626
// the code and message pasted on. A fixture like that keeps passing when Node
2727
// changes either, which is the whole risk being covered.
2828

29-
/** Mirrors the probe labels in `src/commands/doctor/index.ts`. */
30-
const ENCRYPTION_LABEL = 'Encryption engine (@cipherstash/stack → protect-ffi)'
31-
const AUTH_LABEL = 'Auth (@cipherstash/auth)'
29+
const ENCRYPTION_LABEL = messages.doctor.encryptionProbeLabel
30+
const AUTH_LABEL = messages.doctor.authProbeLabel
3231

3332
interface Unresolve {
3433
/** The bare specifier to divert. */
@@ -125,7 +124,11 @@ describe.skipIf(!hooksAvailable)('stash doctor — probe classification', () =>
125124
expect(r.output).toContain(
126125
`${ENCRYPTION_LABEL} — ${messages.doctor.notInstalledOptional}`,
127126
)
128-
expect(r.output).toContain(messages.doctor.allChecksPassed)
127+
// Recoverable, so exit 0 and a green row — but the encryption check did not
128+
// run, and the outro must not say it passed. Same distinction the too-old
129+
// arm makes below; this arm predates it and claimed a pass.
130+
expect(r.output).toContain(messages.doctor.checksIncomplete)
131+
expect(r.output).not.toContain(messages.doctor.allChecksPassed)
129132
expect(r.output).not.toContain('Fatal error')
130133
// The optional package's absence must not be dressed up as a missing
131134
// binary — that would send the user to a reinstall for a package they

0 commit comments

Comments
 (0)