Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
528a66807d | ||
|
|
88412da7a9 | ||
|
|
5a38f5bb8d | ||
|
|
4caa5bac31 | ||
|
|
fc16b50d37 | ||
|
|
6163dea01c | ||
|
|
03dbf4a74b | ||
|
|
ecff59d773 | ||
|
|
fc9f7096d3 | ||
|
|
aa9739caa7 | ||
|
|
47fb192fee | ||
|
|
3a8c42c1bf | ||
|
|
1bb22839d3 | ||
|
|
008f44beff | ||
|
|
49c27760c1 | ||
|
|
9638c4cd92 | ||
|
|
92cc6193e0 | ||
|
|
d227ad324e | ||
|
|
2310539e66 | ||
|
|
3d446ea37e | ||
|
|
4ef56601b5 | ||
|
|
779e795732 | ||
|
|
151cb75236 | ||
|
|
17df7e0e35 | ||
|
|
f67a99bdd3 | ||
|
|
d33062fd47 | ||
|
|
a2189bcb2e | ||
|
|
91f526e739 | ||
|
|
9c2d05997d | ||
|
|
83bba3f12c | ||
|
|
de6629754d | ||
|
|
faa50e15c8 | ||
|
|
18a50a1734 | ||
|
|
d27c247715 |
@@ -16,6 +16,8 @@ Checks:
|
||||
- -bugprone-unchecked-optional-access
|
||||
# many warnings, seems like a questionable lint
|
||||
- -bugprone-branch-clone
|
||||
# extremely noisy before clang 19: https://github.com/llvm/llvm-project/issues/93959
|
||||
- -bugprone-multi-level-implicit-pointer-conversion
|
||||
# all thrown exceptions must derive from std::exception
|
||||
- hicpp-exception-baseclass
|
||||
# capturing async lambdas are dangerous
|
||||
@@ -33,3 +35,4 @@ Checks:
|
||||
|
||||
CheckOptions:
|
||||
bugprone-reserved-identifier.AllowedIdentifiers: '__asan_default_options'
|
||||
bugprone-unused-return-value.AllowCastToVoid: true
|
||||
|
||||
@@ -1,4 +1,59 @@
|
||||
# Lix 2.91 "Dragon's Breath" (2024-08-12)
|
||||
# Lix 2.91.3 (2025-06-30)
|
||||
|
||||
## Fixes
|
||||
- Revert CVE-2025-52992 failed mitigation [fj#883](https://git.lix.systems/lix-project/lix/issues/883) [fj#887](https://git.lix.systems/lix-project/lix/issues/887) [cl/3420](https://gerrit.lix.systems/c/lix/+/3420) [cl/3524](https://gerrit.lix.systems/c/lix/+/3524) [cl/3523](https://gerrit.lix.systems/c/lix/+/3523) [cl/3522](https://gerrit.lix.systems/c/lix/+/3522)
|
||||
|
||||
Following the initial mitigation of **CVE-2025-52992** in `cl/3420`, we
|
||||
received reports of **unexpected deletion of in-use store paths**.
|
||||
|
||||
Upon investigation, we found that the patch did **not correctly cancel all
|
||||
automatic deleters**, resulting in potentially critical path loss during normal
|
||||
operation.
|
||||
|
||||
Given the severity and time-sensitive nature of the situation ([see incident
|
||||
report](https://lix.systems/blog/2025-06-27-lix-critical-bug/)), we evaluated
|
||||
possible options to repair the behavior safely. However, we concluded that a
|
||||
rushed fix would either:
|
||||
|
||||
* **Overdelete**, i.e. breaking running systems, or,
|
||||
* **Underdelete**, effectively **reopening CVE-2025-52992** while leaving
|
||||
orphaned paths behind.
|
||||
|
||||
As **CVE-2025-52992 has no known exploit vector**, and correctness is critical
|
||||
in the Lix project, we have **fully reverted the previous mitigations**.
|
||||
|
||||
Moving forward, the Lix team will rework this code path in a **long-term,
|
||||
correctness-first fix** on the main branch. We will explore backporting it to
|
||||
stable channels once its safety is assured.
|
||||
|
||||
We are deeply sorry for the stability incident and the Lix team remain
|
||||
available for assisting you in recovering your systems.
|
||||
|
||||
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||
- Fallback to safe temp dir when build-dir is unwritable [fj#876](https://git.lix.systems/lix-project/lix/issues/876) [cl/3502](https://gerrit.lix.systems/c/lix/+/3502)
|
||||
|
||||
Non-daemon builds started failing with a permission error after introducing the `build-dir` option:
|
||||
|
||||
```
|
||||
$ nix build --store ~/scratch nixpkgs#hello --rebuild
|
||||
error: creating directory '/nix/var/nix/builds/nix-build-hello-2.12.2.drv-0': Permission denied
|
||||
```
|
||||
|
||||
This happens because:
|
||||
|
||||
1. These builds are not run via the daemon, which owns `/nix/var/nix/builds`.
|
||||
2. The user lacks permissions for that path.
|
||||
|
||||
We considered making `build-dir` a store-level option and defaulting it to `<chroot-root>/nix/var/nix/builds` for chroot stores, but opted instead for a fallback: if the default fails, Nix now creates a safe build directory under `/tmp`.
|
||||
|
||||
To avoid CVE-2025-52991, the fallback uses an extra path component between `/tmp` and the build dir.
|
||||
|
||||
**Note**: this fallback clutters `/tmp` with build directories that are not cleaned up. To prevent this, explicitly set `build-dir` to a path managed by Lix, even for local workloads.
|
||||
|
||||
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||
|
||||
|
||||
# Lix 2.91.2 (2025-06-23)
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
+37
-38
@@ -62,38 +62,37 @@ let
|
||||
++ autoLayered
|
||||
++ extraPkgs;
|
||||
|
||||
users =
|
||||
{
|
||||
users = {
|
||||
|
||||
root = {
|
||||
uid = 0;
|
||||
shell = "${pkgs.bashInteractive}/bin/bash";
|
||||
home = "/root";
|
||||
gid = 0;
|
||||
groups = [ "root" ];
|
||||
description = "System administrator";
|
||||
};
|
||||
root = {
|
||||
uid = 0;
|
||||
shell = "${pkgs.bashInteractive}/bin/bash";
|
||||
home = "/root";
|
||||
gid = 0;
|
||||
groups = [ "root" ];
|
||||
description = "System administrator";
|
||||
};
|
||||
|
||||
nobody = {
|
||||
uid = 65534;
|
||||
shell = "${pkgs.shadow}/bin/nologin";
|
||||
home = "/var/empty";
|
||||
gid = 65534;
|
||||
groups = [ "nobody" ];
|
||||
description = "Unprivileged account (don't use!)";
|
||||
nobody = {
|
||||
uid = 65534;
|
||||
shell = "${pkgs.shadow}/bin/nologin";
|
||||
home = "/var/empty";
|
||||
gid = 65534;
|
||||
groups = [ "nobody" ];
|
||||
description = "Unprivileged account (don't use!)";
|
||||
};
|
||||
}
|
||||
// lib.listToAttrs (
|
||||
map (n: {
|
||||
name = "nixbld${toString n}";
|
||||
value = {
|
||||
uid = 30000 + n;
|
||||
gid = 30000;
|
||||
groups = [ "nixbld" ];
|
||||
description = "Nix build user ${toString n}";
|
||||
};
|
||||
}
|
||||
// lib.listToAttrs (
|
||||
map (n: {
|
||||
name = "nixbld${toString n}";
|
||||
value = {
|
||||
uid = 30000 + n;
|
||||
gid = 30000;
|
||||
groups = [ "nixbld" ];
|
||||
description = "Nix build user ${toString n}";
|
||||
};
|
||||
}) (lib.lists.range 1 32)
|
||||
);
|
||||
}) (lib.lists.range 1 32)
|
||||
);
|
||||
|
||||
groups = {
|
||||
root.gid = 0;
|
||||
@@ -193,13 +192,11 @@ let
|
||||
in
|
||||
''
|
||||
{
|
||||
${
|
||||
lib.concatStringsSep "\n" (
|
||||
builtins.map (output: ''
|
||||
${output} = { outPath = "${lib.getOutput output drv}"; };
|
||||
'') outputs
|
||||
)
|
||||
}
|
||||
${lib.concatStringsSep "\n" (
|
||||
builtins.map (output: ''
|
||||
${output} = { outPath = "${lib.getOutput output drv}"; };
|
||||
'') outputs
|
||||
)}
|
||||
outputs = [ ${lib.concatStringsSep " " (builtins.map (x: "\"${x}\"") outputs)} ];
|
||||
name = "${drv.name}";
|
||||
outPath = "${drv}";
|
||||
@@ -361,8 +358,10 @@ let
|
||||
"org.opencontainers.image.source" = "https://git.lix.systems/lix-project/lix";
|
||||
"org.opencontainers.image.vendor" = "Lix project";
|
||||
"org.opencontainers.image.version" = pkgs.nix.version;
|
||||
"org.opencontainers.image.description" = "Minimal Lix container image, with some batteries included.";
|
||||
} // lib.optionalAttrs (lixRevision != null) { "org.opencontainers.image.revision" = lixRevision; };
|
||||
"org.opencontainers.image.description" =
|
||||
"Minimal Lix container image, with some batteries included.";
|
||||
}
|
||||
// lib.optionalAttrs (lixRevision != null) { "org.opencontainers.image.revision" = lixRevision; };
|
||||
};
|
||||
|
||||
meta = {
|
||||
|
||||
Generated
+69
-10
@@ -16,6 +16,22 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1633514407,
|
||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix2container": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@@ -32,18 +48,44 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"nix_2_18": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"flake-compat"
|
||||
],
|
||||
"lowdown-src": "lowdown-src",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-regression": [
|
||||
"nixpkgs-regression"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1735651292,
|
||||
"narHash": "sha256-YLbzcBtYo1/FEzFsB3AnM16qFc6fWPMIoOuSoDwvg9g=",
|
||||
"lastModified": 1730375271,
|
||||
"narHash": "sha256-RrOFlDGmRXcVRV2p2HqHGqvzGNyWoD0Dado/BNlJ1SI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0da3c44a9460a26d2025ec3ed2ec60a895eb1114",
|
||||
"repo": "nix",
|
||||
"rev": "0f665ff6779454f2117dcc32e44380cda7f45523",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05-small",
|
||||
"ref": "2.18.9",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1705033721,
|
||||
"narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.05-small",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -64,14 +106,30 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1757198069,
|
||||
"narHash": "sha256-m3VUcOD4rTs8J7S+3dOjWMrAjw6RcITC3XYQ98zhEFs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0747026fc57ecb9c28901c7f7a2b5dc40e8af43c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05-small",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1721042469,
|
||||
"narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=",
|
||||
"lastModified": 1733318908,
|
||||
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "f451c19376071a90d8c58ab1a953c6e9840527fd",
|
||||
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -84,7 +142,8 @@
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nix2container": "nix2container",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nix_2_18": "nix_2_18",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-regression": "nixpkgs-regression",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,19 @@
|
||||
description = "Lix: A modern, delicious implementation of the Nix package manager";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05-small";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05-small";
|
||||
nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
||||
|
||||
# Required because Nix 2.18 is not in Nixpkgs ≥ 25.05 anymore.
|
||||
nix_2_18 = {
|
||||
url = "github:NixOS/nix/2.18.9";
|
||||
# NOTE(Raito): this is not possible because patches on libseccomp does not apply anymore on this Nix.
|
||||
# Let's keep the latest known nixpkgs useable with Nix 2.18 for our tests.
|
||||
# inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.nixpkgs-regression.follows = "nixpkgs-regression";
|
||||
inputs.flake-compat.follows = "flake-compat";
|
||||
};
|
||||
|
||||
pre-commit-hooks = {
|
||||
url = "github:cachix/git-hooks.nix";
|
||||
flake = false;
|
||||
@@ -25,6 +36,7 @@
|
||||
nixpkgs-regression,
|
||||
pre-commit-hooks,
|
||||
nix2container,
|
||||
nix_2_18,
|
||||
flake-compat,
|
||||
}:
|
||||
|
||||
@@ -161,6 +173,16 @@
|
||||
{
|
||||
nixStable = prev.nix;
|
||||
|
||||
nixVersions = prev.nixVersions // {
|
||||
nix_2_3 = prev.nixVersions.nix_2_3.overrideAttrs (old: {
|
||||
meta = old.meta // {
|
||||
knownVulnerabilities = [ ];
|
||||
};
|
||||
});
|
||||
# Nix 2.18 has been removed from Nixpkgs ≥ 25.05, so we need to reintroduce it ourselves for our tests.
|
||||
nix_2_18 = nix_2_18.outputs.packages.${currentStdenv.hostPlatform.system}.default;
|
||||
};
|
||||
|
||||
# Forward from the previous stage as we don’t want it to pick the lowdown override
|
||||
nixUnstable = prev.nixUnstable;
|
||||
|
||||
@@ -346,13 +368,16 @@
|
||||
in
|
||||
pkgs.symlinkJoin {
|
||||
name = "nixpkgs-lib-tests";
|
||||
paths =
|
||||
[ testWithNix ]
|
||||
# FIXME: This is disabled on darwin due to a nixpkgs bug https://github.com/NixOS/nixpkgs/issues/319147
|
||||
# After that is fixed, it should be restored to use lib/tests/release.nix as before, rather than this reimplementation.
|
||||
++ lib.optionals pkgs.stdenv.isLinux [
|
||||
(import (nixpkgs + "/pkgs/test/release") { inherit pkgs lib nix; })
|
||||
];
|
||||
paths = [
|
||||
testWithNix
|
||||
]
|
||||
# NOTE: nixpkgs 25.05 is being ... *creative*, and requires this dance to override
|
||||
# the evaluator used for the test. it will break again in the future, don't worry.
|
||||
++ lib.optionals pkgs.stdenv.isLinux [
|
||||
((pkgs.callPackage "${nixpkgs}/ci/eval" { inherit nix; }).attrpathsSuperset {
|
||||
evalSystem = system;
|
||||
})
|
||||
];
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -301,6 +301,11 @@ editline = dependency('libeditline', 'editline', version : '>=1.14', required :
|
||||
|
||||
lowdown = dependency('lowdown', version : '>=0.9.0', required : true, include_type : 'system')
|
||||
|
||||
# TODO(sterni): drop the corresponding #ifdef after NixOS 25.05 is EOL which still distributes lowdown < 1.4.0
|
||||
if lowdown.version().version_compare('>= 1.4.0')
|
||||
add_project_arguments('-DLOWDOWN_SEPARATE_TERM_OPTS', language: 'cpp')
|
||||
endif
|
||||
|
||||
# HACK(Qyriad): rapidcheck's pkg-config doesn't include the libs lol
|
||||
# Note: technically we 'check' for rapidcheck twice, for the internal-api-docs handling above,
|
||||
# but Meson will cache the result of the first one, and the required : arguments are different.
|
||||
@@ -475,6 +480,7 @@ add_project_arguments(
|
||||
# It would be nice for our headers to be idempotent instead.
|
||||
'-include', 'config.h',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wimplicit-fallthrough',
|
||||
'-Werror=switch',
|
||||
'-Werror=switch-enum',
|
||||
|
||||
+65
-67
@@ -179,12 +179,13 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
|
||||
VERSION_SUFFIX = versionSuffix;
|
||||
|
||||
outputs =
|
||||
[ "out" ]
|
||||
++ lib.optionals (!finalAttrs.dontBuild) [
|
||||
"dev"
|
||||
"doc"
|
||||
];
|
||||
outputs = [
|
||||
"out"
|
||||
]
|
||||
++ lib.optionals (!finalAttrs.dontBuild) [
|
||||
"dev"
|
||||
"doc"
|
||||
];
|
||||
|
||||
dontBuild = lintInsteadOfBuild;
|
||||
|
||||
@@ -220,67 +221,65 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
# We only include CMake so that Meson can locate toml11, which only ships CMake dependency metadata.
|
||||
dontUseCmakeConfigure = true;
|
||||
|
||||
nativeBuildInputs =
|
||||
[
|
||||
python3
|
||||
meson
|
||||
ninja
|
||||
cmake
|
||||
]
|
||||
++ [
|
||||
(lib.getBin lowdown-unsandboxed)
|
||||
mdbook
|
||||
mdbook-linkcheck
|
||||
]
|
||||
++ [
|
||||
pkg-config
|
||||
nativeBuildInputs = [
|
||||
python3
|
||||
meson
|
||||
ninja
|
||||
cmake
|
||||
]
|
||||
++ [
|
||||
(lib.getBin lowdown-unsandboxed)
|
||||
mdbook
|
||||
mdbook-linkcheck
|
||||
]
|
||||
++ [
|
||||
pkg-config
|
||||
|
||||
# Tests
|
||||
git
|
||||
mercurial
|
||||
jq
|
||||
lsof
|
||||
]
|
||||
++ lib.optional hostPlatform.isLinux util-linuxMinimal
|
||||
++ lib.optional (!officialRelease && buildUnreleasedNotes) build-release-notes
|
||||
++ lib.optional internalApiDocs doxygen
|
||||
++ lib.optionals lintInsteadOfBuild [
|
||||
# required for a wrapped clang-tidy
|
||||
llvmPackages.clang-tools
|
||||
# required for run-clang-tidy
|
||||
llvmPackages.clang-unwrapped
|
||||
];
|
||||
# Tests
|
||||
git
|
||||
mercurial
|
||||
jq
|
||||
lsof
|
||||
]
|
||||
++ lib.optional hostPlatform.isLinux util-linuxMinimal
|
||||
++ lib.optional (!officialRelease && buildUnreleasedNotes) build-release-notes
|
||||
++ lib.optional internalApiDocs doxygen
|
||||
++ lib.optionals lintInsteadOfBuild [
|
||||
# required for a wrapped clang-tidy
|
||||
llvmPackages.clang-tools
|
||||
# required for run-clang-tidy
|
||||
llvmPackages.clang-unwrapped
|
||||
];
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
curl
|
||||
bzip2
|
||||
xz
|
||||
brotli
|
||||
editline-lix
|
||||
openssl
|
||||
sqlite
|
||||
libarchive
|
||||
boost
|
||||
lowdown
|
||||
libsodium
|
||||
toml11
|
||||
lix-doc
|
||||
pegtl
|
||||
]
|
||||
++ lib.optionals hostPlatform.isLinux [
|
||||
libseccomp
|
||||
busybox-sandbox-shell
|
||||
passt-lix
|
||||
]
|
||||
++ lib.optional internalApiDocs rapidcheck
|
||||
++ lib.optional hostPlatform.isx86_64 libcpuid
|
||||
# There have been issues building these dependencies
|
||||
++ lib.optional (hostPlatform.canExecute buildPlatform) aws-sdk-cpp-nix
|
||||
++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs
|
||||
# I am so sorry. This is because checkInputs are required to pass
|
||||
# configure, but we don't actually want to *run* the checks here.
|
||||
++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs;
|
||||
buildInputs = [
|
||||
curl
|
||||
bzip2
|
||||
xz
|
||||
brotli
|
||||
editline-lix
|
||||
openssl
|
||||
sqlite
|
||||
libarchive
|
||||
boost
|
||||
lowdown
|
||||
libsodium
|
||||
toml11
|
||||
lix-doc
|
||||
pegtl
|
||||
]
|
||||
++ lib.optionals hostPlatform.isLinux [
|
||||
libseccomp
|
||||
busybox-sandbox-shell
|
||||
passt-lix
|
||||
]
|
||||
++ lib.optional internalApiDocs rapidcheck
|
||||
++ lib.optional hostPlatform.isx86_64 libcpuid
|
||||
# There have been issues building these dependencies
|
||||
++ lib.optional (hostPlatform.canExecute buildPlatform) aws-sdk-cpp-nix
|
||||
++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs
|
||||
# I am so sorry. This is because checkInputs are required to pass
|
||||
# configure, but we don't actually want to *run* the checks here.
|
||||
++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs;
|
||||
|
||||
checkInputs = [
|
||||
gtest
|
||||
@@ -427,7 +426,6 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
just,
|
||||
nixfmt-rfc-style,
|
||||
skopeo,
|
||||
xonsh,
|
||||
|
||||
# Lix specific packages
|
||||
pre-commit-checks,
|
||||
@@ -447,7 +445,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
p.requests
|
||||
p.xdg-base-dirs
|
||||
p.packaging
|
||||
(p.toPythonModule xonsh.passthru.unwrapped)
|
||||
p.xonsh
|
||||
]
|
||||
);
|
||||
pythonEnv = python3.withPackages pythonPackages;
|
||||
|
||||
+12
-13
@@ -35,19 +35,18 @@ perl.pkgs.toPerlModule (
|
||||
ninja
|
||||
];
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
nix
|
||||
curl
|
||||
bzip2
|
||||
xz
|
||||
perl
|
||||
boost
|
||||
perlPackages.DBI
|
||||
perlPackages.DBDSQLite
|
||||
]
|
||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
||||
++ lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security;
|
||||
buildInputs = [
|
||||
nix
|
||||
curl
|
||||
bzip2
|
||||
xz
|
||||
perl
|
||||
boost
|
||||
perlPackages.DBI
|
||||
perlPackages.DBDSQLite
|
||||
]
|
||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
||||
++ lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security;
|
||||
|
||||
# Nixpkgs' Meson hook likes to set this to "plain".
|
||||
mesonBuildType = "debugoptimized";
|
||||
|
||||
+1
-4
@@ -19,10 +19,7 @@ endif
|
||||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
# Really version 5.8.0, but Perl's version string is of the form
|
||||
# "This is perl 5, version 38, subversion 2", for 5.38.2, so as far
|
||||
# as Meson is concerned, the version of Perl we need is 8 or greater.
|
||||
perl = find_program('perl', version : '>=8')
|
||||
perl = find_program('perl')
|
||||
|
||||
# "compiler to convert Perl XS code into C code"
|
||||
xsubpp = find_program('xsubpp')
|
||||
|
||||
+17
-2
@@ -11,13 +11,28 @@ namespace nix {
|
||||
std::string renderMarkdownToTerminal(std::string_view markdown)
|
||||
{
|
||||
int windowWidth = getWindowSize().second;
|
||||
size_t lowdown_cols = std::max(windowWidth - 5, 60);
|
||||
|
||||
struct lowdown_opts opts {
|
||||
struct lowdown_opts opts{
|
||||
.type = LOWDOWN_TERM,
|
||||
#ifdef LOWDOWN_SEPARATE_TERM_OPTS
|
||||
.term =
|
||||
{
|
||||
.cols = lowdown_cols,
|
||||
.width = 0,
|
||||
.hmargin = 0,
|
||||
.hpadding = 4,
|
||||
.vmargin = 0,
|
||||
.centre = 0,
|
||||
},
|
||||
// maxdepth needs to be part of the ifdefs to match declaration order
|
||||
.maxdepth = 20,
|
||||
.cols = (size_t) std::max(windowWidth - 5, 60),
|
||||
#else
|
||||
.maxdepth = 20,
|
||||
.cols = lowdown_cols,
|
||||
.hmargin = 0,
|
||||
.vmargin = 0,
|
||||
#endif /* LOWDOWN_SEPARATE_TERM_OPTS */
|
||||
.feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES,
|
||||
.oflags = LOWDOWN_TERM_NOLINK,
|
||||
};
|
||||
|
||||
@@ -129,7 +129,6 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
|
||||
try {
|
||||
auto colon = fn.rfind(':');
|
||||
if (colon == std::string::npos) fail();
|
||||
std::string filename(fn, 0, colon);
|
||||
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
|
||||
return {CanonPath(fn.substr(0, colon)), lineno};
|
||||
} catch (std::invalid_argument & e) {
|
||||
|
||||
@@ -212,7 +212,7 @@ struct ExprAttrs : Expr
|
||||
AttrDef() { };
|
||||
|
||||
template<typename T>
|
||||
const T & chooseByKind(const T & plain, const T & inherited, const T & inheritedFrom) const
|
||||
T chooseByKind(const T & plain, const T & inherited, const T & inheritedFrom) const
|
||||
{
|
||||
switch (kind) {
|
||||
case Kind::Plain:
|
||||
|
||||
@@ -624,10 +624,13 @@ struct nothing : p::nothing<Rule> {
|
||||
static_assert(!std::is_base_of_v<semantic, Rule>);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Self, typename OpCtx, typename AttrPathT, typename ExprT>
|
||||
struct operator_semantics {
|
||||
struct operator_semantics
|
||||
{
|
||||
private:
|
||||
operator_semantics() = default;
|
||||
friend Self;
|
||||
public:
|
||||
struct has_attr : grammar::op::has_attr {
|
||||
AttrPathT path;
|
||||
};
|
||||
|
||||
@@ -250,9 +250,7 @@ std::optional<Hash> Input::getNarHash() const
|
||||
|
||||
std::optional<std::string> Input::getRef() const
|
||||
{
|
||||
if (auto s = maybeGetStrAttr(attrs, "ref"))
|
||||
return *s;
|
||||
return {};
|
||||
return maybeGetStrAttr(attrs, "ref");
|
||||
}
|
||||
|
||||
std::optional<Hash> Input::getRev() const
|
||||
@@ -273,16 +271,12 @@ std::optional<Hash> Input::getRev() const
|
||||
|
||||
std::optional<uint64_t> Input::getRevCount() const
|
||||
{
|
||||
if (auto n = maybeGetIntAttr(attrs, "revCount"))
|
||||
return *n;
|
||||
return {};
|
||||
return maybeGetIntAttr(attrs, "revCount");
|
||||
}
|
||||
|
||||
std::optional<time_t> Input::getLastModified() const
|
||||
{
|
||||
if (auto n = maybeGetIntAttr(attrs, "lastModified"))
|
||||
return *n;
|
||||
return {};
|
||||
return maybeGetIntAttr(attrs, "lastModified");
|
||||
}
|
||||
|
||||
ParsedURL InputScheme::toURL(const Input & input) const
|
||||
|
||||
@@ -130,7 +130,7 @@ std::optional<std::string> readHeadCached(const std::string & actualUrl)
|
||||
// This function must behave the same way, so we return the expired
|
||||
// cached ref here.
|
||||
warn("could not get HEAD ref for repository '%s'; using expired cached ref '%s'", actualUrl, *cachedRef);
|
||||
return *cachedRef;
|
||||
return cachedRef;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
||||
@@ -1212,7 +1212,7 @@ HookReply DerivationGoal::tryBuildHook()
|
||||
hook->toHook.writeSide.reset();
|
||||
|
||||
/* Create the log file and pipe. */
|
||||
Path logFile = openLogFile();
|
||||
openLogFile();
|
||||
|
||||
std::set<int> fds;
|
||||
fds.insert(hook->fromHook.readSide.get());
|
||||
|
||||
@@ -332,7 +332,7 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull()
|
||||
if (statvfs(localStore.realStoreDir.get().c_str(), &st) == 0 &&
|
||||
(uint64_t) st.f_bavail * st.f_bsize < required)
|
||||
diskFull = true;
|
||||
if (statvfs(tmpDir.c_str(), &st) == 0 &&
|
||||
if (statvfs(tmpDirRoot.c_str(), &st) == 0 &&
|
||||
(uint64_t) st.f_bavail * st.f_bsize < required)
|
||||
diskFull = true;
|
||||
}
|
||||
@@ -363,13 +363,9 @@ void LocalDerivationGoal::cleanupPostOutputsRegisteredModeCheck()
|
||||
|
||||
void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck()
|
||||
{
|
||||
/* In the past, redirected outputs were manually tracked for deletion.
|
||||
* Now that we have the scratch outputs cleaner which are a superset of
|
||||
* redirected outputs, we just fire all uncancelled automatic deleters now.
|
||||
*
|
||||
* This should clean up any paths that IS NOT registered in the database.
|
||||
*/
|
||||
scratchOutputsCleaner.clear();
|
||||
/* Delete unused redirected outputs (when doing hash rewriting). */
|
||||
for (auto & i : redirectedOutputs)
|
||||
deletePath(worker.store.Store::toRealPath(i.second));
|
||||
|
||||
/* Delete the chroot (if we were using one). */
|
||||
autoDelChroot.reset(); /* this runs the destructor */
|
||||
@@ -479,25 +475,88 @@ void LocalDerivationGoal::startBuilder()
|
||||
settings.thisSystem,
|
||||
concatStringsSep<StringSet>(", ", worker.store.systemFeatures));
|
||||
|
||||
createDirs(settings.buildDir.get());
|
||||
try {
|
||||
auto buildDir = worker.buildDirOverride.value_or(settings.buildDir.get());
|
||||
|
||||
/* Create a temporary directory where the build will take
|
||||
place. */
|
||||
tmpDir = createTempDir(
|
||||
settings.buildDir.get(),
|
||||
"nix-build-" + std::string(drvPath.name()),
|
||||
false,
|
||||
false,
|
||||
0700
|
||||
);
|
||||
createDirs(buildDir);
|
||||
|
||||
/* Create a temporary directory where the build will take
|
||||
place. */
|
||||
tmpDirRoot =
|
||||
createTempDir(buildDir, "nix-build-" + std::string(drvPath.name()), false, false, 0700);
|
||||
} catch (SysError & e) {
|
||||
/*
|
||||
* Fallback to the global tmpdir and create a safe space there
|
||||
* only if it's a permission error.
|
||||
*/
|
||||
if (e.errNo != EACCES) {
|
||||
throw;
|
||||
}
|
||||
|
||||
auto globalTmp = defaultTempDir();
|
||||
createDirs(globalTmp);
|
||||
#if __APPLE__
|
||||
/* macOS filesystem namespacing does not exist, to avoid breaking builds, we need to weaken
|
||||
* the mode bits on the top-level directory. This avoids issues like
|
||||
* https://github.com/NixOS/nix/pull/11031. */
|
||||
constexpr int toplevelDirMode = 0755;
|
||||
#else
|
||||
constexpr int toplevelDirMode = 0700;
|
||||
#endif
|
||||
auto nixBuildsTmp =
|
||||
createTempDir(globalTmp, fmt("nix-builds-%s", geteuid()), false, false, toplevelDirMode);
|
||||
warn(
|
||||
"Failed to use the system-wide build directory '%s', falling back to a temporary "
|
||||
"directory inside '%s'",
|
||||
settings.buildDir.get(),
|
||||
nixBuildsTmp
|
||||
);
|
||||
worker.buildDirOverride = nixBuildsTmp;
|
||||
tmpDirRoot = createTempDir(
|
||||
nixBuildsTmp, "nix-build-" + std::string(drvPath.name()), false, false, 0700
|
||||
);
|
||||
}
|
||||
/* The TOCTOU between the previous mkdir call and this open call is unavoidable due to
|
||||
* POSIX semantics.*/
|
||||
tmpDirFd = AutoCloseFD{open(tmpDir.c_str(), O_RDONLY | O_NOFOLLOW | O_DIRECTORY)};
|
||||
tmpDirRootFd = AutoCloseFD{open(tmpDirRoot.c_str(), O_RDONLY | O_NOFOLLOW | O_DIRECTORY)};
|
||||
if (!tmpDirRootFd)
|
||||
throw SysError("failed to open the build temporary directory descriptor '%1%'", tmpDirRoot);
|
||||
|
||||
// place the actual build directory in a subdirectory of tmpDirRoot. if
|
||||
// we do not do this a build can `chown 777` its build directory and so
|
||||
// make it accessible to everyone in the system, breaking isolation. we
|
||||
// also need the intermediate level to be inaccessible to others. build
|
||||
// processes must be able to at least traverse to the directory though,
|
||||
// without being able to chmod. this means either mode 0750 or 0710. we
|
||||
// cannot use 0710 because the libarchive we link with is compiled with
|
||||
// an old apple sdk that does not have O_SEARCH, which makes libarchive
|
||||
// try to open tmpDirRoot for *read* and fail because g+r is not set. a
|
||||
// future update to nixpkgs may fix this. until then we do not lose any
|
||||
// security by setting mode 0750 because we use only a single subdir in
|
||||
// tmpDirRoot, so being able to list its parent doesn't break anything.
|
||||
//
|
||||
// use a short name to not increase the path length too much on darwin.
|
||||
// darwin has a severe sockaddr_un path length limitation, so this does
|
||||
// make a difference over more evocative names. we use `b` for `build`.
|
||||
tmpDir = tmpDirRoot + "/b";
|
||||
if (mkdirat(tmpDirRootFd.get(), "b", 0700)) {
|
||||
throw SysError("failed to create the build temporary directory '%1%'", tmpDir);
|
||||
}
|
||||
tmpDirFd = AutoCloseFD{openat(tmpDirRootFd.get(), "b", O_RDONLY | O_NOFOLLOW | O_DIRECTORY)};
|
||||
if (!tmpDirFd)
|
||||
throw SysError("failed to open the build temporary directory descriptor '%1%'", tmpDir);
|
||||
|
||||
chownToBuilder(tmpDirFd);
|
||||
|
||||
if (buildUser) {
|
||||
if (fchown(tmpDirRootFd.get(), -1, buildUser->getGID()) == -1) {
|
||||
throw SysError("cannot change ownership of '%1%'", tmpDirRoot);
|
||||
}
|
||||
if (fchmod(tmpDirRootFd.get(), 0750) == -1) {
|
||||
throw SysError("cannot change mode of '%1%'", tmpDirRoot);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & [outputName, status] : initialOutputs) {
|
||||
/* Set scratch path we'll actually use during the build.
|
||||
|
||||
@@ -527,10 +586,6 @@ void LocalDerivationGoal::startBuilder()
|
||||
to use a temporary path */
|
||||
makeFallbackPath(status.known->path);
|
||||
scratchOutputs.insert_or_assign(outputName, scratchPath);
|
||||
/* Schedule this scratch output path for automatic deletion
|
||||
* if we do not cancel it, e.g. when registering the outputs.
|
||||
*/
|
||||
scratchOutputsCleaner.insert_or_assign(outputName, worker.store.printStorePath(scratchPath));
|
||||
|
||||
/* Substitute output placeholders with the scratch output paths.
|
||||
We'll use during the build. */
|
||||
@@ -553,6 +608,8 @@ void LocalDerivationGoal::startBuilder()
|
||||
std::string h2 { scratchPath.hashPart() };
|
||||
inputRewrites[h1] = h2;
|
||||
}
|
||||
|
||||
redirectedOutputs.insert_or_assign(std::move(fixedFinalPath), std::move(scratchPath));
|
||||
}
|
||||
|
||||
/* Construct the environment passed to the builder. */
|
||||
@@ -721,7 +778,7 @@ void LocalDerivationGoal::startBuilder()
|
||||
printMsg(lvlVomit, "setting builder env variable '%1%'='%2%'", i.first, i.second);
|
||||
|
||||
/* Create the log file. */
|
||||
Path logFile = openLogFile();
|
||||
openLogFile();
|
||||
|
||||
/* Create a pseudoterminal to get the output of the builder. */
|
||||
builderOut = AutoCloseFD{posix_openpt(O_RDWR | O_NOCTTY)};
|
||||
@@ -1846,6 +1903,8 @@ void LocalDerivationGoal::runChild()
|
||||
|
||||
if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") {
|
||||
Strings sandboxArgs;
|
||||
sandboxArgs.push_back("_NIX_BUILD_TOP");
|
||||
sandboxArgs.push_back(tmpDir);
|
||||
sandboxArgs.push_back("_GLOBAL_TMP_DIR");
|
||||
sandboxArgs.push_back(globalTmpDir);
|
||||
if (allowLocalNetworking) {
|
||||
@@ -2382,10 +2441,6 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||
localStore.registerValidPaths({{oldInfo.path, oldInfo}});
|
||||
}
|
||||
|
||||
/* Don't register anything, since we already have the
|
||||
previous versions which we're comparing.
|
||||
NOTE: this means that the `.check` path will be automatically deleted.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2409,13 +2464,8 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||
/* If it's a CA path, register it right away. This is necessary if it
|
||||
isn't statically known so that we can safely unlock the path before
|
||||
the next iteration */
|
||||
if (newInfo.ca) {
|
||||
if (newInfo.ca)
|
||||
localStore.registerValidPaths({{newInfo.path, newInfo}});
|
||||
/* Cancel automatic deletion of that output if it was a scratch output. */
|
||||
if (auto cleaner = scratchOutputsCleaner.extract(outputName)) {
|
||||
cleaner.mapped().cancel();
|
||||
}
|
||||
}
|
||||
|
||||
infos.emplace(outputName, std::move(newInfo));
|
||||
}
|
||||
@@ -2443,13 +2493,6 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||
infos2.insert_or_assign(newInfo.path, newInfo);
|
||||
}
|
||||
localStore.registerValidPaths(infos2);
|
||||
|
||||
/* Cancel automatic deletion of that output if it was a scratch output that we just registered. */
|
||||
for (auto & [outputName, _ ] : infos) {
|
||||
if (auto cleaner = scratchOutputsCleaner.extract(outputName)) {
|
||||
cleaner.mapped().cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In case of a fixed-output derivation hash mismatch, throw an
|
||||
@@ -2483,13 +2526,6 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||
builtOutputs.emplace(outputName, thisRealisation);
|
||||
}
|
||||
|
||||
/* NOTE: At this point, all outputs MAY NOT have been registered.
|
||||
* Therefore, there may remains auto-deleters pending in the cleaner list (`scratchOutputsCleaner`).
|
||||
*
|
||||
* They will be finally deleted but we have no way to assert they all have been, e.g.
|
||||
* `assert(scratchOutputsCleaner.size() == 0)` cannot be written.
|
||||
*/
|
||||
|
||||
return builtOutputs;
|
||||
}
|
||||
|
||||
@@ -2679,16 +2715,16 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
|
||||
|
||||
void LocalDerivationGoal::deleteTmpDir(bool force)
|
||||
{
|
||||
if (tmpDir != "") {
|
||||
if (tmpDirRoot != "") {
|
||||
/* Don't keep temporary directories for builtins because they
|
||||
might have privileged stuff (like a copy of netrc). */
|
||||
if (settings.keepFailed && !force && !drv->isBuiltin()) {
|
||||
printError("note: keeping build directory '%s'", tmpDir);
|
||||
chmod(tmpDir.c_str(), 0755);
|
||||
printError("note: keeping build directory '%s'", tmpDirRoot);
|
||||
chmod(tmpDirRoot.c_str(), 0755);
|
||||
}
|
||||
else
|
||||
deletePath(tmpDir);
|
||||
tmpDir = "";
|
||||
deletePath(tmpDirRoot);
|
||||
tmpDirRoot = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||
/**
|
||||
* The temporary directory.
|
||||
*/
|
||||
Path tmpDir;
|
||||
Path tmpDirRoot, tmpDir;
|
||||
|
||||
/**
|
||||
* The temporary directory file descriptor
|
||||
*/
|
||||
AutoCloseFD tmpDirFd;
|
||||
AutoCloseFD tmpDirRootFd, tmpDirFd;
|
||||
|
||||
/**
|
||||
* The path of the temporary directory in the sandbox.
|
||||
@@ -107,6 +107,8 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||
* Hash rewriting.
|
||||
*/
|
||||
StringMap inputRewrites, outputRewrites;
|
||||
typedef map<StorePath, StorePath> RedirectedOutputs;
|
||||
RedirectedOutputs redirectedOutputs;
|
||||
|
||||
/**
|
||||
* The outputs paths used during the build.
|
||||
@@ -123,19 +125,6 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||
* self-references.
|
||||
*/
|
||||
OutputPathMap scratchOutputs;
|
||||
/**
|
||||
* Output paths used during the build are scheduled for
|
||||
* automatic cleanup unless they have been successfully built.
|
||||
*
|
||||
* `registerOutputs` take care of cancelling the cleanups
|
||||
* and clearing this vector.
|
||||
*
|
||||
* `startBuilder` take care of filling this vector
|
||||
* as `scratchOutputs` gets filled.
|
||||
*
|
||||
* This is a map from output names to automatic delete handles.
|
||||
*/
|
||||
std::map<std::string, AutoDelete> scratchOutputsCleaner;
|
||||
|
||||
/**
|
||||
* Path registration info from the previous round, if we're
|
||||
|
||||
@@ -26,12 +26,14 @@ R""(
|
||||
; Allow getpwuid.
|
||||
(allow mach-lookup (global-name "com.apple.system.opendirectoryd.libinfo"))
|
||||
|
||||
; Access to /tmp.
|
||||
; Access to /tmp and the build directory.
|
||||
; The network-outbound/network-inbound ones are for unix domain sockets, which
|
||||
; we allow access to in TMPDIR (but if we allow them more broadly, you could in
|
||||
; theory escape the sandbox)
|
||||
(allow file* process-exec network-outbound network-inbound
|
||||
(literal "/tmp") (subpath TMPDIR))
|
||||
(literal "/tmp")
|
||||
(subpath TMPDIR)
|
||||
(subpath (param "_NIX_BUILD_TOP")))
|
||||
|
||||
; Some packages like to read the system version.
|
||||
(allow file-read*
|
||||
|
||||
@@ -161,6 +161,7 @@ public:
|
||||
|
||||
Store & store;
|
||||
Store & evalStore;
|
||||
std::optional<Path> buildDirOverride;
|
||||
|
||||
struct HookState {
|
||||
std::unique_ptr<HookInstance> instance;
|
||||
|
||||
@@ -93,7 +93,7 @@ WireFormatGenerator CommonProto::Serialise<std::optional<ContentAddress>>::write
|
||||
{
|
||||
return [](std::string s) -> WireFormatGenerator {
|
||||
co_yield s;
|
||||
}(caOpt ? renderContentAddress(*caOpt) : "");
|
||||
}(caOpt ? renderContentAddress(caOpt) : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,8 +45,15 @@ std::string SecretKey::signDetached(std::string_view data) const
|
||||
{
|
||||
unsigned char sig[crypto_sign_BYTES];
|
||||
unsigned long long sigLen;
|
||||
crypto_sign_detached(sig, &sigLen, charptr_cast<const unsigned char *>(data.data()), data.size(),
|
||||
charptr_cast<const unsigned char *>(key.data()));
|
||||
crypto_sign_detached(
|
||||
sig,
|
||||
&sigLen,
|
||||
// the following is not a string function so no null termination issues are possible here.
|
||||
// NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
|
||||
charptr_cast<const unsigned char *>(data.data()),
|
||||
data.size(),
|
||||
charptr_cast<const unsigned char *>(key.data())
|
||||
);
|
||||
return name + ":" + base64Encode(std::string(reinterpret_cast<char *>(sig), sigLen));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,9 @@ void Store::exportPaths(const StorePathSet & paths, Sink & sink)
|
||||
auto sorted = topoSortPaths(paths);
|
||||
std::reverse(sorted.begin(), sorted.end());
|
||||
|
||||
std::string doneLabel("paths exported");
|
||||
//logger->incExpected(doneLabel, sorted.size());
|
||||
|
||||
for (auto & path : sorted) {
|
||||
//Activity act(*logger, lvlInfo, "exporting path '%s'", path);
|
||||
sink << 1;
|
||||
exportPath(path, sink);
|
||||
//logger->incProgress(doneLabel);
|
||||
}
|
||||
|
||||
sink << 0;
|
||||
|
||||
@@ -152,7 +152,6 @@ struct NarAccessor : public FSAccessor
|
||||
|
||||
NarMember * find(const Path & path)
|
||||
{
|
||||
Path canon = path == "" ? "" : canonPath(path);
|
||||
NarMember * current = &root;
|
||||
auto end = path.end();
|
||||
for (auto it = path.begin(); it != end; ) {
|
||||
|
||||
@@ -120,7 +120,7 @@ std::string NarInfo::to_string(const Store & store) const
|
||||
res += "Sig: " + sig + "\n";
|
||||
|
||||
if (ca)
|
||||
res += "CA: " + renderContentAddress(*ca) + "\n";
|
||||
res += "CA: " + renderContentAddress(ca) + "\n";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ SQLiteStmt::Use::~Use()
|
||||
SQLiteStmt::Use & SQLiteStmt::Use::operator () (std::string_view value, bool notNull)
|
||||
{
|
||||
if (notNull) {
|
||||
if (sqlite3_bind_text(stmt, curArg++, value.data(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
|
||||
if (sqlite3_bind_text(stmt, curArg++, value.data(), value.length(), SQLITE_TRANSIENT) != SQLITE_OK)
|
||||
SQLiteError::throw_(stmt.db, "binding argument");
|
||||
} else
|
||||
bind();
|
||||
|
||||
@@ -1322,8 +1322,7 @@ std::optional<StorePath> Store::getBuildDerivationPath(const StorePath & path)
|
||||
if (!path.isDerivation()) {
|
||||
try {
|
||||
auto info = queryPathInfo(path);
|
||||
if (!info->deriver) return std::nullopt;
|
||||
return *info->deriver;
|
||||
return info->deriver;
|
||||
} catch (InvalidPath &) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -239,6 +239,7 @@ struct BrotliCompressionSink : ChunkedCompressionSink
|
||||
|
||||
void writeInternal(std::string_view data) override
|
||||
{
|
||||
// NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
|
||||
auto next_in = charptr_cast<const uint8_t *>(data.data());
|
||||
size_t avail_in = data.size();
|
||||
uint8_t * next_out = outbuf;
|
||||
|
||||
@@ -475,7 +475,7 @@ static void _deletePath(const Path & path, uint64_t & bytesFreed)
|
||||
throw SysError("opening directory '%1%'", path);
|
||||
}
|
||||
|
||||
_deletePath(dirfd.get(), baseNameOf(path).data(), bytesFreed);
|
||||
_deletePath(dirfd.get(), std::string(baseNameOf(path)), bytesFreed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ std::string hiliteMatches(
|
||||
out.append(s.substr(last_end, m.position() - last_end));
|
||||
// Merge continous matches
|
||||
ssize_t end = start + m.length();
|
||||
while (++it != matches.end() && (*it).position() <= end) {
|
||||
for (++it; it != matches.end() && (*it).position() <= end; ++it) {
|
||||
auto n = *it;
|
||||
ssize_t nend = start + (n.position() - start + n.length());
|
||||
if (nend > end)
|
||||
|
||||
@@ -38,6 +38,6 @@ const nlohmann::json & ensureType(
|
||||
nlohmann::json(expectedType).type_name(),
|
||||
value.type_name());
|
||||
|
||||
return value;
|
||||
return value; // NOLINT(bugprone-return-const-ref-from-parameter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,12 +258,12 @@ extern Verbosity verbosity;
|
||||
* level. Note that this has to be implemented as a macro to ensure that the
|
||||
* arguments are evaluated lazily.
|
||||
*/
|
||||
#define printMsgUsing(loggerParam, level, args...) \
|
||||
do { \
|
||||
auto __lvl = level; \
|
||||
if (__lvl <= nix::verbosity) { \
|
||||
loggerParam->log(__lvl, fmt(args)); \
|
||||
} \
|
||||
#define printMsgUsing(loggerParam, level, args...) \
|
||||
do { \
|
||||
auto _lix_logger_print_lvl = level; \
|
||||
if (_lix_logger_print_lvl <= nix::verbosity) { \
|
||||
loggerParam->log(_lix_logger_print_lvl, fmt(args)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define printMsg(level, args...) printMsgUsing(logger, level, args)
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void RefScanSink::operator () (std::string_view data)
|
||||
previous fragment and the start of the current fragment. */
|
||||
auto s = tail;
|
||||
auto tailLen = std::min(data.size(), refLength);
|
||||
s.append(data.data(), tailLen);
|
||||
s.append(data.data(), tailLen); // NOLINT(bugprone-suspicious-stringview-data-usage)
|
||||
search(s, hashes, seen);
|
||||
|
||||
search(data, hashes, seen);
|
||||
|
||||
@@ -75,7 +75,6 @@ void Source::operator () (char * data, size_t len)
|
||||
|
||||
void Source::drainInto(Sink & sink)
|
||||
{
|
||||
std::string s;
|
||||
std::array<char, 8192> buf;
|
||||
while (true) {
|
||||
size_t n;
|
||||
@@ -251,7 +250,7 @@ Error readError(Source & source)
|
||||
auto type = readString(source);
|
||||
assert(type == "Error");
|
||||
auto level = (Verbosity) readInt(source);
|
||||
auto name = readString(source); // removed
|
||||
readString(source); // removed (name)
|
||||
auto msg = readString(source);
|
||||
ErrorInfo info {
|
||||
.level = level,
|
||||
|
||||
@@ -34,7 +34,7 @@ bool shouldANSI(StandardOutputStream fileno)
|
||||
// FIXME(jade): replace with TerminalCodeEater. wowie this is evil code.
|
||||
std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width, bool eatTabs)
|
||||
{
|
||||
std::string t, e;
|
||||
std::string t;
|
||||
size_t w = 0;
|
||||
auto i = s.begin();
|
||||
|
||||
|
||||
@@ -80,12 +80,18 @@ typename T::mapped_type * get(T & map, const typename T::key_type & key)
|
||||
* Get a value for the specified key from an associate container, or a default value if the key isn't present.
|
||||
*/
|
||||
template <class T>
|
||||
const typename T::mapped_type & getOr(T & map,
|
||||
const typename T::mapped_type & getOr(
|
||||
T & map [[clang::lifetimebound]],
|
||||
const typename T::key_type & key,
|
||||
const typename T::mapped_type & defaultValue)
|
||||
const typename T::mapped_type & defaultValue [[clang::lifetimebound]]
|
||||
)
|
||||
{
|
||||
auto i = map.find(key);
|
||||
if (i == map.end()) return defaultValue;
|
||||
if (i == map.end()) {
|
||||
/* FIXME(Raito): `[[clang::lifetimebound]]` has no effect on `defaultValue` warning. */
|
||||
// NOLINTNEXTLINE(bugprone-return-const-ref-from-parameter)
|
||||
return defaultValue;
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -1313,7 +1313,7 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg
|
||||
throw UsageError("exactly one argument expected");
|
||||
|
||||
if (auto dstGen = string2Int<GenerationNumber>(opArgs.front()))
|
||||
switchGeneration(globals.profile, *dstGen, globals.dryRun);
|
||||
switchGeneration(globals.profile, dstGen, globals.dryRun);
|
||||
else
|
||||
throw UsageError("expected a generation number");
|
||||
}
|
||||
|
||||
@@ -116,8 +116,6 @@ struct CmdBundle : InstallableCommand
|
||||
},
|
||||
});
|
||||
|
||||
auto outPathS = store->printStorePath(outPath);
|
||||
|
||||
if (!outLink) {
|
||||
auto * attr = vRes->attrs->get(evalState->sName);
|
||||
if (!attr)
|
||||
|
||||
@@ -114,7 +114,7 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
|
||||
std::cout << '\t';
|
||||
Strings ss;
|
||||
if (info->ultimate) ss.push_back("ultimate");
|
||||
if (info->ca) ss.push_back("ca:" + renderContentAddress(*info->ca));
|
||||
if (info->ca) ss.push_back("ca:" + renderContentAddress(info->ca));
|
||||
for (auto & sig : info->sigs) ss.push_back(sig);
|
||||
std::cout << concatStringsSep(" ", ss);
|
||||
}
|
||||
|
||||
@@ -160,7 +160,6 @@ struct CmdSearch : InstallableCommand, MixJSON
|
||||
{"description", description},
|
||||
};
|
||||
} else {
|
||||
auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m");
|
||||
if (results > 1) logger->cout("");
|
||||
logger->cout(
|
||||
"* %s%s",
|
||||
|
||||
@@ -40,13 +40,9 @@ struct CmdCopySigs : StorePathsCommand
|
||||
|
||||
ThreadPool pool;
|
||||
|
||||
std::string doneLabel = "done";
|
||||
std::atomic<size_t> added{0};
|
||||
|
||||
//logger->setExpected(doneLabel, storePaths.size());
|
||||
|
||||
auto doPath = [&](const Path & storePathS) {
|
||||
//Activity act(*logger, lvlInfo, "getting signatures for '%s'", storePath);
|
||||
|
||||
checkInterrupt();
|
||||
|
||||
@@ -78,8 +74,6 @@ struct CmdCopySigs : StorePathsCommand
|
||||
store->addSignatures(storePath, newSigs);
|
||||
added += newSigs.size();
|
||||
}
|
||||
|
||||
//logger->incProgress(doneLabel);
|
||||
};
|
||||
|
||||
for (auto & storePath : storePaths)
|
||||
|
||||
@@ -34,6 +34,7 @@ private:
|
||||
OptionalFileEntryRef File,
|
||||
StringRef SearchPath, StringRef RelativePath,
|
||||
const Module *Imported,
|
||||
bool ModuleImported,
|
||||
SrcMgr::CharacteristicKind FileType) override;
|
||||
};
|
||||
|
||||
@@ -46,7 +47,7 @@ void FixIncludesCallbacks::LexedFileChanged(FileID, LexedFileChangeReason,
|
||||
void FixIncludesCallbacks::InclusionDirective(
|
||||
SourceLocation, const Token &, StringRef FileName, bool IsAngled,
|
||||
CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef,
|
||||
StringRef, const Module *, SrcMgr::CharacteristicKind) {
|
||||
StringRef, const Module *, bool, SrcMgr::CharacteristicKind) {
|
||||
if (Ignore)
|
||||
return;
|
||||
|
||||
|
||||
@@ -80,4 +80,4 @@ out="$(nix-build 2>&1 failing.nix \
|
||||
[[ "$out" =~ .*"note: keeping build directory".* ]]
|
||||
|
||||
build_dir="$(grep "note: keeping build" <<< "$out" | sed -E "s/^(.*)note: keeping build directory '(.*)'(.*)$/\2/")"
|
||||
[[ "foo" = $(<"$build_dir"/bar) ]]
|
||||
[[ "foo" = $(<"$build_dir"/b/bar) ]]
|
||||
|
||||
@@ -170,3 +170,28 @@ test "$(<<<"$out" grep -E '^error:' | wc -l)" = 3
|
||||
<<<"$out" grepQuiet -E "error: 2 dependencies of derivation '.*-x4\\.drv' failed to build"
|
||||
<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x3\\.drv'"
|
||||
<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
|
||||
|
||||
# Ensure when if the system build dir is inaccessible, we can still build things
|
||||
BUILD_DIR=$(mktemp -d)
|
||||
chmod 0000 "$BUILD_DIR"
|
||||
nix --build-dir "$BUILD_DIR" build -E 'with import ./config.nix; mkDerivation { name = "test"; buildCommand = "echo rawr > $out"; }' --impure --no-link
|
||||
|
||||
# ensure that the build directory parent is not world-accessible
|
||||
chmod 0755 "$BUILD_DIR"
|
||||
FIFO="$BUILD_DIR/fifo"
|
||||
mkfifo "$FIFO"
|
||||
(
|
||||
echo > "$FIFO"
|
||||
trap 'echo > "$FIFO"' EXIT
|
||||
mode=$(stat -c %a $BUILD_DIR/b/*)
|
||||
[ "$mode" = "700" -o "$mode" = "710" ]
|
||||
) &
|
||||
nix build --build-dir "$BUILD_DIR/b" -E '
|
||||
with import ./config.nix; mkDerivation {
|
||||
name = "test";
|
||||
buildCommand = "cat '"$FIFO"'; cat '"$FIFO"' > $out";
|
||||
}' \
|
||||
--extra-sandbox-paths "$FIFO" \
|
||||
--impure \
|
||||
--no-link
|
||||
wait
|
||||
|
||||
@@ -45,7 +45,7 @@ test_custom_build_dir() {
|
||||
[ "$status" = "100" ]
|
||||
[[ 1 == "$(count "$customBuildDir/nix-build-"*)" ]]
|
||||
local buildDir="$customBuildDir/nix-build-"*
|
||||
grep $checkBuildId $buildDir/checkBuildId
|
||||
grep $checkBuildId $buildDir/b/checkBuildId
|
||||
}
|
||||
test_custom_build_dir
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
nix-repl> 1 + 1
|
||||
2
|
||||
|
||||
nix-repl> :doc builtins.head
|
||||
Synopsis: builtins.head list
|
||||
nix-repl> :doc builtins.add
|
||||
Synopsis: builtins.add e1 e2
|
||||
|
||||
Return the sum of the numbers e1 and e2.
|
||||
|
||||
Return the first element of a list; abort evaluation if
|
||||
the argument isn’t a list or is an empty list. You can
|
||||
test whether a list is empty by comparing it with [].
|
||||
|
||||
nix-repl> f = a: "" + a
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ let
|
||||
defaults = {
|
||||
nixpkgs.pkgs = nixpkgsFor.${system}.native;
|
||||
nix.checkAllErrors = false;
|
||||
# nixos-option fails to build with lix and no tests use any of the tools
|
||||
system.disableInstallerTools = true;
|
||||
};
|
||||
_module.args.nixpkgs = nixpkgs;
|
||||
_module.args.system = system;
|
||||
@@ -146,9 +148,6 @@ in
|
||||
|
||||
symlinkResolvconf = runNixOSTestFor "x86_64-linux" ./symlink-resolvconf.nix;
|
||||
|
||||
# Use this test to test things that cannot easily be tested under chroot Nix stores in functional test suite.
|
||||
non-chroot-misc = runNixOSTestFor "x86_64-linux" ./non-chroot-misc;
|
||||
|
||||
noNewPrivilegesInSandbox = runNixOSTestFor "x86_64-linux" ./no-new-privileges/sandbox.nix;
|
||||
|
||||
noNewPrivilegesOutsideSandbox = runNixOSTestFor "x86_64-linux" ./no-new-privileges/no-sandbox.nix;
|
||||
|
||||
@@ -76,7 +76,7 @@ in
|
||||
# Fetching from a server with an untrusted cert should fail.
|
||||
err = machine.fail("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }' 2>&1")
|
||||
print(err)
|
||||
assert "SSL certificate problem: self-signed certificate" in err or "SSL peer certificate or SSH remote key was not OK" in err
|
||||
assert "SSL peer certificate or SSH remote key was not OK" in err
|
||||
|
||||
# Fetching from a server with a trusted cert should work via environment variable override.
|
||||
machine.succeed("NIX_SSL_CERT_FILE=/tmp/cafile.pem nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }'")
|
||||
|
||||
@@ -45,12 +45,12 @@ in {
|
||||
server.wait_for_unit("network-online.target")
|
||||
client.wait_for_unit("network-online.target")
|
||||
|
||||
client.succeed("mkdir -m 700 /root/.ssh")
|
||||
client.succeed("mkdir -m 700 /root/.ssh || [[ -d /root/.ssh ]]")
|
||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the server.
|
||||
server.succeed("mkdir -m 700 /root/.ssh")
|
||||
server.succeed("mkdir -m 700 /root/.ssh || [[ -d /root/.ssh ]]")
|
||||
server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
server.wait_for_unit("sshd.service")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world' >&2")
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
{ ... }:
|
||||
# Misc things we want to test inside of a non redirected, non chroot Nix store.
|
||||
let
|
||||
nonAutoCleaningFailingDerivationCode = ''
|
||||
derivation {
|
||||
name = "scratch-failing";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ (builtins.toFile "builder.sh" "echo bonjour > $out; echo out: $out; false") ];
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "non-chroot-sandbox-misc";
|
||||
|
||||
nodes.machine = {
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
import re
|
||||
start_all()
|
||||
|
||||
# You might ask yourself why write such a convoluted thing?
|
||||
# The condition for fooling Nix into NOT cleaning up the output path are non trivial and unclear.
|
||||
# This is one of those: create a derivation, mkdir or touch the $out path, communicate it back.
|
||||
# Even with a sandboxed Lix, you will observe leftovers before 2.93.0. After this version, this test passes.
|
||||
result = machine.fail("""nix-build --substituters "" -E '${nonAutoCleaningFailingDerivationCode}' 2>&1""")
|
||||
match = re.search(r'out: (\S+)', result)
|
||||
assert match is not None, "Did not find Nix store path in the result of the failing build"
|
||||
outpath = match.group(1).strip()
|
||||
print(f"Found Nix store path: {outpath}")
|
||||
machine.fail(f'stat {outpath}')
|
||||
'';
|
||||
}
|
||||
@@ -48,6 +48,7 @@ in
|
||||
imports = [ test.config.builders.config ];
|
||||
services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = [ config.system.build.extraUtils ];
|
||||
nix.settings.sandbox = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.91.2",
|
||||
"official_release": true,
|
||||
"version": "2.91.3",
|
||||
"official_release": false,
|
||||
"release_name": "Dragon's Breath"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user