Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ export class Diagnostics {
const testName = 'using latest or latest-rc CLI version';
let status: DiagnosticStatus['status'] = 'unknown';

childProcess.exec(`npm view ${cliName} dist-tags.latest`, {}, (error, stdout, stderr) => {
// Use execFile instead of exec to avoid shell interpretation.
// exec invokes cmd.exe on Windows, which resolves commands from CWD before PATH.
childProcess.execFile('npm', ['view', cliName, 'dist-tags.latest'], (error, stdout, stderr) => {
const code = error?.code ?? 0;
if (code === 0) {
const latest = stdout.trim();
Expand Down
54 changes: 31 additions & 23 deletions test/diagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ describe('Diagnostics', () => {
const sandbox = Sinon.createSandbox();
const lifecycle = Lifecycle.getInstance();

let childProcessExecStub: sinon.SinonStub;
let childProcessExecFileStub: sinon.SinonStub;
let drAddSuggestionSpy: sinon.SinonSpy;
let lifecycleEmitSpy: sinon.SinonSpy;

beforeEach(() => {
stubMethod(sandbox, ux, 'stdout');
childProcessExecStub = stubMethod(sandbox, childProcess, 'exec');
childProcessExecFileStub = sandbox.stub(childProcess, 'execFile');
drAddSuggestionSpy = spyMethod(sandbox, Doctor.prototype, 'addSuggestion');
lifecycleEmitSpy = spyMethod(sandbox, lifecycle, 'emit');
oclifConfig = {
Expand Down Expand Up @@ -98,7 +98,7 @@ describe('Diagnostics', () => {

// This will have to be updated with each new test
expect(results.length).to.equal(6);
expect(childProcessExecStub.called).to.be.true;
expect(childProcessExecFileStub.called).to.be.true;
expect(lifecycleEmitSpy.called).to.be.true;
expect(lifecycleEmitSpy.args[0][0]).to.equal('Doctor:diagnostic');
expect(lifecycleEmitSpy.args[0][1]).to.have.property('testName');
Expand Down Expand Up @@ -235,11 +235,13 @@ describe('Diagnostics', () => {

describe('outdatedCliVersionCheck', () => {
it('passes when CLI version is equal to latest', async () => {
childProcessExecStub.callsFake((cmdString, opts, cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmdString).to.equal('npm view sfdx-cli dist-tags.latest');
expect(opts).to.be.ok;
cb({}, '7.160.0', '');
});
childProcessExecFileStub.callsFake(
(cmd: string, args: string[], cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmd).to.equal('npm');
expect(args).to.deep.equal(['view', 'sfdx-cli', 'dist-tags.latest']);
cb(null, '7.160.0', '');
}
);

const dr = Doctor.init(oclifConfig);
const diagnostics = new Diagnostics(dr, oclifConfig);
Expand All @@ -254,11 +256,13 @@ describe('Diagnostics', () => {
});

it('passes when CLI version is greater than latest', async () => {
childProcessExecStub.callsFake((cmdString, opts, cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmdString).to.equal('npm view sfdx-cli dist-tags.latest');
expect(opts).to.be.ok;
cb({}, '7.159.0', '');
});
childProcessExecFileStub.callsFake(
(cmd: string, args: string[], cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmd).to.equal('npm');
expect(args).to.deep.equal(['view', 'sfdx-cli', 'dist-tags.latest']);
cb(null, '7.159.0', '');
}
);

const dr = Doctor.init(oclifConfig);
const diagnostics = new Diagnostics(dr, oclifConfig);
Expand All @@ -273,11 +277,13 @@ describe('Diagnostics', () => {
});

it('fails when CLI version is less than latest', async () => {
childProcessExecStub.callsFake((cmdString, opts, cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmdString).to.equal('npm view sfdx-cli dist-tags.latest');
expect(opts).to.be.ok;
cb({}, '7.162.0', '');
});
childProcessExecFileStub.callsFake(
(cmd: string, args: string[], cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmd).to.equal('npm');
expect(args).to.deep.equal(['view', 'sfdx-cli', 'dist-tags.latest']);
cb(null, '7.162.0', '');
}
);

const dr = Doctor.init(oclifConfig);
const diagnostics = new Diagnostics(dr, oclifConfig);
Expand All @@ -292,11 +298,13 @@ describe('Diagnostics', () => {
});

it('fails when npm request fails', async () => {
childProcessExecStub.callsFake((cmdString, opts, cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmdString).to.equal('npm view sfdx-cli dist-tags.latest');
expect(opts).to.be.ok;
cb({ code: 1 }, '', 'connection timeout');
});
childProcessExecFileStub.callsFake(
(cmd: string, args: string[], cb: (e: unknown, stdout: unknown, stderr: unknown) => void) => {
expect(cmd).to.equal('npm');
expect(args).to.deep.equal(['view', 'sfdx-cli', 'dist-tags.latest']);
cb({ code: 1 }, '', 'connection timeout');
}
);

const dr = Doctor.init(oclifConfig);
const diagnostics = new Diagnostics(dr, oclifConfig);
Expand Down
Loading