texlive is actually substitutable

  • Open
  • quality assurance status badge
Details
6 participants
  • Bengt Richter
  • Leo Famulari
  • Liliana Marie Prikler
  • Ludovic Courtès
  • Maxim Cournoyer
  • Morgan Arnold
Owner
unassigned
Submitted by
Ludovic Courtès
Severity
important

Debbugs page

L
L
Ludovic Courtès wrote on 29 May 2020 08:15
texlive-texmf is actually subtitutable
(address . bug-guix@gnu.org)
878sha3h7n.fsf@inria.fr
Strangely, ‘texlive-texmf’ (the big one) is substitutable:

Toggle snippet (21 lines)
$ guix describe
Generacio 145 May 25 2020 00:37:58 (nuna)
guix 9744cc7
repository URL: https://git.savannah.gnu.org/git/guix.git
branch: master
commit: 9744cc7b4636fafb772c94adb8f05961b5b39f16
$ guix environment --ad-hoc texlive -- texdoc biblatex
2.6 MB will be downloaded:
/gnu/store/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6
downloading from https://ci.guix.gnu.org/nar/lzip/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6 ...
subversion-1.10.6 2.5MiB 7.2MiB/s 00:00 [##################] 100.0%

La jena derivo estos konstruata:
/gnu/store/55yx02hr0dz47px1aj0j14xll3bsrmml-texlive-texmf-20190410.drv
2,845.8 MB will be downloaded:
/gnu/store/nm6w84c9zj3yiylal3dk1sqzxq11sjzw-texlive-20190410-texmf.tar.xz
/gnu/store/xpkl70g3bls935h1zdlq7sn2j6rccp3k-texlive-20190410
downloading from https://ci.guix.gnu.org/nar/lzip/z4xvgiliw5baf1pr4z03c7n2hw3bm5x5-texlive-texmf-20190410 ...
texlive-texmf-20190410 2.61GiB

The info suggests it won’t be substituted, but it’s eventually
substituted. I wonder why, because the .drv has:

("allowSubstitutes","0")

and the daemon has:

bool substitutesAllowed(const Derivation & drv)
{
return get(drv.env, "allowSubstitutes", "1") == "1";
}

and:

if (settings.useSubstitutes && substitutesAllowed(drv))
foreach (PathSet::iterator, i, invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));

Thoughts?

Ludo’.
B
B
Bengt Richter wrote on 29 May 2020 21:06
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 41602@debbugs.gnu.org)
20200530040609.GA2810@LionPure
On +2020-05-29 17:15:40 +0200, Ludovic Courtès wrote:
Toggle quote (44 lines)
> Strangely, ‘texlive-texmf’ (the big one) is substitutable:
>
> --8<---------------cut here---------------start------------->8---
> $ guix describe
> Generacio 145 May 25 2020 00:37:58 (nuna)
> guix 9744cc7
> repository URL: https://git.savannah.gnu.org/git/guix.git
> branch: master
> commit: 9744cc7b4636fafb772c94adb8f05961b5b39f16
> $ guix environment --ad-hoc texlive -- texdoc biblatex
> 2.6 MB will be downloaded:
> /gnu/store/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6
> downloading from https://ci.guix.gnu.org/nar/lzip/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6 ...
> subversion-1.10.6 2.5MiB 7.2MiB/s 00:00 [##################] 100.0%
>
> La jena derivo estos konstruata:
> /gnu/store/55yx02hr0dz47px1aj0j14xll3bsrmml-texlive-texmf-20190410.drv
> 2,845.8 MB will be downloaded:
> /gnu/store/nm6w84c9zj3yiylal3dk1sqzxq11sjzw-texlive-20190410-texmf.tar.xz
> /gnu/store/xpkl70g3bls935h1zdlq7sn2j6rccp3k-texlive-20190410
> downloading from https://ci.guix.gnu.org/nar/lzip/z4xvgiliw5baf1pr4z03c7n2hw3bm5x5-texlive-texmf-20190410 ...
> texlive-texmf-20190410 2.61GiB
> --8<---------------cut here---------------end--------------->8---
>
> The info suggests it won’t be substituted, but it’s eventually
> substituted. I wonder why, because the .drv has:
>
> ("allowSubstitutes","0")
>
> and the daemon has:
>
> bool substitutesAllowed(const Derivation & drv)
> {
> return get(drv.env, "allowSubstitutes", "1") == "1";
> }
>
> and:
>
> if (settings.useSubstitutes && substitutesAllowed(drv))
> foreach (PathSet::iterator, i, invalidOutputs)
> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>
> Thoughts?

This is the kind of "wonder why" that makes me wonder about trojan horse bug fixes
as described in [1], which is a really interesting and scary read, especially since [1]
could very conceivably be an example of what it itself is talking about (though they
don't sound malicious, so I can hope trusting okular to display it was not giving
them a pdf or image parser to exploit with malice).

Anyway, please note that the "pdf" file starts with these lines:

Toggle snippet (5 lines)
# I'm a shell script :-) so please make me executable!
# No shebang but I work equally well with Bash, Dash and Zsh
# The script embeds link-grammar, a x86-64 ELF so it requires to be run on a x86-64 linux system

What looks like the beginning of a normal pdf file starts at line 30 counting from 1 as first line.
okular will display the original as if it were pdf (bug??) though "file" just sees it as "data."

Trim off the first 29 lines and file sees it as pdf, and pdfinfo will find its way too.

Idk, you might want at least to cut out the first 29 lines before looking at it with e.g. okular,
(which I trustingly used to open the file): note that okular got past the 29-line script part, (which
is a bit promiscuous for my taste), and displayed the pdf.

It was really interesting, esp the sections around

Toggle snippet (5 lines)
3
Deniable Backdoors Using Compiler Bugs
by Scott Bauer, Pascal Cuoq, and John Regehr

Maybe you can view it in a sandbox :) But don't blame me if you don't.
YOU WERE WARNED.

So read it -- and wonder what might come with a mysterious substitute ;-P


Toggle quote (6 lines)
>
> Ludo’.
>
>
>

--
Regards,
Bengt Richter
L
L
Ludovic Courtès wrote on 30 May 2020 07:07
(name . Leo Famulari)(address . leo@famulari.name)(address . 41602@debbugs.gnu.org)
87sgfhtt1f.fsf@gnu.org
Hi,

Leo Famulari <leo@famulari.name> skribis:

Toggle quote (24 lines)
> On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
>> The info suggests it won’t be substituted, but it’s eventually
>> substituted. I wonder why, because the .drv has:
>>
>> ("allowSubstitutes","0")
>>
>> and the daemon has:
>>
>> bool substitutesAllowed(const Derivation & drv)
>> {
>> return get(drv.env, "allowSubstitutes", "1") == "1";
>> }
>>
>> and:
>>
>> if (settings.useSubstitutes && substitutesAllowed(drv))
>> foreach (PathSet::iterator, i, invalidOutputs)
>> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>>
>> Thoughts?
>
> I wonder if the content-addressed fallbacks take a different code path
> that doesn't respect "allowSubstitutes"?

It does, but this texlive-texmf.drv is not a fixed-output derivation.

Ludo’.
L
L
Leo Famulari wrote on 30 May 2020 10:10
(no subject)
(address . control@debbugs.gnu.org)
20200530171007.GA25305@jasmine.lan
severity 41602 important
M
M
Maxim Cournoyer wrote on 2 Apr 2024 19:08
control message for bug #41602
(address . control@debbugs.gnu.org)
878r1vw637.fsf@gmail.com
retitle 41602 texlive is actually substitutable
quit
M
M
Maxim Cournoyer wrote on 2 Apr 2024 19:09
Re: bug#41602: texlive-texmf is actually subtitutable
(name . Ludovic Courtès)(address . ludo@gnu.org)
874jcjw621.fsf@gmail.com
Hello,

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (30 lines)
> Hi,
>
> Leo Famulari <leo@famulari.name> skribis:
>
>> On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
>>> The info suggests it won’t be substituted, but it’s eventually
>>> substituted. I wonder why, because the .drv has:
>>>
>>> ("allowSubstitutes","0")
>>>
>>> and the daemon has:
>>>
>>> bool substitutesAllowed(const Derivation & drv)
>>> {
>>> return get(drv.env, "allowSubstitutes", "1") == "1";
>>> }
>>>
>>> and:
>>>
>>> if (settings.useSubstitutes && substitutesAllowed(drv))
>>> foreach (PathSet::iterator, i, invalidOutputs)
>>> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>>>
>>> Thoughts?
>>
>> I wonder if the content-addressed fallbacks take a different code path
>> that doesn't respect "allowSubstitutes"?
>
> It does, but this texlive-texmf.drv is not a fixed-output derivation.

I just verified; this still happens:

Toggle snippet (19 lines)
$ guix build texlive -n
substitute: mise à jour des substituts depuis « https://ci.guix.gnu.org »... 100.0 %
La dérivation suivante serait compilée :
/gnu/store/ym96pipknrh6khzc3ws8ychiy6224y61-texlivetexmf-20230313.drv
3 880,6 Mo seraient téléchargés :
/gnu/store/rzczwmmkvpkahy0mgpahav0yx37ci61b-texlive-20230313-texmf.tar.xz
/gnu/store/bcc5071mvprhp4yj1jimlhyyi499d2ba-texlivebin-20230313
/gnu/store/bd4mzanvv7q2plm2b6zld8cz3fy0x34a-texlive-20230313
maxim@hurd ~/src/guix [env]$ guix build /gnu/store/bd4mzanvv7q2plm2b6zld8cz3fy0x34a-texlive-20230313
substitute: mise à jour des substituts depuis « https://ci.guix.gnu.org »... 100.0 %
substitution de /gnu/store/bcc5071mvprhp4yj1jimlhyyi499d2ba-texlivebin-20230313...
téléchargement depuis https://ci.guix.gnu.org/nar/lzip/bcc5071mvprhp4yj1jimlhyyi499d2ba-texlivebin-20230313...
texlivebin-20230313 13.5MiB 527KiB/s 00:26 ▕██████████████████▏ 100.0%

substitution de /gnu/store/4hr3i6p7g2miwhy9gn64mxp1haix36dq-texlivetexmf-20230313...
téléchargement depuis https://ci.guix.gnu.org/nar/lzip/4hr3i6p7g2miwhy9gn64mxp1haix36dq-texlivetexmf-20230313...
texlivetexmf-20230313 3.63GiB 360KiB/s 00:17 ▕ ▏ 0.2%^C

--
Thanks,
Maxim
M
M
Maxim Cournoyer wrote on 18 Feb 08:08 -0800
Re: bug#41602: texlive is actually substitutable
(name . Ludovic Courtès)(address . ludo@gnu.org)
874j0rxmjs.fsf_-_@gmail.com
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:

Toggle quote (29 lines)
> Hello,
>
> Ludovic Courtès <ludo@gnu.org> writes:
>
>> Hi,
>>
>> Leo Famulari <leo@famulari.name> skribis:
>>
>>> On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
>>>> The info suggests it won’t be substituted, but it’s eventually
>>>> substituted. I wonder why, because the .drv has:
>>>>
>>>> ("allowSubstitutes","0")
>>>>
>>>> and the daemon has:
>>>>
>>>> bool substitutesAllowed(const Derivation & drv)
>>>> {
>>>> return get(drv.env, "allowSubstitutes", "1") == "1";
>>>> }
>>>>
>>>> and:
>>>>
>>>> if (settings.useSubstitutes && substitutesAllowed(drv))
>>>> foreach (PathSet::iterator, i, invalidOutputs)
>>>> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>>>>
>>>> Thoughts?

It's odd, when using --dry-run, it seems the expected situation would
happen:

Toggle snippet (9 lines)
$ guix build --no-grafts -n texlive
guix build --no-grafts -n texlive
La dérivation suivante serait compilée :
/gnu/store/v10c5wzji81pkwq2fhj123gw3d8il0ic-texlivetexmf-20240312.drv
4 270,0 Mo seraient téléchargés :
/gnu/store/pb6z5d5fx6s13cjzmvlw7dykpafp9x97-texlive-20240312-texmf.tar.xz
/gnu/store/0gkx9q1kyys8cis93cw9qhlzyx584dr6-texlive-20240312

Only the private texlivetexmf is marked as non-substitutable, so the
above looks correct (though we see the intention of preserving bandwidth
wouldn't be achieved, given the source is as large as the final
package).

When removing the --dry-run, what happens though is that the output of
the texlivetexmf package, which is marked as non-substitutable, is downloaded:

Toggle snippet (11 lines)
$ guix build --no-grafts texlive
La dérivation suivante sera compilée :
/gnu/store/v10c5wzji81pkwq2fhj123gw3d8il0ic-texlivetexmf-20240312.drv
4 270,0 Mo seront téléchargés :
/gnu/store/pb6z5d5fx6s13cjzmvlw7dykpafp9x97-texlive-20240312-texmf.tar.xz
/gnu/store/0gkx9q1kyys8cis93cw9qhlzyx584dr6-texlive-20240312
substitution de /gnu/store/b5sn5ha961hab37r7vl5p2n6sf46x582-texlivetexmf-20240312...
téléchargement depuis https://bordeaux.guix.gnu.org/nar/lzip/b5sn5ha961hab37r7vl5p2n6sf46x582-texlivetexmf-20240312...
texlivetexmf-20240312 3.95GiB 2.8MiB/s 00:06 ▕ ▏ 0.4% C-c C-c^C

I've had some success as stopping in the daemon right before the downlod
starts, with this sequence:

Start the locally built guix-daemon in gdb, with a command like:

Toggle snippet (3 lines)
sudo -E ./pre-inst-env gdb --args ./guix-daemon --debug --build-users-group=guixbuild --max-silent-time 3600 --timeout 86400 --log-compression none --discover=no --substitute-urls='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org'

Then, to be able to reach the point in the execution where the downloads
are about to start, we need to break in the first fork (but not the 2nd,
which is the guile substituter), like follows at the GDB prompt:

Toggle snippet (41 lines)
set follow-fork-mode child

# To break inside the first child process
break LocalStore::querySubstitutablePathInfos

run

## from a terminal, 'guix build texlive' to hit breakpoint

delete 1

# avoid entering the guile substituter fork
set follow-fork-mode parent

break LocalStore::buildPaths

continue

-> should break in
Thread 2.1 "guix-daemon" hit Breakpoint 2.1, nix::LocalStore::buildPaths
(this=0x51f4d0, drvPaths=std::set with 1 element = {...},
buildMode=nix::bmNormal) at nix/libstore/build.cc:3627

Thread 2.1 "guix-daemon" hit Breakpoint 2.1, nix::LocalStore::buildPaths (this=0x51f4d0, drvPaths=std::set with 1 element = {...}, buildMode=nix::bmNormal) at nix/libstore/build.cc:3627
3627 {
(gdb) bt
#0 nix::LocalStore::buildPaths (this=0x51f4d0, drvPaths=std::set with 1 element = {...}, buildMode=nix::bmNormal) at nix/libstore/build.cc:3627
#1 0x00000000004253b6 in performOp (from=..., to=..., op=<optimized out>, clientVersion=356, trusted=false) at nix/nix-daemon/nix-daemon.cc:481
#2 processConnection (trusted=<optimized out>, userId=<optimized out>) at nix/nix-daemon/nix-daemon.cc:841
#3 0x000000000042805f in operator() (__closure=0x4e8f50) at nix/nix-daemon/nix-daemon.cc:1003
#4 0x00000000004280ac in std::__invoke_impl<void, acceptConnection(int)::<lambda()>&> (__f=...) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/invoke.h:61
#5 std::__invoke_r<void, acceptConnection(int)::<lambda()>&> (__fn=...) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/invoke.h:154
#6 std::_Function_handler<void(), acceptConnection(int)::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/std_function.h:290
#7 0x0000000000495dbb in std::function<void()>::operator() (this=0x7fffffffbb00) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/std_function.h:590
#8 nix::startProcess (fun=..., dieWithParent=dieWithParent@entry=false, errorPrefix="unexpected build daemon error: ", runExitHandlers=runExitHandlers@entry=true) at nix/libutil/util.cc:1025
#9 0x00000000004237c2 in acceptConnection (fdSocket=<optimized out>) at nix/nix-daemon/nix-daemon.cc:977
#10 daemonLoop (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1055
#11 0x00000000004241b9 in run (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1064
#12 0x0000000000420635 in main (argc=<optimized out>, argv=<optimized out>) at nix/nix-daemon/guix-daemon.cc:569

I haven't investigated where in this execution path the
substitutesAllowed procedure is called, if at all, but this is what I
will try to understand next.

--
Thanks,
Maxim
M
M
Maxim Cournoyer wrote on 18 Feb 19:14 -0800
(name . Ludovic Courtès)(address . ludo@gnu.org)
87zfiiwrra.fsf@gmail.com
Hello,

Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:

[...]

Toggle quote (4 lines)
> I haven't investigated where in this execution path the
> substitutesAllowed procedure is called, if at all, but this is what I
> will try to understand next.

This gets called, in the case of texlive, only for the texlive .drv
itself, not for its referenced .drvs, which the daemon attempts to
substitute without checking for their allowSubstitutes variable first,
as this gdb screen grab attempts to show:

Toggle snippet (19 lines)
2: *goal = {<std::enable_shared_from_this<nix::Goal>> = {_M_weak_this = std::weak_ptr<nix::Goal> (use count 2, weak count 3) = {get() = 0x5e29a0}}, _vptr.Goal = 0x4c75e0 <vtable for nix::SubstitutionGoal+16>, worker = @0x7fffffff85c0, waitees = std::set with 0 elements, waiters = std::__cxx11::list = {[0] = std::weak_ptr<nix::Goal> (use count 1, weak count 5) = {get() = 0x5b08f0}}, nrFailed = 0, nrNoSubstituters = 0, nrIncompleteClosure = 0, name = "substitution of `/gnu/store/b5sn5ha961hab37r7vl5p2n6sf46x582-texlivetexmf-20240312'", exitCode = nix::Goal::ecBusy}

(gdb) where
#0 nix::Worker::run (this=0x7fffffff85c0, _topGoals=std::set with 1 element = {...}) at nix/libstore/build.cc:3448
#1 0x00000000004659c9 in nix::LocalStore::buildPaths (this=0x55b4d0, drvPaths=std::set with 1 element = {...}, buildMode=nix::bmNormal) at nix/libstore/build.cc:3642
#2 0x000000000040ad6c in performOp (trusted=false, clientVersion=356, from=..., to=..., op=9) at nix/nix-daemon/nix-daemon.cc:481
#3 0x000000000040e01b in processConnection (trusted=false, userId=1000) at nix/nix-daemon/nix-daemon.cc:841
#4 0x000000000040e754 in operator() (__closure=0x524f50) at nix/nix-daemon/nix-daemon.cc:1003
#5 0x0000000000410fda in std::__invoke_impl<void, acceptConnection(int)::<lambda()>&>(std::__invoke_other, struct {...} &) (__f=...) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/invoke.h:61
#6 0x000000000040f718 in std::__invoke_r<void, acceptConnection(int)::<lambda()>&>(struct {...} &) (__fn=...) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/invoke.h:154
#7 0x000000000040f5db in std::_Function_handler<void(), acceptConnection(int)::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/std_function.h:290
#8 0x0000000000441f00 in std::function<void()>::operator() (this=0x7fffffffaf10) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/std_function.h:590
#9 0x00000000004ab2ef in nix::startProcess (fun=..., dieWithParent=false, errorPrefix="unexpected build daemon error: ", runExitHandlers=true) at nix/libutil/util.cc:1025
#10 0x000000000040ed6b in acceptConnection (fdSocket=3) at nix/nix-daemon/nix-daemon.cc:977
#11 0x000000000040f40e in daemonLoop (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1055
#12 0x000000000040f4bd in run (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1064
#13 0x000000000041a262 in main (argc=12, argv=0x7fffffffc208) at nix/nix-daemon/guix-daemon.cc:569

But perhaps it is futile that the *client* should enforce this. If we
do not want to distribute something in binary form, we shouldn't bake a
.nar for it and make it available in the first place, as pointed by
Emily in #nix-dev:nixos.org (on their Matrix server).

I'll investigate this idea next.

--
Thanks,
Maxim
L
L
Ludovic Courtès wrote on 21 Feb 03:09 -0800
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
87cyfba719.fsf@gnu.org
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:

Toggle quote (5 lines)
> But perhaps it is futile that the *client* should enforce this. If we
> do not want to distribute something in binary form, we shouldn't bake a
> .nar for it and make it available in the first place, as pointed by
> Emily in #nix-dev:nixos.org (on their Matrix server).

Agreed, probably something to fix in ‘guix publish’ & co.

Thanks for addressing this longstanding issue!

Ludo’.
M
M
Morgan Arnold wrote on 24 Feb 07:17 -0800
(name . Ludovic Courtès)(address . ludo@gnu.org)
EU_AVZ76UKFsrLyYSjpm16v1Ivms-4Vxp6PFqmjSP95tJ3xHa1ol4wyf7BukG0ELgazJOEG7_FO_pm44dRAxAFA3T4GYLkjUqNKBOF8JuxA=@proton.me
Hi Maxim, Ludo,

I did a bit of work on this, and I think that there might be a problem with limiting the distribution of derivation outputs. The problem is with encoding that a derivation's outputs are non-distributable. Because `#:distributable?` should presumably be an argument to `derivation`, and because `guix publish` does not have access to the underlying derivation object, it seems necessary to store distributability information somehow, like is done with "allowSubstitutes" currently. The problem, then, is that when `guix publish` manages a request, what it has to work with is the path of the output being requested *not the derivation from which it was built*. I could be wrong, but I assume that there is no way to compute, from an output path, the path of the derivation which produced it.

It then seems impossible to effectively prevent distribution! I don't see a sane way to attach metadata to every single object in the store (all of which may, to the best of my understanding, be published), and even if we include information about distributability in the derivation file, there is no way for `guix publish` to locate that derivation file, since it is supplied with the path of the derivation output, not the derivation which produced it.

I would appreciate thoughts on this, but I am not sure if I see how `#:distributable?` is a workable solution. I agree that enforcing non-distribution on the client side is inelegant, but I don't see a way to enforce it server-side.

Best,

Morgan
L
L
Ludovic Courtès wrote on 24 Feb 09:32 -0800
(name . Morgan Arnold)(address . morgan.arnold@proton.me)
87tt8js0yn.fsf@gnu.org
Hi!

I would rely on #:substitutable? instead of relying on a new
#:distributable? flag that the daemon doesn’t know about anyway.

With that in mind, ‘guix publish’ in ‘render-nar’ could have an extra
check in addition to ‘valid-path?’: ‘substitutable-path?’.

One way to implement ‘substitutable-path?’ is by (1) getting a “deriver”
of the store item with ‘valid-derivers’, and (2) checking whether the
returned derivation (if any) passes ‘substitutable-derivation?’.

One downside is that this extra check could be a bit costly, but it’s a
cost one would only pay when not using ‘--cache’.

Does that make sense?

HTH,
Ludo’.
M
M
Morgan Arnold wrote on 24 Feb 11:03 -0800
[PATCH v1] Prevent publication of non-substitutable derivation outputs
(address . 41602@debbugs.gnu.org)(name . Morgan Arnold)(address . morgan.arnold@proton.me)
ac57764fcf349604aa9520cb793d3e869c4de242.1740423677.git.morgan.arnold@proton.me
This commit prevents Guix substitute servers from distributing binaries which are marked non-substitutable. This prevents substitute servers from accidentally committing copyright violations by distributing binaries which are non-substitutable for copyright reasons.

Change-Id: Iaca81f5bdb430a12a3ad41e9b83e0bcc535af607
---
guix/scripts/publish.scm | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

Toggle diff (33 lines)
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index a000c559a7..fc8b007d36 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -61,6 +61,7 @@ (define-module (guix scripts publish)
#:use-module (guix cache)
#:use-module (guix ui)
#:use-module (guix scripts)
+ #:use-module (guix derivations)
#:use-module ((guix utils)
#:select (with-atomic-file-output compressed-file?))
#:use-module ((guix build utils)
@@ -696,11 +697,14 @@ (define* (bake-narinfo+nar cache item
(define* (render-nar store request store-item
#:key (compression %no-compression))
"Render archive of the store path corresponding to STORE-ITEM."
- (let ((store-path (string-append %store-directory "/" store-item)))
+ (let* ((store-path (string-append %store-directory "/" store-item))
+ (substitutable-store-item? (every substitutable-derivation?
+ (map read-derivation-from-file
+ (valid-derivers store-path)))))
;; The ISO-8859-1 charset *must* be used otherwise HTTP clients will
;; interpret the byte stream as UTF-8 and arbitrarily change invalid byte
;; sequences.
- (if (valid-path? store store-path)
+ (if ((and substitutable-store-item? valid-path?) store store-path)
(values `((content-type . (application/x-nix-archive
(charset . "ISO-8859-1")))
(x-nar-compression . ,compression))

base-commit: 23b068c036223e70bdea9d7d579850a1cffc02a7
--
2.47.1
M
M
Morgan Arnold wrote on 24 Feb 11:10 -0800
[PATCH v2] Prevent publication of non-substitutable derivation outputs
(address . 41602@debbugs.gnu.org)(name . Morgan Arnold)(address . morgan.arnold@proton.me)
bc5ddaa3c82e818bc947a173ca3a64fa8d3dd4b6.1740424114.git.morgan.arnold@proton.me
This commit prevents Guix substitute servers from distributing binaries which are marked non-substitutable. This prevents substitute servers from accidentally committing copyright violations by distributing binaries which are non-substitutable for copyright reasons.

Change-Id: Iaca81f5bdb430a12a3ad41e9b83e0bcc535af607
---
guix/scripts/publish.scm | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

Toggle diff (34 lines)
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index a000c559a7..f736cf3068 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -61,6 +61,7 @@ (define-module (guix scripts publish)
#:use-module (guix cache)
#:use-module (guix ui)
#:use-module (guix scripts)
+ #:use-module (guix derivations)
#:use-module ((guix utils)
#:select (with-atomic-file-output compressed-file?))
#:use-module ((guix build utils)
@@ -696,11 +697,15 @@ (define* (bake-narinfo+nar cache item
(define* (render-nar store request store-item
#:key (compression %no-compression))
"Render archive of the store path corresponding to STORE-ITEM."
- (let ((store-path (string-append %store-directory "/" store-item)))
+ (let* ((store-path (string-append %store-directory "/" store-item))
+ (substitutable-store-item? (every substitutable-derivation?
+ (map read-derivation-from-file
+ (valid-derivers store
+ store-path)))))
;; The ISO-8859-1 charset *must* be used otherwise HTTP clients will
;; interpret the byte stream as UTF-8 and arbitrarily change invalid byte
;; sequences.
- (if (valid-path? store store-path)
+ (if ((and substitutable-store-item? valid-path?) store store-path)
(values `((content-type . (application/x-nix-archive
(charset . "ISO-8859-1")))
(x-nar-compression . ,compression))

base-commit: 23b068c036223e70bdea9d7d579850a1cffc02a7
--
2.47.1
M
M
Morgan Arnold wrote on 24 Feb 11:13 -0800
texlive is actually substitutable
(name . 41602@debbugs.gnu.org)(address . 41602@debbugs.gnu.org)
gy8O6t_G2lOYgafb4lLIX7zS7_P2SzwecZopSC-UYLoKexr54c61z-i9vnH6jUVfzrqTO4YveNeC8jUWua0RkJsywl2xGN8ARYpSlPiYGD0=@proton.me
Hey Ludo, Maxim,

Sorry about the double-email. I messed up the first patch by mistake. The fix actually ends up being quite simple! I didn't know about `valid-derivers`, so thanks to Ludo for that.

This patch should fix the issue by restricting substitutions on the server side instead of the client side. The bug in the daemon may remain, but this should at least ensure correct functionality. Besides, it seems that we are in agreement that substitutability isn't something that should really be enforced by the client anyway.

Best,

Morgan
L
L
Liliana Marie Prikler wrote on 5 Mar 11:59 -0800
Re: [PATCH v2] Prevent publication of non-substitutable derivation outputs
337b88a4d49a4749fc1718ca5a300912007a4ecd.camel@gmail.com
Am Montag, dem 24.02.2025 um 19:10 +0000 schrieb Morgan Arnold:
Toggle quote (46 lines)
> This commit prevents Guix substitute servers from distributing
> binaries which are marked non-substitutable. This prevents substitute
> servers from accidentally committing copyright violations by
> distributing binaries which are non-substitutable for copyright
> reasons.
>
> Change-Id: Iaca81f5bdb430a12a3ad41e9b83e0bcc535af607
> ---
>  guix/scripts/publish.scm | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
> index a000c559a7..f736cf3068 100644
> --- a/guix/scripts/publish.scm
> +++ b/guix/scripts/publish.scm
> @@ -61,6 +61,7 @@ (define-module (guix scripts publish)
>    #:use-module (guix cache)
>    #:use-module (guix ui)
>    #:use-module (guix scripts)
> +  #:use-module (guix derivations)
>    #:use-module ((guix utils)
>                  #:select (with-atomic-file-output compressed-file?))
>    #:use-module ((guix build utils)
> @@ -696,11 +697,15 @@ (define* (bake-narinfo+nar cache item
>  (define* (render-nar store request store-item
>                       #:key (compression %no-compression))
>    "Render archive of the store path corresponding to STORE-ITEM."
> -  (let ((store-path (string-append %store-directory "/" store-
> item)))
> +  (let* ((store-path (string-append %store-directory "/" store-
> item))
> +         (substitutable-store-item? (every substitutable-derivation?
> +                                           (map read-derivation-
> from-file
> +                                                (valid-derivers
> store
> +                                                               
> store-path)))))
>      ;; The ISO-8859-1 charset *must* be used otherwise HTTP clients
> will
>      ;; interpret the byte stream as UTF-8 and arbitrarily change
> invalid byte
>      ;; sequences.
> -    (if (valid-path? store store-path)
> +    (if ((and substitutable-store-item? valid-path?) store store-
> path)
This should probably be
(and substitutable-store-item? (valid-path? store store-path))

Cheers
M
M
Morgan Arnold wrote on 6 Mar 02:16 -0800
[PATCH v3] Prevent publication of non-substitutable derivation outputs
(address . 41602@debbugs.gnu.org)(name . Morgan Arnold)(address . morgan.arnold@proton.me)
0de73c8665feeccb57acfa1986c18041d709ef6b.1741256083.git.morgan.arnold@proton.me
This commit prevents Guix substitute servers from distributing binaries which are marked non-substitutable. This prevents substitute servers from accidentally committing copyright violations by distributing binaries which are non-substitutable for copyright reasons.

Change-Id: Iaca81f5bdb430a12a3ad41e9b83e0bcc535af607
---
guix/scripts/publish.scm | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

Toggle diff (34 lines)
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 6f993ef0d6..4650e4ef3a 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -61,6 +61,7 @@ (define-module (guix scripts publish)
#:use-module (guix cache)
#:use-module (guix ui)
#:use-module (guix scripts)
+ #:use-module (guix derivations)
#:use-module ((guix utils)
#:select (with-atomic-file-output compressed-file?))
#:use-module ((guix build utils)
@@ -693,11 +694,15 @@ (define* (bake-narinfo+nar cache item
(define* (render-nar store request store-item
#:key (compression %no-compression))
"Render archive of the store path corresponding to STORE-ITEM."
- (let ((store-path (string-append %store-directory "/" store-item)))
+ (let* ((store-path (string-append %store-directory "/" store-item))
+ (substitutable-store-item? (every substitutable-derivation?
+ (map read-derivation-from-file
+ (valid-derivers store
+ store-path)))))
;; The ISO-8859-1 charset *must* be used otherwise HTTP clients will
;; interpret the byte stream as UTF-8 and arbitrarily change invalid byte
;; sequences.
- (if (valid-path? store store-path)
+ (if (and substitutable-store-item? (valid-path? store store-path))
(values `((content-type . (application/x-nix-archive
(charset . "ISO-8859-1")))
(x-nar-compression . ,compression))

base-commit: 19c656e3cad3a4f1e3338a955a1af57e363545df
--
2.47.1
M
M
Morgan Arnold wrote on 6 Mar 02:20 -0800
Re: [PATCH v2] Prevent publication of non-substitutable derivation outputs
(name . Liliana Marie Prikler)(address . liliana.prikler@gmail.com)(address . 41602@debbugs.gnu.org)
b-oN757RNwQ-wjFsR4aTuiU7kG4glTs7G8EwfiVeIXXT0BpAz1iNxpR9WJSl81aD90bNoAfxKeGf4tqPQTjrQkfdpPTszzRk4imTnl0T0w4=@proton.me
Hi Liliana,

Thanks! What a dumb mistake on my part. I tried to test the changes on my machine, but `guix publish` seems to just crash. I reverted my changes to double-check, and the version in `master` also crashes on my machine, so I'm afraid that I wasn't able to test the changes. I've sent a new version.

Best,

Morgan
?
Your comment

Commenting via the web interface is currently disabled.

To comment on this conversation send an email to 41602@patchwise.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 41602
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch