[PATCH 0/5] Record operating system provenance info

DoneSubmitted by Ludovic Courtès.
2 participants
  • Ludovic Courtès
  • zimoun
Ludovic Courtès wrote on 30 Nov 2019 23:30
(address . guix-patches@gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
Hello Guix!
This patch series allows ‘guix system’ to record provenance infoabout a system in its output: the system itself (e.g.,/run/current-system) now contains three more files: “channels.scm”,“configuration.scm”, and “provenance” (a summary of the first twofiles.)
That means you can always inspect a deployed system to find its own“source”. In some cases, you can even run something like:
guix time-machine \ -C /var/guix/profiles/system-N-link/channels.scm -- \ system reconfigure \ /var/guix/profiles/system-N-link/configuration.scm
to rebuild generation N of your system. Pretty cool, no? :-)
Otherwise you can simply run:
guix system describe
to see where your OS comes from.
Provenance tracking is implemented as a service. The service isautomatically added by ‘guix system init’, ‘reconfigure’, and by‘guix deploy’. For other commands, one can pass ‘--save-provenance’to turn it on.
This was long overdue!
This has interesting implications on trustworthiness: you candistribute a VM/Docker image with provenance info, and anyonecan reproduce it and ensure they obtain the same bits (well, ideally,because I guess a few steps may still not be bit-reproducible).
Ludovic Courtès (5): services: Add 'provenance-service-type'. guix system: Use 'provenance-service-type', add "--save-provenance". machine: Add provenance tracking to each machine operating system. guix system: "list-generations" displays provenance info. guix system: Add "describe" action.
doc/guix.texi | 109 +++++++++++++++++++++++++++++++++++++--- gnu/machine.scm | 7 ++- gnu/services.scm | 87 ++++++++++++++++++++++++++++++++ gnu/system.scm | 10 ++++ guix/scripts/pull.scm | 1 + guix/scripts/system.scm | 107 ++++++++++++++++++++++++++++++++------- 6 files changed, 293 insertions(+), 28 deletions(-)
-- 2.24.0
Ludovic Courtès wrote on 30 Nov 2019 23:31
[PATCH 1/5] services: Add 'provenance-service-type'.
(address . 38441@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
* gnu/services.scm (object->pretty-string)(channel->code, channel->sexp, provenance-file)(provenance-entry): New procedures.(provenance-service-type): New variable.* gnu/system.scm (operating-system-with-provenance): New procedure.* doc/guix.texi (Service Reference): Document 'provenance-service-type'.--- doc/guix.texi | 44 ++++++++++++++++++++++++ gnu/services.scm | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ gnu/system.scm | 10 ++++++ 3 files changed, 141 insertions(+)
Toggle diff (204 lines)diff --git a/doc/guix.texi b/doc/guix.texiindex 661aa41785..fd40b6535f 100644--- a/doc/guix.texi+++ b/doc/guix.texi@@ -26970,6 +26970,50 @@ programs under @file{/run/current-system/profile}. Other services can extend it by passing it lists of packages to add to the system profile. @end defvr +@cindex provenance tracking, of the operating system+@defvr {Scheme Variable} provenance-service-type+This is the type of the service that records @dfn{provenance meta-data}+in the system itself. It creates several files under+@file{/run/current-system}:++@table @file+@item channels.scm+This is a ``channel file'' that can be passed to @command{guix pull -C}+or @command{guix time-machine -C}, and which describes the channels used+to build the system, if that information was available+(@pxref{Channels}).++@item configuration.scm+This is the file that was passed as the value for this+@code{provenance-service-type} service. By default, @command{guix+system reconfigure} automatically passes the OS configuration file it+received on the command line.++@item provenance+This contains the same information as the two other files but in a+format that is more readily processable.+@end table++In general, these two pieces of information (channels and configuration+file) are enough to reproduce the operating system ``from source''.++@quotation Caveats+This information is necessary to rebuild your operating system, but it+is not always sufficient. In particular, @file{configuration.scm}+itself is insufficient if it is not self-contained---if it refers to+external Guile modules or to extra files. If you want+@file{configuration.scm} to be self-contained, we recommend that modules+or files it refers to be part of a channel.++Besides, provenance meta-data is ``silent'' in the sense that it does+not change the bits contained in your system, @emph{except for the+meta-data bits themselves}. Two different OS configurations or sets of+channels can lead to the same system, bit-for-bit; when+@code{provenance-service-type} is used, these two systems will have+different meta-data and thus different store file names, which makes+comparison less trivial.+@end quotation+@end defvr @node Shepherd Services @subsection Shepherd Servicesdiff --git a/gnu/services.scm b/gnu/services.scmindex 394470ba7d..e7a3a95e43 100644--- a/gnu/services.scm+++ b/gnu/services.scm@@ -25,6 +25,8 @@ #:use-module (guix profiles) #:use-module (guix discovery) #:use-module (guix combinators)+ #:use-module (guix channels)+ #:use-module (guix describe) #:use-module (guix sets) #:use-module (guix ui) #:use-module ((guix utils) #:select (source-properties->location))@@ -39,6 +41,7 @@ #:use-module (srfi srfi-35) #:use-module (ice-9 vlist) #:use-module (ice-9 match)+ #:autoload (ice-9 pretty-print) (pretty-print) #:export (service-extension service-extension? service-extension-target@@ -82,6 +85,7 @@ ambiguous-target-service-error-target-type system-service-type+ provenance-service-type boot-service-type cleanup-service-type activation-service-type@@ -370,6 +374,89 @@ by the initrd once the root file system is mounted."))) ;; The service that produces the boot script. (service boot-service-type #t)) + +;;;+;;; Provenance tracking.+;;;++(define (object->pretty-string obj)+ "Like 'object->string', but using 'pretty-print'."+ (call-with-output-string+ (lambda (port)+ (pretty-print obj port))))++(define (channel->code channel)+ "Return code to build CHANNEL, ready to be dropped in a 'channels.scm'+file."+ `(channel (name ',(channel-name channel))+ (url ,(channel-url channel))+ (branch ,(channel-branch channel))+ (commit ,(channel-commit channel))))++(define (channel->sexp channel)+ "Return an sexp describing CHANNEL. The sexp is _not_ code and is meant to+be parsed by tools; it's potentially more future-proof than code."+ `(channel (name ,(channel-name channel))+ (url ,(channel-url channel))+ (branch ,(channel-branch channel))+ (commit ,(channel-commit channel))))++(define (provenance-file channels config-file)+ "Return a 'provenance' file describing CHANNELS, a list of channels, and+CONFIG-FILE, which can be either #f or a <local-file> containing the OS+configuration being used."+ (scheme-file "provenance"+ #~(provenance+ (version 0)+ (channels #+@(if channels+ (map channel->sexp channels)+ '()))+ (configuration-file #+config-file))))++(define (provenance-entry config-file)+ "Return system entries describing the operating system provenance: the+channels in use and CONFIG-FILE, if it is true."+ (define profile+ (current-profile))++ (define channels+ (and=> profile profile-channels))++ (mbegin %store-monad+ (let ((config-file (cond ((string? config-file)+ (local-file config-file "configuration.scm"))+ ((not config-file)+ #f)+ (else+ config-file))))+ (return `(("provenance" ,(provenance-file channels config-file))+ ,@(if channels+ `(("channels.scm"+ ,(plain-file "channels.scm"+ (object->pretty-string+ `(list+ ,@(map channel->code channels))))))+ '())+ ,@(if config-file+ `(("configuration.scm" ,config-file))+ '()))))))++(define provenance-service-type+ (service-type (name 'provenance)+ (extensions+ (list (service-extension system-service-type+ provenance-entry)))+ (default-value #f) ;the OS config file+ (description+ "Store provenance information about the system in the system+itself: the channels used when building the system, and its configuration+file, when available.")))++ +;;;+;;; Cleanup.+;;;+ (define (cleanup-gexp _) "Return a gexp to clean up /tmp and similar places upon boot." (with-imported-modules '((guix build utils))diff --git a/gnu/system.scm b/gnu/system.scmindex a353b1a5c8..525b1a171d 100644--- a/gnu/system.scm+++ b/gnu/system.scm@@ -110,6 +110,7 @@ system-linux-image-file-name operating-system-with-gc-roots+ operating-system-with-provenance boot-parameters boot-parameters?@@ -539,6 +540,15 @@ bookkeeping." gc-root-service-type roots) (operating-system-user-services os))))) +(define* (operating-system-with-provenance os #:optional config-file)+ "Return a variant of OS that stores its own provenance information,+including CONFIG-FILE, if available. This is achieved by adding an instance+of PROVENANCE-SERVICE-TYPE to its services."+ (operating-system+ (inherit os)+ (services (cons (service provenance-service-type config-file)+ (operating-system-user-services os)))))+ ;;; ;;; /etc.-- 2.24.0
Ludovic Courtès wrote on 30 Nov 2019 23:31
[PATCH 2/5] guix system: Use 'provenance-service-type', add "--save-provenance".
(address . 38441@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
* guix/scripts/system.scm (show-help, %options): Add "--save-provenance".(process-action): Define 'save-provenance?' and 'transform'; call'transform' on the OS.* doc/guix.texi (Invoking guix system): Document it under 'reconfigure'.(Service Reference): Mention that 'provenance-service-type' isautomatically added by 'reconfigure' & 'init'.--- doc/guix.texi | 61 +++++++++++++++++++++++++++++++++++------ guix/scripts/system.scm | 47 ++++++++++++++++++++----------- 2 files changed, 84 insertions(+), 24 deletions(-)
Toggle diff (187 lines)diff --git a/doc/guix.texi b/doc/guix.texiindex fd40b6535f..3dc2fd1318 100644--- a/doc/guix.texi+++ b/doc/guix.texi@@ -25839,6 +25839,15 @@ switch to it@footnote{This action (and the related actions @code{switch-generation} and @code{roll-back}) are usable only on systems already running Guix System.}. +@quotation Note+@c The paragraph below refers to the problem discussed at+@c <https://lists.gnu.org/archive/html/guix-devel/2014-08/msg00057.html>.+It is highly recommended to run @command{guix pull} once before you run+@command{guix system reconfigure} for the first time (@pxref{Invoking+guix pull}). Failing to do that you would see an older version of Guix+once @command{reconfigure} has completed.+@end quotation+ This effects all the configuration specified in @var{file}: user accounts, system services, global package list, setuid programs, etc. The command starts system services specified in @var{file} that are not@@ -25857,14 +25866,27 @@ It also adds a bootloader menu entry for the new OS configuration, entries for older configurations to a submenu, allowing you to choose an older system generation at boot time should you need it. -@quotation Note-@c The paragraph below refers to the problem discussed at-@c <https://lists.gnu.org/archive/html/guix-devel/2014-08/msg00057.html>.-It is highly recommended to run @command{guix pull} once before you run-@command{guix system reconfigure} for the first time (@pxref{Invoking-guix pull}). Failing to do that you would see an older version of Guix-once @command{reconfigure} has completed.-@end quotation+@cindex provenance tracking, of the operating system+Upon completion, the new system is deployed under+@file{/run/current-system}. This directory contains @dfn{provenance+meta-data}: the list of channels in use (@pxref{Channels}) and+@var{file} itself, when available. This information is useful should+you later want to inspect how this particular generation was built.++In fact, assuming @var{file} is self-contained, you can later rebuild+generation @var{n} of your operating system with:++@example+guix time-machine \+ -C /var/guix/profiles/system-@var{n}-link/channels.scm -- \+ system reconfigure \+ /var/guix/profiles/system-@var{n}-link/configuration.scm+@end example++You can think of it as some sort of built-in version control! Your+system is not just a binary artifact: @emph{it carries its own source}.+@xref{Service Reference, @code{provenance-service-type}}, for more+information on provenance tracking. @item switch-generation @cindex generations@@ -26126,6 +26148,25 @@ This works as per @command{guix build} (@pxref{Invoking guix build}). Return the derivation file name of the given operating system without building anything. +@cindex provenance tracking, of the operating system+@item --save-provenance+As discussed above, @command{guix system init} and @command{guix system+reconfigure} always save provenance information @i{via} a dedicated+service (@pxref{Service Reference, @code{provenance-service-type}}).+However, other commands don't do that by default. If you wish to, say,+create a virtual machine image that contains provenance information, you+can run:++@example+guix system vm-image --save-provenance config.scm+@end example++That way, the resulting image will effectively ``embed its own source''+in the form of meta-data in @file{/run/current-system}. With that+information, one can rebuild the image to make sure it really contains+what it pretends to contain; or they could use that to derive a variant+of the image.+ @item --file-system-type=@var{type} @itemx -t @var{type} For the @code{disk-image} action, create a file system of the given@@ -27013,6 +27054,10 @@ channels can lead to the same system, bit-for-bit; when different meta-data and thus different store file names, which makes comparison less trivial. @end quotation++This service is automatically added to your operating system+configuration when you use @command{guix system reconfigure} or+@command{guix system init}. @end defvr @node Shepherd Servicesdiff --git a/guix/scripts/system.scm b/guix/scripts/system.scmindex e49c9d36b9..b22945658e 100644--- a/guix/scripts/system.scm+++ b/guix/scripts/system.scm@@ -722,7 +722,9 @@ and TARGET arguments." (return (primitive-eval (lowered-gexp-sexp lowered)))))) (define* (perform-action action os- #:key skip-safety-checks?+ #:key+ save-provenance?+ skip-safety-checks? install-bootloader? dry-run? derivations-only? use-substitutes? bootloader-target target@@ -917,16 +919,18 @@ Some ACTIONS support additional ARGS.\n")) --image-size=SIZE for 'vm-image', produce an image of SIZE")) (display (G_ " --no-bootloader for 'init', do not install a bootloader"))+ (display (G_ "+ --save-provenance save provenance information")) (display (G_ " --share=SPEC for 'vm', share host file system according to SPEC"))+ (display (G_ "+ --expose=SPEC for 'vm', expose host file system according to SPEC")) (display (G_ " -N, --network for 'container', allow containers to access the network")) (display (G_ " -r, --root=FILE for 'vm', 'vm-image', 'disk-image', 'container', and 'build', make FILE a symlink to the result, and register it as a garbage collector root"))- (display (G_ "- --expose=SPEC for 'vm', expose host file system according to SPEC")) (display (G_ " --full-boot for 'vm', make a full boot sequence")) (display (G_ "@@ -977,6 +981,9 @@ Some ACTIONS support additional ARGS.\n")) (option '("full-boot") #f #f (lambda (opt name arg result) (alist-cons 'full-boot? #t result)))+ (option '("save-provenance") #f #f+ (lambda (opt name arg result)+ (alist-cons 'save-provenance? #t result))) (option '("skip-checks") #f #f (lambda (opt name arg result) (alist-cons 'skip-safety-checks? #t result)))@@ -1040,24 +1047,32 @@ resulting from command-line parsing." file-or-exp)) obj) + (define save-provenance?+ (or (assoc-ref opts 'save-provenance?)+ (memq action '(init reconfigure))))+ (let* ((file (match args (() #f) ((x . _) x))) (expr (assoc-ref opts 'expression)) (system (assoc-ref opts 'system))- (os (ensure-operating-system- (or file expr)- (cond- ((and expr file)- (leave- (G_ "both file and expression cannot be specified~%")))- (expr- (read/eval expr))- (file- (load* file %user-module- #:on-error (assoc-ref opts 'on-error)))- (else- (leave (G_ "no configuration specified~%"))))))+ (transform (if save-provenance?+ (cut operating-system-with-provenance <> file)+ identity))+ (os (transform+ (ensure-operating-system+ (or file expr)+ (cond+ ((and expr file)+ (leave+ (G_ "both file and expression cannot be specified~%")))+ (expr+ (read/eval expr))+ (file+ (load* file %user-module+ #:on-error (assoc-ref opts 'on-error)))+ (else+ (leave (G_ "no configuration specified~%"))))))) (dry? (assoc-ref opts 'dry-run?)) (bootloader? (assoc-ref opts 'install-bootloader?))-- 2.24.0
Ludovic Courtès wrote on 30 Nov 2019 23:31
[PATCH 3/5] machine: Add provenance tracking to each machine operating system.
(address . 38441@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
* gnu/machine.scm (<machine>): Rename accessor to'%machine-operating-system'.(machine-operating-system): New procedure.* doc/guix.texi (Service Reference): Mention it.--- doc/guix.texi | 4 ++-- gnu/machine.scm | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-)
Toggle diff (39 lines)diff --git a/doc/guix.texi b/doc/guix.texiindex 3dc2fd1318..198792c54a 100644--- a/doc/guix.texi+++ b/doc/guix.texi@@ -27056,8 +27056,8 @@ comparison less trivial. @end quotation This service is automatically added to your operating system-configuration when you use @command{guix system reconfigure} or-@command{guix system init}.+configuration when you use @command{guix system reconfigure},+@command{guix system init}, or @command{guix deploy}. @end defvr @node Shepherd Servicesdiff --git a/gnu/machine.scm b/gnu/machine.scmindex 05b03b21d4..b342fe2144 100644--- a/gnu/machine.scm+++ b/gnu/machine.scm@@ -93,11 +93,16 @@ make-machine machine? this-machine- (operating-system machine-operating-system) ; <operating-system>+ (operating-system %machine-operating-system); <operating-system> (environment machine-environment) ; symbol (configuration machine-configuration ; configuration object (default #f))) ; specific to environment +(define (machine-operating-system machine)+ "Return the operating system of MACHINE."+ (operating-system-with-provenance+ (%machine-operating-system machine)))+ (define (machine-display-name machine) "Return the host-name identifying MACHINE." (operating-system-host-name (machine-operating-system machine)))-- 2.24.0
Ludovic Courtès wrote on 30 Nov 2019 23:31
[PATCH 4/5] guix system: "list-generations" displays provenance info.
(address . 38441@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
* guix/scripts/pull.scm (channel-commit-hyperlink): Export.* guix/scripts/system.scm (display-system-generation)[display-channel]: New procedure.Read the "provenance" file of GENERATION and display channel info andthe configuration file name when available.--- guix/scripts/pull.scm | 1 + guix/scripts/system.scm | 49 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-)
Toggle diff (101 lines)diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scmindex 19410ad141..04cc51829d 100644--- a/guix/scripts/pull.scm+++ b/guix/scripts/pull.scm@@ -60,6 +60,7 @@ #:use-module (ice-9 format) #:export (display-profile-content channel-list+ channel-commit-hyperlink with-git-error-handling guix-pull)) diff --git a/guix/scripts/system.scm b/guix/scripts/system.scmindex b22945658e..0ddb40a03c 100644--- a/guix/scripts/system.scm+++ b/guix/scripts/system.scm@@ -36,9 +36,11 @@ #:use-module (guix records) #:use-module (guix profiles) #:use-module (guix scripts)+ #:use-module (guix channels) #:use-module (guix scripts build) #:autoload (guix scripts package) (delete-generations delete-matching-generations)+ #:autoload (guix scripts pull) (channel-commit-hyperlink) #:use-module (guix graph) #:use-module (guix scripts graph) #:use-module (guix scripts system reconfigure)@@ -456,9 +458,30 @@ list of services." ;;; Generations. ;;; +(define (sexp->channel sexp)+ "Return the channel corresponding to SEXP, an sexp as found in the+\"provenance\" file produced by 'provenance-service-type'."+ (match sexp+ (('channel ('name name)+ ('url url)+ ('branch branch)+ ('commit commit))+ (channel (name name) (url url)+ (branch branch) (commit commit)))))+ (define* (display-system-generation number #:optional (profile %system-profile)) "Display a summary of system generation NUMBER in a human-readable format."+ (define (display-channel channel)+ (format #t " ~a:~%" (channel-name channel))+ (format #t (G_ " repository URL: ~a~%") (channel-url channel))+ (when (channel-branch channel)+ (format #t (G_ " branch: ~a~%") (channel-branch channel)))+ (format #t (G_ " commit: ~a~%")+ (if (supports-hyperlinks?)+ (channel-commit-hyperlink channel)+ (channel-commit channel))))+ (unless (zero? number) (let* ((generation (generation-file-name profile number)) (params (read-boot-parameters-file generation))@@ -468,7 +491,13 @@ list of services." (root-device (if (bytevector? root) (uuid->string root) root))- (kernel (boot-parameters-kernel params)))+ (kernel (boot-parameters-kernel params))+ (provenance (catch 'system-error+ (lambda ()+ (call-with-input-file+ (string-append generation "/provenance")+ read))+ (const #f)))) (display-generation profile number) (format #t (G_ " file name: ~a~%") generation) (format #t (G_ " canonical file name: ~a~%") (readlink* generation))@@ -495,7 +524,23 @@ list of services." (else root-device))) - (format #t (G_ " kernel: ~a~%") kernel))))+ (format #t (G_ " kernel: ~a~%") kernel)++ (match provenance+ (#f #t)+ (('provenance ('version 0)+ ('channels channels ...)+ ('configuration-file config-file))+ (unless (null? channels)+ ;; TRANSLATORS: Here "channel" is the same terminology as used in+ ;; "guix describe" and "guix pull --channels".+ (format #t (G_ " channels:~%"))+ (for-each display-channel (map sexp->channel channels)))+ (when config-file+ (format #t (G_ " configuration file: ~a~%")+ (if (supports-hyperlinks?)+ (file-hyperlink config-file)+ config-file)))))))) (define* (list-generations pattern #:optional (profile %system-profile)) "Display in a human-readable format all the system generations matching-- 2.24.0
Ludovic Courtès wrote on 30 Nov 2019 23:31
[PATCH 5/5] guix system: Add "describe" action.
(address . 38441@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
* guix/scripts/system.scm (show-help): Add "describe".(process-command): Handle it.(guix-system): Likewise.* doc/guix.texi (Invoking guix system): Document it.--- doc/guix.texi | 4 ++++ guix/scripts/system.scm | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-)
Toggle diff (53 lines)diff --git a/doc/guix.texi b/doc/guix.texiindex 198792c54a..cb4b0b45e7 100644--- a/doc/guix.texi+++ b/doc/guix.texi@@ -26240,6 +26240,10 @@ bootloader boot menu: @table @code +@item describe+Describe the current system generation: its file name, the kernel and+bootloader used, etc., as well as provenance information when available.+ @item list-generations List a summary of each generation of the operating system available on disk, in a human-readable way. This is similar to thediff --git a/guix/scripts/system.scm b/guix/scripts/system.scmindex 0ddb40a03c..ccff68f1ab 100644--- a/guix/scripts/system.scm+++ b/guix/scripts/system.scm@@ -921,6 +921,8 @@ Some ACTIONS support additional ARGS.\n")) reconfigure switch to a new operating system configuration\n")) (display (G_ "\ roll-back switch to the previous operating system configuration\n"))+ (display (G_ "\+ describe describe the current system\n")) (display (G_ "\ list-generations list the system generations\n")) (display (G_ "\@@ -1187,6 +1189,12 @@ argument list and OPTS is the option alist." ((pattern) pattern) (x (leave (G_ "wrong number of arguments~%")))))) (list-generations pattern)))+ ((describe)+ (match (generation-number %system-profile)+ (0+ (error (G_ "no system generation, nothing to describe~%")))+ (generation+ (display-system-generation generation)))) ((search) (apply (resolve-subcommand "search") args)) ;; The following commands need to use the store, but they do not need an@@ -1226,7 +1234,8 @@ argument list and OPTS is the option alist." (case action ((build container vm vm-image disk-image reconfigure init extension-graph shepherd-graph- list-generations delete-generations roll-back+ list-generations describe+ delete-generations roll-back switch-generation search docker-image) (alist-cons 'action action result)) (else (leave (G_ "~a: unknown action~%") action))))))-- 2.24.0
zimoun wrote on 2 Dec 2019 13:12
Re: [bug#38441] [PATCH 0/5] Record operating system provenance info
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 38441@debbugs.gnu.org)
Hi Ludo,
On Sat, 30 Nov 2019 at 23:31, Ludovic Courtès <ludo@gnu.org> wrote:
Toggle quote (2 lines)> Thoughts?
Really cool!
This is a killer feature IMHO compared to the Dockerfile approach. Letspread the world. ;-)

Ludovic Courtès wrote on 7 Dec 2019 01:03
(address . 38441-done@debbugs.gnu.org)
Ludovic Courtès <ludo@gnu.org> skribis:
Toggle quote (6 lines)> services: Add 'provenance-service-type'.> guix system: Use 'provenance-service-type', add "--save-provenance".> machine: Add provenance tracking to each machine operating system.> guix system: "list-generations" displays provenance info.> guix system: Add "describe" action.
zimoun <zimon.toutoune@gmail.com> skribis:
Toggle quote (5 lines)> Really cool!>> This is a killer feature IMHO compared to the Dockerfile approach. Let> spread the world. ;-)
Glad you like it, thanks for your feedback! :-)
Your comment

This issue is archived.

To comment on this conversation send email to 38441@debbugs.gnu.org