Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cli): empty ~/.codemod same as non-existent for credentials #1398

Closed

Conversation

spirulence
Copy link
Contributor

📚 Description

When a user attempts to login to the codemod platform using the CLI, and doesn't have the right binaries installed for keytar to work as intended, it's supposed to print an error like the following to help users install the right packages, or allow them to proceed with plaintext password storage if they want to live more adventurously:

CleanShot 2024-12-01 at 22 02 21

However, first time installers of the codemod cli may run into this issue if they do not have a ~/.codemod directory in their home path:

CleanShot 2024-12-01 at 21 58 43

Because the login command will create this directory when successfully setting authentication credentials, the more proper behavior would be to treat a non-existent directory as an empty one.

🔗 Linked Issue

Fixes #1397

🧪 Test Plan

On the latest main, in addition to npm latest, running codemod login locally has different results if the ~/.codemod directory is missing or simply empty.

Build first:
npx turbo build

Then run the following:

└─(06:50:36 on main ✹)──> rm -rf ~/.codemod && node apps/cli/dist/index.cjs login           

ENOENT: no such file or directory, scandir '/home/developer/.codemod'

└─(06:50:43 on main ✹)──> mkdir -p ~/.codemod && node apps/cli/dist/index.cjs login                                                      
Error: libsecret-1.so.0: cannot open shared object file: No such file or directory 

Codemod CLI uses "keytar" to store your credentials securely. 
Please make sure you have "libsecret" installed on your system. 
Depending on your distribution, you will need to run the following command 
Debian/Ubuntu: sudo apt-get install libsecret-1-dev 
Fedora: sudo dnf install libsecret 
Arch Linux: sudo pacman -S libsecret 

If you were not able to install the necessary package or CLI was not able to detect the installationplease reach out to us at our Community Slack channel. 
You can still use the CLI with file-based replacement that will store your credentials at your home directory.
⠋ Redirecting to Codemod sign-in pagenode:events:496
      throw er; // Unhandled 'error' event
      ^

Error: spawn xdg-open ENOENT
    at ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on ChildProcess instance at:
    at ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn xdg-open',
  path: 'xdg-open',
  spawnargs: [
    'https://staging.codemod.com?command=accessTokenRequestedByCLI&sessionId=f1vSZl7jHosGsD6-R4APfRESwpwKHCPC_fr2hRI2kMZNKwFZlTTXK4i9DUdSPBRi&iv=HCkCFrE5fatr-EedwDuHcA'
  ]
}

Node.js v20.18.1

Using the version in this branch, the behavior is consistent:

└─(06:52:21 on cs/codemod-login-first-time ✹)──> rm -rf ~/.codemod && node apps/cli/dist/index.cjs login   
Error: libsecret-1.so.0: cannot open shared object file: No such file or directory 

Codemod CLI uses "keytar" to store your credentials securely. 
Please make sure you have "libsecret" installed on your system. 
Depending on your distribution, you will need to run the following command 
Debian/Ubuntu: sudo apt-get install libsecret-1-dev 
Fedora: sudo dnf install libsecret 
Arch Linux: sudo pacman -S libsecret 

If you were not able to install the necessary package or CLI was not able to detect the installationplease reach out to us at our Community Slack channel. 
You can still use the CLI with file-based replacement that will store your credentials at your home directory.
⠋ Redirecting to Codemod sign-in pagenode:events:496
      throw er; // Unhandled 'error' event
      ^

Error: spawn xdg-open ENOENT
    at ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on ChildProcess instance at:
    at ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn xdg-open',
  path: 'xdg-open',
  spawnargs: [
    'https://staging.codemod.com?command=accessTokenRequestedByCLI&sessionId=NTfhpqdvCJHkdHH0WCC5rzj8ubLAtszRLJ5kiVH5snLKIW5Doj793XFDrN9t9GIY&iv=hv3z_TyeomDHMYHniIm4QA'
  ]
}

Node.js v20.18.1

└─(06:52:29 on cs/codemod-login-first-time ✹)──> mkdir -p ~/.codemod && node apps/cli/dist/index.cjs login                           
Error: libsecret-1.so.0: cannot open shared object file: No such file or directory 

Codemod CLI uses "keytar" to store your credentials securely. 
Please make sure you have "libsecret" installed on your system. 
Depending on your distribution, you will need to run the following command 
Debian/Ubuntu: sudo apt-get install libsecret-1-dev 
Fedora: sudo dnf install libsecret 
Arch Linux: sudo pacman -S libsecret 

If you were not able to install the necessary package or CLI was not able to detect the installationplease reach out to us at our Community Slack channel. 
You can still use the CLI with file-based replacement that will store your credentials at your home directory.
⠋ Redirecting to Codemod sign-in pagenode:events:496
      throw er; // Unhandled 'error' event
      ^

Error: spawn xdg-open ENOENT
    at ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on ChildProcess instance at:
    at ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn xdg-open',
  path: 'xdg-open',
  spawnargs: [
    'https://staging.codemod.com?command=accessTokenRequestedByCLI&sessionId=iT_bscKcL9d3LevshflsoqN_Fgzj7hqz0dMujfqIRq7gj-dj676KTluCQ-c_GZUx&iv=awLENs_2UwQEHiKFq3OJNw'
  ]
}

Node.js v20.18.1

The change is accomplished by breaking out the logic that reads the directory into it's own function, which returns an empty list of credentials to the caller if the directory is empty or if it doesn't exist. Unit tests using memfs are provided to test this functionality.

📄 Documentation to Update

Unaware of any documentation to update.

Copy link

vercel bot commented Dec 2, 2024

@spirulence is attempting to deploy a commit to the Codemod Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant
Copy link

CLAassistant commented Dec 2, 2024

CLA assistant check
All committers have signed the CLA.

@spirulence spirulence force-pushed the cs/codemod-login-first-time branch from 346f241 to d2bf003 Compare December 2, 2024 07:01
@spirulence spirulence changed the title fix(cli): non-existent ~/.codemod directory same as empty during codemod login fix(cli): non-existent ~/.codemod directory same as non-existent for credentials Dec 2, 2024
@spirulence spirulence force-pushed the cs/codemod-login-first-time branch from c7042a7 to ce6c6cf Compare December 2, 2024 07:17
@spirulence
Copy link
Contributor Author

I receive a clean test run with this new test suite:

> [email protected] test /home/developer/gitclone/codemod/apps/cli
> TEST=1 vitest run


 RUN  v1.6.0 /home/developer/gitclone/codemod/apps/cli

stderr | test/credentialsStorage.test.ts > CredentialsStorage > when .codemod directory does not exist > should return null without throwing an error
Error: libsecret-1.so.0: cannot open shared object file: No such file or directory 

Codemod CLI uses "keytar" to store your credentials securely. 
Please make sure you have "libsecret" installed on your system. 
Depending on your distribution, you will need to run the following command 
Debian/Ubuntu: sudo apt-get install libsecret-1-dev 
Fedora: sudo dnf install libsecret 
Arch Linux: sudo pacman -S libsecret 

If you were not able to install the necessary package or CLI was not able to detect the installationplease reach out to us at our Community Slack channel. 
You can still use the CLI with file-based replacement that will store your credentials at your home directory.

 ✓ test/credentialsStorage.test.ts (4)
   ✓ CredentialsStorage (4)
     ✓ when .codemod directory does not exist (1)
       ✓ should return null without throwing an error
     ✓ when there is a different kind of error reading the directory (1)
       ✓ should rethrow the error
     ✓ when .codemod directory exists (2)
       ✓ should return null when no credentials are found
       ✓ should retrieve existing credentials when found

 Test Files  1 passed (1)
      Tests  4 passed (4)
   Start at  07:18:37
   Duration  1.18s (transform 269ms, setup 14ms, collect 807ms, tests 29ms, environment 0ms, prepare 104ms)```

@spirulence spirulence changed the title fix(cli): non-existent ~/.codemod directory same as non-existent for credentials fix(cli): empty ~/.codemod same as non-existent for credentials Dec 2, 2024
Copy link
Contributor Author

@spirulence spirulence left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some self-review.

vol.fromJSON({ "": "" }, "/home/codemod-test/.codemod");

const storage = new CredentialsStorage();
expect(storage.get(testAccount)).rejects.toThrow();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would not be hard to expect the specific ENOTDIR error to be thrown. Might do.


describe("when .codemod directory does not exist", () => {
beforeEach(() => {
vol.reset();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This before each block is repeated on each test. Would be happy to move to enclosing scope.

vi.mock("node:fs/promises", () => fs.promises);

// Use a mock homedir in order to reliably have a memfs home directory
vi.mock("node:os", () => ({ homedir: () => "/home/codemod-test/" }));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a better way to enforce a homedirectory than by mocking an implementation internal, I'm down to do that instead.

import {
CredentialsStorage,
CredentialsStorageType,
} from "../src/credentials-storage.js";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a relative import the expected way to pull in the code under test?

);
} catch (error) {
// If the directory does not exist, treat it as "no results"
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also need to test what happens here if readdir throws an error that is not a NodeJS.ErrnoException or does not have a .code attribute

@spirulence
Copy link
Contributor Author

closing in favor of #1401

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[codemod] codemod login fails for first-time users that don't have a ~/.codemod directory
2 participants