Skip to content

pass command instead of password in zuliprc #1581

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

Gopinath-Mahendiran
Copy link

@Gopinath-Mahendiran Gopinath-Mahendiran commented Apr 10, 2025

What does this PR do, and why?

This PR updates the default config generation logic in zulip-term to support a more secure way of managing Zulip API keys. Instead of writing the API key directly into the zuliprc file, we now generate:
• a zuliprc file with a passcmd field
• a zulip_key file containing just the API key
• zulip_key: A temporary file that contains only the API key.
• zuliprc: [api]: contains Zulip login configuration (email, server URL, and now passcmd)

Here’s how the new auto-generated zuliprc file looks:

[api]
email=abc@gmail.com
# Fill the passcmd field with a command that outputs the API key.
# The API key is temporarily stored in the 'zulip_key' file.
# After storing the key in a password manager, please delete the 'zulip_key' file.
passcmd=cat zulip_key
site=https://chat.zulip.org

If you’re downloading a zuliprc file from your Zulip account (which includes the key field), you’re encouraged to manually replace the key line with a passcmd, like this:

passcmd=cat zulip_key

You can (and should) later replace cat zulip_key with a command tied to your preferred secret storage tool

Outstanding aspect(s)

  • [ ]

External discussion & connections

How did you test this?

  • Manually - Behavioral changes
  • Manually - Visual changes
  • Adapting existing automated tests
  • Adding automated tests for new behavior (or missing tests)
  • Existing automated tests should already cover this (only a refactor of tested code)

Self-review checklist for each commit

  • It is a minimal coherent idea
  • It has a commit summary following the documented style (title & body)
  • It has a commit summary describing the motivation and reasoning for the change
  • It individually passes linting and tests
  • It contains test additions for any new behavior
  • It flows clearly from a previous branch commit, and/or prepares for the next commit

@zulipbot zulipbot added the size: L [Automatic label added by zulipbot] label Apr 10, 2025
@zulipbot
Copy link
Member

Hello @Gopinath-Mahendiran, it seems like you have referenced #1502 in your pull request description, but you have not referenced them in your commit message description(s). Referencing an issue in a commit message automatically closes the corresponding issue when the commit is merged, which makes the issue tracker easier to manage.

Please run git commit --amend in your command line client to amend your commit message description with Fixes #1502..

An example of a correctly-formatted commit:

commit fabd5e450374c8dde65ec35f02140383940fe146
Author: zulipbot
Date:   Sat Mar 18 13:42:40 2017 -0700

    pull requests: Check PR commits reference when issue is referenced.

    Fixes #51.

To learn how to write a great commit message, please refer to our guide.

@Gopinath-Mahendiran Gopinath-Mahendiran changed the title Gopinath mahendiran pass command instead of password in zuliprc Apr 10, 2025
@Gopinath-Mahendiran Gopinath-Mahendiran force-pushed the Gopinath-Mahendiran branch 2 times, most recently from c165d04 to 0e5ca88 Compare April 13, 2025 17:28
@zulipbot zulipbot added size: XL [Automatic label added by zulipbot] and removed size: L [Automatic label added by zulipbot] labels Apr 13, 2025
@Gopinath-Mahendiran
Copy link
Author

Gopinath-Mahendiran commented Apr 13, 2025

@neiljp,@dkwo review the pr and kindly give the feedback

Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

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

@Gopinath-Mahendiran It looks like you have the right idea here now 👍

I've left some inline comments, since there are a few adjustments still to be made, but it's easier to point them out in the code now.

We can include this only in Terminal, but as Tim said, you could add it to the general Zulip python library instead. That would of course affect where the initial changes are made - but we could still document how it works for those using it in Terminal as a follow-up here, or perhaps wrap options in command-line flags.

You've updated some test code to match the code, but where you've added code it'd be useful to have new tests to demonstrate the functionality. I may have missed that - the last commit is rather large and full of unrelated changes.

@@ -137,6 +139,25 @@ def raise_exception_in_main_thread(
self._exception_info = exc_info
self._critical_exception = critical
os.write(self._exception_pipe, b"1")

def get_api_key(self,config_file: str) -> Optional[str]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we're including this in the Terminal app, this should be integrated into the existing code in run.py, where we handle elements in the config file.

Alternatively, as discussed on chat.zulip.org, you could add this to the zulip package in the python-zulip-api repository, since it could then load it transparently in the Client initializer when we use it in Terminal.

Choose a reason for hiding this comment

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

Moved the logic for retrieving the API key (get_api_key) to the python-zulip-api repository as part of PR #86

Comment on lines 338 to 347
f.write(f"[api]\nemail={login_id}\nkey={api_key}\nsite={server_url}")
f.write(f"[api]\nemail={login_id}\n# Fill the passcmd field with a command that outputs the API key.\n# The API key is temporarily stored in the 'zulip_key' file at {os.path.dirname(os.path.abspath(to_path))}.\n# After storing the key in a password manager, replace the cmd.\npasscmd=cat zulip_key\nsite={server_url}")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Automatic creation is likely to be a rare enough feature, that we can leave this element for now, but if the commit is tidied up we can move it to the end to more easily merge the earlier commit(s).

Choose a reason for hiding this comment

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

Removed the implementation responsible for automatic creation

return ""
except FileExistsError:
return f"zuliprc already exists at {to_path}"
except OSError as ex:
return f"{ex.__class__.__name__}: zuliprc could not be created at {to_path}"

def _write_zulip_key(to_path: str, *, api_key: str) -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function is very similar to the function above. Instead of adding a near-duplicate, it is preferable to refactor the existing code and then use that new version for the feature commit.

Choose a reason for hiding this comment

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

refactored the function by removing duplicate-lines

Comment on lines 325 to 333
if not save_zulipkey_failure:
print(f"Generated API key saved at {zulip_key_path}")
else:
exit_with_error(save_zuliprc_failure)

if not save_zuliprc_failure :
print(f"Generated config file saved at {zuliprc_path}")
else:
exit_with_error(save_zuliprc_failure)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this saved only one file, what would you expect to happen?

Choose a reason for hiding this comment

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

could you explain this in detail?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Does it make sense to (only) save one file, if there is an error saving the other?

Choose a reason for hiding this comment

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

Ensured that if an error occurs during the creation of one file, the other files are not created, maintaining consistency.

@@ -257,6 +265,7 @@ transparency=disabled
# editor: nano
```


Copy link
Collaborator

Choose a reason for hiding this comment

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

Please check for unnecessary additions.

Comment on lines +210 to +215
configuration conssist of two file:
- zulip_key, file contains the api_key
- zuliprc, file consist of login configurations

The `zulip_key`contains only the api_key.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The zulip_key (or similar) file is intended to be optional, so that zuliprc files in a previous format (and current, from the web app) work correctly.

For that reason anything like this part should likely be further down.

Since this documents the way the zuliprc file works, whether only for the Terminal app, or for all apps using the python zulip package (when we use the updated package, if so), it should be clear that it refers to the [api] part of the config.

Comment on lines -225 to +233
key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
passcmd=cat zulip_key
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since this needs to be optional, and if in Terminal only will be specific to us, it needs to be briefly documented in the sample file, and commented out - see how we document the Terminal options further below.

@@ -207,6 +207,12 @@ to get the hang of things.

## Configuration
Copy link
Collaborator

Choose a reason for hiding this comment

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

This last commit is not just a docs update. If there are changes to tidy other commits, they belong combined with those commits. That will ensure that all the linting and tests passes on each commit individually, rather than just over the branch.

If you have other changes, they belong in new commits specific to those improvements.

pyproject.toml Outdated
Comment on lines 141 to 144
markers = [
"wsl: marks tests as WSL specific",
"quoted_content: marks tests dealing with quoted content rendering",
]
Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks unrelated.

@neiljp neiljp added PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback enhancement New feature or request area: config area: login labels Apr 15, 2025
@Gopinath-Mahendiran
Copy link
Author

I will work towards the changes

@Gopinath-Mahendiran Gopinath-Mahendiran force-pushed the Gopinath-Mahendiran branch 2 times, most recently from e516da9 to daba4fd Compare April 24, 2025 17:43
@Gopinath-Mahendiran
Copy link
Author

@neiljp, updated the code as discussed. Let me know if it looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: config area: login enhancement New feature or request PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback size: XL [Automatic label added by zulipbot]
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pass command instead of password in zuliprc?
3 participants