Previously to this change, the 'guix refresh' download
policy (--key-download)would default to 'interactive', which would throw a
backtrace when guix was invoked with its stdin not connected to a peusdo
terminal (tty).  This change makes the new default value 'auto' use
interactive only in an interactive environment, with 'always' used as
fallback.

* doc/guix.texi (Invoking guix refresh): Adjust doc.
* etc/completion/fish/guix.fish: Adjust accordingly.
* etc/completion/zsh/_guix (_guix_list_installed_packages): Likewise.
* guix/gnupg.scm (gnupg-verify*): Change default #:key-download argument value
to 'auto.  Update doc.  Validate argument.  Raise an error in case read-line
returns #<eof>.
* guix/import/gnu.scm (gnu-package->sexp): <#:key-download>: Change default
value to 'auto.
* guix/import/gnu.scm (gnu->guix-package): <#:key-download>: Likewise.
* guix/scripts/import/gnu.scm (%options): Add "auto" to accepted
--key-download values.
(%default-options): Set default key-download option to the 'auto value.
(show-help): Update doc.
* guix/scripts/refresh.scm (show-help): Update doc.
(update-package) <#:key-download>: Change default value to 'auto.  Update doc.
* guix/upstream.scm (download-tarball): <#:key-download>: Likewise.
(package-update): Likewise.

Fixes: https://issues.guix.gnu.org/76112
Change-Id: Id1ca8fd6d453ca4bc5b372534445e3beab9133a8
---
 doc/guix.texi                 |  7 ++++++-
 etc/completion/fish/guix.fish |  4 ++--
 etc/completion/zsh/_guix      |  2 +-
 guix/gnupg.scm                | 37 +++++++++++++++++++++++++++++------
 guix/import/gnu.scm           |  6 +++---
 guix/scripts/import/gnu.scm   |  8 ++++----
 guix/scripts/refresh.scm      | 13 ++++++------
 guix/upstream.scm             | 10 +++++-----
 8 files changed, 59 insertions(+), 28 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 9f1e4bf0f0..c2c68d313b 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -15321,7 +15321,12 @@ Invoking guix refresh
 
 @item interactive
 When a package signed with an unknown OpenPGP key is encountered, ask
-the user whether to download it or not.  This is the default behavior.
+the user whether to download it or not.
+
+@item auto
+Automatically selects the @code{interactive} policy when the standard
+input is connected to a pseudo terminal (TTY), else @code{always}.  This
+is the default behavior.
 @end table
 
 @item --key-server=@var{host}
diff --git a/etc/completion/fish/guix.fish b/etc/completion/fish/guix.fish
index e6c290256f..9e3b3211ea 100644
--- a/etc/completion/fish/guix.fish
+++ b/etc/completion/fish/guix.fish
@@ -284,7 +284,7 @@ complete -f -c guix -n '__fish_guix_using_command refresh' 
-l list-updaters -d '
 complete -f -c guix -n '__fish_guix_using_command refresh' -l list-dependent 
-d 'list top-level dependent packages that would need to be rebuilt as a result 
of upgrading PACKAGE'
 complete -f -c guix -n '__fish_guix_using_command refresh' -a "--key-server=" 
-d 'use HOST as the OpenPGP key server'
 complete -f -c guix -n '__fish_guix_using_command refresh' -a "--gpg=" -d 'use 
COMMAND as the GnuPG 2.x command'
-complete -f -c guix -n '__fish_guix_using_command refresh' -a 
"--key-download=" -d 'handle missing OpenPGP keys according to POLICY.' 
--exclusive --arguments "always never interactive"
+complete -f -c guix -n '__fish_guix_using_command refresh' -a 
"--key-download=" -d 'handle missing OpenPGP keys according to POLICY.' 
--exclusive --arguments "always auto never interactive"
 
 #### publish
 set -l remotecommands port= listen= user= compression ttl= repl
@@ -321,7 +321,7 @@ set -l remotecommands import gnu nix pypi cpan hackage elpa 
gem cran crate texli
 complete -f -c guix -n '__fish_guix_needs_command' -a import -d 'Run IMPORTER 
with ARGS'
 ##### import gnu
 complete -f -c guix -n '__fish_guix_using_command import; and not 
__fish_seen_subcommand_from $remotecommands' -a gnu -d 'Return a package 
declaration template for PACKAGE, a GNU package.'
-complete -f -c guix -n '__fish_guix_using_command import; and 
__fish_seen_subcommand_from gnu' -a "--key-download=" -d 'handle missing 
OpenPGP keys according to POLICY: "always", "never", and "interactive", which 
is also used when "key-download" is not specified.'
+complete -f -c guix -n '__fish_guix_using_command import; and 
__fish_seen_subcommand_from gnu' -a "--key-download=" -d 'handle missing 
OpenPGP keys according to POLICY: "always", "auto", "never", and "interactive", 
which is also used when "key-download" is not specified.'
 ##### import pypi
 complete -f -c guix -n '__fish_guix_using_command import; and not 
__fish_seen_subcommand_from $remotecommands' -a pypi -d 'Import and convert the 
PyPI package for PACKAGE-NAME.'
 ##### import cpan
diff --git a/etc/completion/zsh/_guix b/etc/completion/zsh/_guix
index 9b1f16c664..42b92475a9 100644
--- a/etc/completion/zsh/_guix
+++ b/etc/completion/zsh/_guix
@@ -507,7 +507,7 @@ _guix_list_installed_packages()
         '--keyring=[use FILE as the keyring of upstream OpenPGP 
keys]:FILE:_files' \
         '--key-server=[use HOST as the OpenPGP key server]:HOST_hosts' \
         '--gpg=[use COMMAND as the GnuPG 2.x command]:COMMAND' \
-        '--key-download=[handle missing OpenPGP keys according to 
POLICY:]:POLICY:(always interactive never)' \
+        '--key-download=[handle missing OpenPGP keys according to 
POLICY:]:POLICY:(always auto interactive never)' \
         '--load-path=[prepend DIR to the package module search 
path]:DIR:_files -/' \
         {-V,--version}'[display version information and exit]' \
         '*:package:->packages'
diff --git a/guix/gnupg.scm b/guix/gnupg.scm
index 088bebc0de..ef9b71a2cb 100644
--- a/guix/gnupg.scm
+++ b/guix/gnupg.scm
@@ -2,7 +2,7 @@
 ;;; Copyright © 2010, 2011, 2013, 2014, 2016, 2018, 2019 Ludovic Courtès 
<l...@gnu.org>
 ;;; Copyright © 2013 Nikita Karetnikov <nik...@karetnikov.org>
 ;;; Copyright © 2020 Tobias Geerinckx-Rice <m...@tobias.gr>
-;;; Copyright © 2021 Maxim Cournoyer <maxim.courno...@gmail.com>
+;;; Copyright © 2021, 2025 Maxim Cournoyer <maxim.courno...@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -26,6 +26,8 @@ (define-module (guix gnupg)
   #:use-module (ice-9 rdelim)
   #:use-module (ice-9 i18n)
   #:use-module (srfi srfi-1)
+  #:use-module ((srfi srfi-34) #:select (raise))
+  #:use-module (guix diagnostics)
   #:use-module (guix i18n)
   #:use-module ((guix utils) #:select (config-directory))
   #:use-module ((guix build utils) #:select (mkdir-p))
@@ -201,7 +203,7 @@ (define* (gnupg-receive-keys fingerprint/key-id
 
 (define* (gnupg-verify* sig file
                         #:key
-                        (key-download 'interactive)
+                        (key-download 'auto)
                         server
                         (keyring (current-keyring)))
   "Like `gnupg-verify', but try downloading the public key if it's missing.
@@ -210,9 +212,29 @@ (define* (gnupg-verify* sig file
 'invalid-signature with a fingerprint if the signature is invalid.
 
 KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
-values: 'always', 'never', and 'interactive' (default).  Return a
+values: 'auto', 'always', 'never', and 'interactive' The default policy is
+auto, which automatically selects the interactive policy when a TTY is
+connected to the standard input, or the always policy otherwise.  Return a
 fingerprint/user name pair on success and #f otherwise."
-  (let ((status (gnupg-verify sig file)))
+  (let* ((interactive? (isatty? (current-input-port)))
+         ;; Validate or compute (in the case of 'auto) the KEY-DOWNLOAD
+         ;; argument.
+         (key-download (match key-download
+                         ('auto (if interactive?
+                                    'interactive
+                                    'always))
+                         ('interactive
+                          (unless interactive?
+                            (raise (formatted-message
+                                    (G_ "cannot use interactive policy\
+ without TTY input")))))
+                         ((or 'always 'never)
+                          key-download)
+                         (_
+                          (raise (formatted-message
+                                  (G_ "invalid key-download policy: ~a")
+                                  key-download)))))
+         (status (gnupg-verify sig file)))
     (match (gnupg-status-good-signature? status)
       ((fingerprint . user)
        (values 'valid-signature (cons fingerprint user)))
@@ -236,7 +258,10 @@ (define* (gnupg-verify* sig file
                     (format #t (G_ "Would you like to add this key \
 to keyring '~a'?~%")
                             keyring)
-                    (read-line))))
+                    (match (read-line)
+                      ((? eof-object?)
+                       (error "read-line unexpectedly returned #<eof>"))
+                      (other other)))))
              (string-match (locale-yes-regexp) answer)))
 
          (case key-download
@@ -244,7 +269,7 @@ (define* (gnupg-verify* sig file
             (values 'missing-key missing))
            ((always)
             (download-and-try-again))
-           (else
+           (else                        ;interactive
             (if (receive?)
                 (download-and-try-again)
                 (values 'missing-key missing)))))))))
diff --git a/guix/import/gnu.scm b/guix/import/gnu.scm
index fb61332fb8..e68dc06824 100644
--- a/guix/import/gnu.scm
+++ b/guix/import/gnu.scm
@@ -1,7 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <l...@gnu.org>
 ;;; Copyright © 2021 Simon Tournier <zimon.touto...@gmail.com>
-;;; Copyright © 2021 Maxim Cournoyer <maxim.courno...@gmail.com>
+;;; Copyright © 2021, 2025 Maxim Cournoyer <maxim.courno...@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -54,7 +54,7 @@ (define (preferred-archive-type release)
         '("xz" "lz" "bz2" "tbz2" "gz" "tgz" "Z")))
 
 (define* (gnu-package->sexp package release
-                            #:key (key-download 'interactive))
+                            #:key (key-download 'auto))
   "Return the 'package' sexp for the RELEASE (a <gnu-release>) of PACKAGE (a
 <gnu-package>), or #f upon failure.  Use KEY-DOWNLOAD as the OpenPGP key
 download policy (see 'download-tarball' for details.)"
@@ -106,7 +106,7 @@ (define* (gnu-package->sexp package release
        #f))))
 
 (define* (gnu->guix-package name
-                            #:key (key-download 'interactive)
+                            #:key (key-download 'auto)
                             #:allow-other-keys)
   "Return the package declaration for NAME as an s-expression.  Use
 KEY-DOWNLOAD as the OpenPGP key download policy (see 'download-tarball' for
diff --git a/guix/scripts/import/gnu.scm b/guix/scripts/import/gnu.scm
index 344e363abe..93ab6043c7 100644
--- a/guix/scripts/import/gnu.scm
+++ b/guix/scripts/import/gnu.scm
@@ -35,7 +35,7 @@ (define-module (guix scripts import gnu)
 ;;;
 
 (define %default-options
-  '((key-download . interactive)))
+  '((key-download . auto)))
 
 (define (show-help)
   (display (G_ "Usage: guix import gnu [OPTION...] PACKAGE
@@ -44,8 +44,8 @@ (define (show-help)
   (display (G_ "
       --key-download=POLICY
                          handle missing OpenPGP keys according to POLICY:
-                         'always', 'never', and 'interactive', which is also
-                         used when 'key-download' is not specified"))
+                         'auto' (default), 'always', 'never', and
+                         'interactive'"))
   (newline)
   (display (G_ "
   -h, --help             display this help and exit"))
@@ -66,7 +66,7 @@ (define %options
          (option '("key-download") #t #f          ;from (guix scripts refresh)
                  (lambda (opt name arg result)
                    (match arg
-                     ((or "interactive" "always" "never")
+                     ((or "auto" "interactive" "always" "never")
                       (alist-cons 'key-download (string->symbol arg)
                                   result))
                      (x
diff --git a/guix/scripts/refresh.scm b/guix/scripts/refresh.scm
index 8c72d0c545..6532feef25 100644
--- a/guix/scripts/refresh.scm
+++ b/guix/scripts/refresh.scm
@@ -10,7 +10,7 @@
 ;;; Copyright © 2020 Simon Tournier <zimon.touto...@gmail.com>
 ;;; Copyright © 2021 Sarah Morgensen <iskar...@mgsn.dev>
 ;;; Copyright © 2022 Hartmut Goebel <h.goe...@crazy-compilers.com>
-;;; Copyright © 2023 Maxim Cournoyer maxim.courno...@gmail.com>
+;;; Copyright © 2023, 2025 Maxim Cournoyer maxim.courno...@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -193,8 +193,9 @@ (define (show-help)
   (display (G_ "
       --key-download=POLICY
                          handle missing OpenPGP keys according to POLICY:
-                         'always', 'never', and 'interactive', which is also
-                         used when 'key-download' is not specified"))
+                         'auto', 'always', 'never', and 'interactive'.
+                         When left unspecified, the default policy is 'auto',
+                         which automatically selects interactive or always."))
   (newline)
   (display (G_ "
   -L, --load-path=DIR    prepend DIR to the package module search path"))
@@ -364,12 +365,12 @@ (define (warn-no-updater package)
            (package-name package)))
 
 (define* (update-package store package version updaters
-                         #:key (key-download 'interactive) key-server
+                         #:key (key-download 'auto) key-server
                          warn?)
   "Update the source file that defines PACKAGE with the new version.
 KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
-values: 'interactive' (default), 'always', and 'never'.  When WARN? is true,
-warn about packages that have no matching updater."
+values: 'auto' (default), interactive', 'always', and 'never'.  When WARN? is
+true, warn about packages that have no matching updater."
   (if (lookup-updater package updaters)
       (let ((version output source
                      (package-update store package updaters
diff --git a/guix/upstream.scm b/guix/upstream.scm
index 62ba6c9d39..169d260c2d 100644
--- a/guix/upstream.scm
+++ b/guix/upstream.scm
@@ -314,14 +314,14 @@ (define (uncompressed-tarball name tarball)
                                         #$output)))))
 
 (define* (download-tarball store url signature-url
-                           #:key (key-download 'interactive) key-server)
+                           #:key (key-download 'auto) key-server)
   "Download the tarball at URL to the store; check its OpenPGP signature at
 SIGNATURE-URL, unless SIGNATURE-URL is false.  On success, return the tarball
 file name; return #f on failure (network failure or authentication failure).
 
 KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
-values: 'interactive' (default), 'always', and 'never'; KEY-SERVER specifies
-the OpenPGP key server where the key should be looked up."
+values: 'auto' (default), 'always', 'interactive' and 'never'; KEY-SERVER
+specifies the OpenPGP key server where the key should be looked up."
   (let ((tarball (download-to-store store url)))
     (if (not signature-url)
         tarball
@@ -512,12 +512,12 @@ (define %method-updates
 (define* (package-update store package
                          #:optional (updaters (force %updaters))
                          #:key (version #f)
-                         (key-download 'interactive) key-server)
+                         (key-download 'auto) key-server)
   "Return the new version, the file name of the new version tarball, and input
 changes for PACKAGE; return #f (three values) when PACKAGE is up-to-date;
 raise an error when the updater could not determine available releases.
 KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
-values: 'always', 'never', and 'interactive' (default).
+values: 'always', 'auto' (default), 'never', and 'interactive'.
 
 When VERSION is specified, update PACKAGE to that version, even if that is a
 downgrade."

base-commit: 220ef58440668c39ddf7c6434c0fbfc82d3dd507
-- 
2.48.1




Reply via email to