Subject: [bug#27155] [PATCH 0/2] Support service extensions on the "final"

From: Rutherther <[email-masked]>
Date: Fri, 18 Apr 2025 17:04:29 +0200

Hello Ludo,

I appreciate your answer. I am sorry for getting back after longer time,
I had to think about this more deeply, I was writing something the first
day it came but the answer didn't feel right.

Ludovic Courtès <[email-masked]> writes:

> Hello Rutherther,
>
> Rutherther <[email-masked]> skribis:
>
>> what's the state of this? Why has this been abandoned?
>
> It was abandoned first because there wasn’t high demand (did people
> learn to live with a limitation? or is it that that limitation is
> acceptable in practice?) and second because I had second thoughts.
>
> My main concern is that it could make service composition much harder to
> understand.  Currently, there’s a graph of services/service types where
> edges show what node influences each intermediate configuration value;
> you can follow the arrows and understand what originates where
> (demonstrated with <https://notabug.org/civodul/guix-explorer).
>
> With this extension, pretty much anything could happen.  The extra
> flexibility could be put to good use, but we should also pay attention
> to the cost and see if we can come up with less invasive alternatives.

We already have something like this in pam service, the transformer
field, I think that if other services started supporting that, it's
basically the same as making a generic interface like this, except
harder as each service has to do it on their own.

Yes, it drops the nice inspectionability, but even now it can be made
complicated depending on how the service's extension field sets up the
extend procedure.

>
>> For example, I would like to change the home mcron shepherd service so that it gets
>> a wayland display env var.
>
> I think it’s an example that could be solved at the Shepherd level, by
> attaching essentially a key/value store to each service (the mcron
> service would query the ‘wayland-display’ value of the wayland service.)

I think that anything we come up with can be solved at the service
level, but I think that is besides the point, the point being that this
is a generic interface to do that, without having to make complicated
support for everything in already existing services. The service-maker
can't think of everything the user might want, so they won't expose
every modification option under the sun.

>
>>> Right.  As discussed on IRC, one problem is ordering: if there are
>>> several users of this features for a given service, you can=E2=80=99t really
>>> tell what=E2=80=99s going to happen, unless the modifications happen to be
>>> commutable.
>>
>> As for ordering, since I was using NixOS, I know a way they solve issue
>> like this. Your system config there is composed of many options that
>> you set to values. One option can be set multiple times, and if that
>> happens, there are two possibilities - either both have same priority
>> and the type is composable, then both values are used and it is
>> composed with a function (ie. if you have lines type and you add
>> two values, it will get merged with \n). If it is not composable,
>> and error is thrown. If both have different priorities, the higher
>> priority is used.
>
> Interesting.
>
> Note that I was using NixOS too (but long ago), and the “ambient
> authority” in the NixOS module system is one thing I definitely wanted
> to avoid.  By “ambient authority” I mean that any module can change any
> option of the global system config; there’s no way to track which module
> does what, nor whether an option that is set is used at all.

I definitely agree, and it's one of the reasons I switched to Guix
System. But I don't think what this is adding is so similar to that
though, because you still get that 'link' between the services that can
be seen by the user in an 'extension' graph (or something new like
finalizer graph)
Also with this finalizers, it's still not possible to read values of
services like NixOS allows.
In NixOS, one 'service', A, can change B, and B can change A, leaving
us with a mess, this is also something that will still not be allowed
if finalizers are used.

Let me sketch few things I now lack in Guix System, all solvable by
this, or on per-service basis:

- Modifying shepherd services
  - Auto start disable
  - New env vars
    - Ie. allowing programs to use GUI with DISPLAY
  - Run as different user
    - Security or convenience
    - But this one suffers from another issue, where the user is
      actually decided by the forkexec, so this one is more involved, it's
      not trivial even with this change. So we will need shepherd support
- Modifying users
  - Add a group to a user
    - To share a common socket file between two services
- Modifying existing pam rules

The reason I would be in favor of this generic solution, rather than
'local' ones is that I don't see any disadvantages applying only to the
generic one, but see the massive advantage of not needing to solve this
on each individual service by defining interfaces for it.

Apart from those use cases, one I am missing the most is the possibility
to extend the least authority wrappers, but this one suffers from
similar issue as running services as different user. I am not sure how
to well go about that, we will probably still need something specific
for shepherd for that. It's the main reason I am not thinking about
migrating my server from NixOS to Guix System. NixOS uses systemd
hardening much more... And thanks to the fact that any service can
change any other option, it's possible to combine services like that,
ie. share a socket through shared tmp folder, while the real filesystem
stays hidden.
(not saying I would go and migrate right away
after this issue is somehow solved, I will have to write a lot of
services myself...)

>
> Anyway, I’m glad you’re looking into this with a fresh mind.  Hopefully
> we can revisit it and find an option that brings flexibility without
> chaos.  :-)
>
> Thanks,
> Ludo’.

Best regards,
Ruther