emacs-jupyter / jupyter

An interface to communicate with Jupyter kernels.
GNU General Public License v3.0
947 stars 93 forks source link

[Upstream Regresion?] `jupyter-tramp-read-passwd`: `tramp-read-passwd nil` no longer works #524

Open NightMachinery opened 9 months ago

NightMachinery commented 9 months ago
(defun jupyter-tramp-read-passwd (filename &optional prompt)
  "Read a password based off of FILENAME's TRAMP filename components.
Use PROMPT to prompt the user for the password if needed, PROMPT
defaults to \"Password:\"."
  (unless (jupyter-tramp-file-name-p filename)
    (error "Not a Jupyter filename"))
  (with-parsed-tramp-file-name filename nil
    (let ((tramp-current-method method)
          (tramp-current-user (or user user-login-name))
          (tramp-current-domain nil)
          (tramp-current-host host)
          (tramp-current-port port))
      (tramp-read-passwd nil (or prompt "Password: ")))))

This function passes nil for proc to tramp-read-passwd, which triggers this error on emacs 29.2:

Debugger entered--Lisp error: (wrong-type-argument processp nil)
  process-get(nil tramp-vector)
  tramp-read-passwd(nil "Password [/jpy:127.0.0.1#6035:]: ")
  (let ((tramp-current-method method) (tramp-current-user (or user user-login-name)) (tramp-current-domain nil) (tramp-current-host host) (tramp-current-port port)) (tramp-read-passwd nil (or prompt "Password: ")))
  (let* ((v (tramp-dissect-file-name filename)) (method (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 1 v))) (user (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 2 v))) (domain (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 3 v))) (host (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 4 v))) (port (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 5 v))) (localname (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 6 v))) (hop (progn (or (progn (and (memq ... cl-struct-tramp-file-name-tags) t)) (signal 'wrong-type-argument (list 'tramp-file-name v))) (nth 7 v)))) (ignore method user domain host port localname hop) (let ((tramp-current-method method) (tramp-current-user (or user user-login-name)) (tramp-current-domain nil) (tramp-current-host host) (tramp-current-port port)) (tramp-read-passwd nil (or prompt "Password: "))))
  jupyter-tramp-read-passwd("/jpy:127.0.0.1#6035:orgk1/" "Password [/jpy:127.0.0.1#6035:]: ")

I am not sure if what the root cause of the issue is, but calling tramp-read-passwd with nil doesn't work in the latest emacs version.

NightMachinery commented 9 months ago

I solved this issue by forgoing tramp altogether:

(defun night/jupyter-tramp-read-passwd (filename &optional prompt)
  "Read a password based off of FILENAME's TRAMP filename components.
Use PROMPT to prompt the user for the password if needed, PROMPT
defaults to \"Password:\"."
  (unless (jupyter-tramp-file-name-p filename)
    (error "Not a Jupyter filename"))
  (let ((prompt (or prompt "Password: ")))
    (comment
     (with-parsed-tramp-file-name filename nil
       (let ((tramp-current-method method)
             (tramp-current-user (or user user-login-name))
             (tramp-current-domain nil)
             (tramp-current-host host)
             (tramp-current-port port))
         (tramp-read-passwd nil prompt))))
    (password-read prompt filename)))
(advice-add 'jupyter-tramp-read-passwd :override #'night/jupyter-tramp-read-passwd)
nnicandro commented 9 months ago

Thanks for the bug report. It is odd that I passed in nil to tramp-read-passwd here. Looking back in the history of that function, that process-get call has been there since at least Emacs 27.1. I wrote jupyter-tramp-read-passwd based off of the internals of tramp-read-passwd in Emacs 26.3 and earlier which didn't really do much with the proc argument.

I like to go through tramp-read-passwd because it, in addition to the password cache, consults auth-sources. So I'd like to continue using it.

I think the issue here is that tramp assumes that there is always a process directly associated with all its connections, whereas in the Jupyter case the connection is handled by the underlying url library and interactions are made via the REST API through calls to url-retrieve in the Jupyter code.

A possible solution would be to get access to the underlying process for those url-retrieve calls and use it as the proc argument to tramp-read-passwd. We would have to setup all the process properties that tramp expects to be available in its connection buffers though like that tramp-vector property. In the function jupyter-tramp-connected-p, there is code for getting the underlying process.

Another possible solution would be to do as you do and just go through password-read, but like I said I would prefer going through tramp-read-passwd due to its checking of auth-sources.

NightMachinery commented 9 months ago

What does auth-sources do? Can I define the password needed for a connection like :session /jpy:127.0.0.1#6035:orgk1/ in ~/.authinfo?

By the way, since switching to password-read, Emacs hasn't asked me for a password after a restart. I think it used to do so, though I am not sure whether it was after restarting the Jupyter server or my laptop.

The weird thing is that I have been using emacs 29.0.xx before, and things worked fine; but when I looked at emacs' source code, it indeed seems to have needed proc for years.

nnicandro commented 9 months ago

auth-sources is another password caching mechanism where the cache is one of the files specified in the auth-sources variable. You can read more about the format expected by TRAMP at https://www.gnu.org/software/emacs/manual//html_node/tramp/Password-handling.html.