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

From: Rutherther <[email-masked]>
Date: Wed, 23 Apr 2025 18:40:08 +0200

Hello,

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

> Hi,
>
> Rutherther <[email-masked]> writes:
>
>>> 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,
>
> Well yes, though I think that the WAYLAND_DISPLAY value is fundamentally
> a run-time value, so it has to be solved though run-time mechanisms, in
> the Shepherd.

Could you clarify what run-time mechanism you have in mind here? I was
thinking in terms of how home-x11-display service does this, where you
need to go and set #:environment-variables in other services. Do you
have something more 'robust' in mind? I know that systemd has a function
to import environment `systemctl import-environment`, on the other hand
I don't really like that you just import the env vars everywhere instead
of having more controlled approach where the service says what to get
from where.

>
>>> 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.
>
> I agree, finalizers are still less expressive than the NixOS module
> system (which I think is good).  Yet, they can still do a lot and none
> of that can be inferred by looking at the extension graph.

I am not sure if my initial point got through, or not, so I will try to
rephrase, in case it already got through to you, and you just wanted to
extend on it, just ignore this:

Currently extensions can do transformations already, ie. the pam service
does that. This makes the extension graph less clear already in the same
way global finaliers would. But I would argue that the current approach
may be making the extension graph even less clear than a global
finalizers, because it's not known which services are extending the
'transformator' and which ones just the normal options. By having a more
global finalizer/transformer approach, it would be something that can be
marked in the graph, and we can distinguish between regular extensions
and finalizers. (of course only given that no one will make a
transformer-like extension support in their service, but at least in
Guix channel itself this could be made sure of, and I don't think anyone
would try that if there was a global approach)

>
>> 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
>
> Hmm.  I think it would be interesting to prototype services that make
> use of finalizers, to get a better idea of the possibilities it would
> open.
>

Yeah, that makes sense. Unfortunately I won't be able to get to this any
time soon I am afraid.

>> - Modifying existing pam rules
>
> This one is handled by the ‘transformer’ field, right? :-)

Yeah, my point was that this makes it more generic.

>
>> 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.
>
> Extend how?

For example to share files, like sockets, between two services.

In NixOS I have opensmtpd, and it contacts my sourcehut instance
by a socket when an e-mail is received. Socket needs to be shared
between those two. I do this in my config:
```
  systemd.services = {
    listssrht-ingress = {
      unitConfig.JoinsNamespaceOf = "opensmtpd.service";
    };
    todosrht-lmtp = {
      unitConfig.JoinsNamespaceOf = "opensmtpd.service";
    };
    opensmtpd = {
      # Needed for sharing the LMTP sockets with JoinsNamespaceOf=
      serviceConfig.PrivateTmp = true;
    };
  };
```
Which will make /tmp of the services shared (this can be made in
multiple ways of course, this is just one possibility, it could also be
a commonly mapped folder, no need for it to be /tmp), so that the socket
under /tmp is visible by both and they can communicate with each other.

Best regards,
Rutherther