Next: , Previous: , Up: Package Management   [Contents][Index]


4.7 Channels

Guix and its package collection are updated by running guix pull (see Invoking guix pull). By default guix pull downloads and deploys Guix itself from the official GNU Guix repository. This can be customized by defining channels in the ~/.config/guix/channels.scm file. A channel specifies a URL and branch of a Git repository to be deployed, and guix pull can be instructed to pull from one or more channels. In other words, channels can be used to customize and to extend Guix, as we will see below. Before that, some security considerations.

4.7.1 Channel Authentication

The guix pull and guix time-machine commands authenticate the code retrieved from channels: they make sure each commit that is fetched is signed by an authorized developer. The goal is to protect from unauthorized modifications to the channel that would lead users to run malicious code.

As a user, you must provide a channel introduction in your channels file so that Guix knows how to authenticate its first commit. A channel specification, including its introduction, looks something along these lines:

(channel
  (name 'my-channel)
  (url "https://example.org/my-channel.git")
  (introduction
   (make-channel-introduction
    "6f0d8cc0d88abb59c324b2990bfee2876016bb86"
    (openpgp-fingerprint
     "CABB A931 C0FF EEC6 900D  0CFB 090B 1199 3D9A EBB5"))))

The specification above shows the name and URL of the channel. The call to make-channel-introduction above specifies that authentication of this channel starts at commit 6f0d8cc…, which is signed by the OpenPGP key with fingerprint CABB A931….

For the main channel, called guix, you automatically get that information from your Guix installation. For other channels, include the channel introduction provided by the channel authors in your channels.scm file. Make sure you retrieve the channel introduction from a trusted source since that is the root of your trust.

If you’re curious about the authentication mechanics, read on!

4.7.2 Using a Custom Guix Channel

The channel called guix specifies where Guix itself—its command-line tools as well as its package collection—should be downloaded. For instance, suppose you want to update from your own copy of the Guix repository at example.org, and specifically the super-hacks branch, you can write in ~/.config/guix/channels.scm this specification:

;; Tell 'guix pull' to use my own repo.
(list (channel
        (name 'guix)
        (url "https://example.org/my-guix.git")
        (branch "super-hacks")))

From there on, guix pull will fetch code from the super-hacks branch of the repository at example.org.

4.7.3 Specifying Additional Channels

You can also specify additional channels to pull from. Let’s say you have a bunch of custom package variants or personal packages that you think would make little sense to contribute to the Guix project, but would like to have these packages transparently available to you at the command line. You would first write modules containing those package definitions (see Package Modules), maintain them in a Git repository, and then you and anyone else can use it as an additional channel to get packages from. Neat, no?

Warning: Before you, dear user, shout—“woow this is soooo coool!”—and publish your personal channel to the world, we would like to share a few words of caution:

You’ve been warned! Having said this, we believe external channels are a practical way to exert your freedom to augment Guix’ package collection and to share your improvements, which are basic tenets of free software. Please email us at guix-devel@gnu.org if you’d like to discuss this.

To use a channel, write ~/.config/guix/channels.scm to instruct guix pull to pull from it in addition to the default Guix channel(s):

;; Add my personal packages to those Guix provides.
(cons (channel
        (name 'my-personal-packages)
        (url "https://example.org/personal-packages.git"))
      %default-channels)

Note that the snippet above is (as always!) Scheme code; we use cons to add a channel the list of channels that the variable %default-channels is bound to (see cons and lists in GNU Guile Reference Manual). With this file in place, guix pull builds not only Guix but also the package modules from your own repository. The result in ~/.config/guix/current is the union of Guix with your own package modules:

$ guix pull --list-generations
…
Generation 19	Aug 27 2018 16:20:48
  guix d894ab8
    repository URL: https://git.savannah.gnu.org/git/guix.git
    branch: master
    commit: d894ab8e9bfabcefa6c49d9ba2e834dd5a73a300
  my-personal-packages dd3df5e
    repository URL: https://example.org/personal-packages.git
    branch: master
    commit: dd3df5e2c8818760a8fc0bd699e55d3b69fef2bb
  11 new packages: my-gimp, my-emacs-with-cool-features, …
  4 packages upgraded: emacs-racket-mode@0.0.2-2.1b78827, …

The output of guix pull above shows that Generation 19 includes both Guix and packages from the my-personal-packages channel. Among the new and upgraded packages that are listed, some like my-gimp and my-emacs-with-cool-features might come from my-personal-packages, while others come from the Guix default channel.

To create a channel, create a Git repository containing your own package modules and make it available. The repository can contain anything, but a useful channel will contain Guile modules that export packages. Once you start using a channel, Guix will behave as if the root directory of that channel’s Git repository has been added to the Guile load path (see Load Paths in GNU Guile Reference Manual). For example, if your channel contains a file at my-packages/my-tools.scm that defines a Guile module, then the module will be available under the name (my-packages my-tools), and you will be able to use it like any other module (see Modules in GNU Guile Reference Manual).

4.7.4 Declaring Channel Dependencies

Channel authors may decide to augment a package collection provided by other channels. They can declare their channel to be dependent on other channels in a meta-data file .guix-channel, which is to be placed in the root of the channel repository.

The meta-data file should contain a simple S-expression like this:

(channel
 (version 0)
 (dependencies
  (channel
   (name some-collection)
   (url "https://example.org/first-collection.git")

   ;; The 'introduction' bit below is optional: you would
   ;; provide it for dependencies that can be authenticated.
   (introduction
    (channel-introduction
      (version 0)
      (commit "a8883b58dc82e167c96506cf05095f37c2c2c6cd")
      (signer "CABB A931 C0FF EEC6 900D  0CFB 090B 1199 3D9A EBB5"))))
  (channel
   (name some-other-collection)
   (url "https://example.org/second-collection.git")
   (branch "testing"))))

In the above example this channel is declared to depend on two other channels, which will both be fetched automatically. The modules provided by the channel will be compiled in an environment where the modules of all these declared channels are available.

For the sake of reliability and maintainability, you should avoid dependencies on channels that you don’t control, and you should aim to keep the number of dependencies to a minimum.

4.7.5 Package Modules in a Sub-directory

As a channel author, you may want to keep your channel modules in a sub-directory. If your modules are in the sub-directory guix, you must add a meta-data file .guix-channel that contains:

(channel
  (version 0)
  (directory "guix"))

4.7.6 Specifying Channel Authorizations

As we saw above, Guix ensures the source code it pulls from channels comes from authorized developers. As a channel author, you need to specify the list of authorized developers in the .guix-authorizations file in the channel’s Git repository. The authentication rule is simple: each commit must be signed by a key listed in the .guix-authorizations file of its parent commit(s)10 The .guix-authorizations file looks like this:

;; Example '.guix-authorizations' file.

(authorizations
 (version 0)               ;current file format version

 (("AD17 A21E F8AE D8F1 CC02  DBD9 F8AE D8F1 765C 61E3"
   (name "alice"))
  ("2A39 3FFF 68F4 EF7A 3D29  12AF 68F4 EF7A 22FB B2D5"
   (name "bob"))
  ("CABB A931 C0FF EEC6 900D  0CFB 090B 1199 3D9A EBB5"
   (name "charlie"))))

Each fingerprint is followed by optional key/value pairs, as in the example above. Currently these key/value pairs are ignored.

This authentication rule creates a chicken-and-egg issue: how do we authenticate the first commit? Related to that: how do we deal with channels whose repository history contains unsigned commits and lack .guix-authorizations? And how do we fork existing channels?

Channel introductions answer these questions by describing the first commit of a channel that should be authenticated. The first time a channel is fetched with guix pull or guix time-machine, the command looks up the introductory commit and verifies that it is signed by the specified OpenPGP key. From then on, it authenticates commits according to the rule above.

Additionally, your channel must provide all the OpenPGP keys that were ever mentioned in .guix-authorizations, stored as .key files, which can be either binary or “ASCII-armored”. By default, those .key files are searched for in the branch named keyring but you can specify a different branch name in .guix-channel like so:

(channel
  (version 0)
  (keyring-reference "my-keyring-branch"))

To summarize, as the author of a channel, there are three things you have to do to allow users to authenticate your code:

  1. Export the OpenPGP keys of past and present committers with gpg --export and store them in .key files, by default in a branch named keyring (we recommend making it an orphan branch).
  2. Introduce an initial .guix-authorizations in the channel’s repository. Do that in a signed commit (see Commit Access, for information on how to sign Git commits.)
  3. Advertise the channel introduction, for instance on your channel’s web page. The channel introduction, as we saw above, is the commit/key pair—i.e., the commit that introduced .guix-authorizations, and the fingerprint of the OpenPGP used to sign it.

Before pushing to your public Git repository, you can run guix git-authenticate to verify that you did sign all the commits you are about to push with an authorized key:

guix git authenticate commit signer

where commit and signer are your channel introduction. See Invoking guix git authenticate, for details.

Publishing a signed channel requires discipline: any mistake, such as an unsigned commit or a commit signed by an unauthorized key, will prevent users from pulling from your channel—well, that’s the whole point of authentication! Pay attention to merges in particular: merge commits are considered authentic if and only if they are signed by a key present in the .guix-authorizations file of both branches.

4.7.7 Primary URL

Channel authors can indicate the primary URL of their channel’s Git repository in the .guix-channel file, like so:

(channel
  (version 0)
  (url "https://example.org/guix.git"))

This allows guix pull to determine whether it is pulling code from a mirror of the channel; when that is the case, it warns the user that the mirror might be stale and displays the primary URL. That way, users cannot be tricked into fetching code from a stale mirror that does not receive security updates.

This feature only makes sense for authenticated repositories, such as the official guix channel, for which guix pull ensures the code it fetches is authentic.

4.7.8 Writing Channel News

Channel authors may occasionally want to communicate to their users information about important changes in the channel. You’d send them all an email, but that’s not convenient.

Instead, channels can provide a news file; when the channel users run guix pull, that news file is automatically read and guix pull --news can display the announcements that correspond to the new commits that have been pulled, if any.

To do that, channel authors must first declare the name of the news file in their .guix-channel file:

(channel
  (version 0)
  (news-file "etc/news.txt"))

The news file itself, etc/news.txt in this example, must look something like this:

(channel-news
  (version 0)
  (entry (tag "the-bug-fix")
         (title (en "Fixed terrible bug")
                (fr "Oh la la"))
         (body (en "@emph{Good news}!  It's fixed!")
               (eo "Certe ĝi pli bone funkcias nun!")))
  (entry (commit "bdcabe815cd28144a2d2b4bc3c5057b051fa9906")
         (title (en "Added a great package")
                (ca "Què vol dir guix?"))
         (body (en "Don't miss the @code{hello} package!"))))

While the news file is using the Scheme syntax, avoid naming it with a .scm extension or else it will get picked up when building the channel and yield an error since it is not a valid module. Alternatively, you can move the channel module to a subdirectory and store the news file in another directory.

The file consists of a list of news entries. Each entry is associated with a commit or tag: it describes changes made in this commit, possibly in preceding commits as well. Users see entries only the first time they obtain the commit the entry refers to.

The title field should be a one-line summary while body can be arbitrarily long, and both can contain Texinfo markup (see Overview in GNU Texinfo). Both the title and body are a list of language tag/message tuples, which allows guix pull to display news in the language that corresponds to the user’s locale.

If you want to translate news using a gettext-based workflow, you can extract translatable strings with xgettext (see xgettext Invocation in GNU Gettext Utilities). For example, assuming you write news entries in English first, the command below creates a PO file containing the strings to translate:

xgettext -o news.po -l scheme -ken etc/news.txt

To sum up, yes, you could use your channel as a blog. But beware, this is not quite what your users might expect.

4.7.9 Replicating Guix

The guix pull --list-generations output above shows precisely which commits were used to build this instance of Guix. We can thus replicate it, say, on another machine, by providing a channel specification in ~/.config/guix/channels.scm that is “pinned” to these commits:

;; Deploy specific commits of my channels of interest.
(list (channel
       (name 'guix)
       (url "https://git.savannah.gnu.org/git/guix.git")
       (commit "6298c3ffd9654d3231a6f25390b056483e8f407c"))
      (channel
       (name 'my-personal-packages)
       (url "https://example.org/personal-packages.git")
       (commit "dd3df5e2c8818760a8fc0bd699e55d3b69fef2bb")))

The guix describe --format=channels command can even generate this list of channels directly (see Invoking guix describe). The resulting file can be used with the -C options of guix pull (see Invoking guix pull) or guix time-machine (see Invoking guix time-machine).

At this point the two machines run the exact same Guix, with access to the exact same packages. The output of guix build gimp on one machine will be exactly the same, bit for bit, as the output of the same command on the other machine. It also means both machines have access to all the source code of Guix and, transitively, to all the source code of every package it defines.

This gives you super powers, allowing you to track the provenance of binary artifacts with very fine grain, and to reproduce software environments at will—some sort of “meta reproducibility” capabilities, if you will. See Inferiors, for another way to take advantage of these super powers.


Footnotes

(10)

Git commits form a directed acyclic graph (DAG). Each commit can have zero or more parents; “regular” commits have one parent and merge commits have two parent commits. Read Git for Computer Scientists for a great overview.


Next: , Previous: , Up: Package Management   [Contents][Index]