Skip to content

Commit 628acf0

Browse files
committed
Merge remote-tracking branch 'detsys/main' into sync-2.34
2 parents e105583 + 7ab838d commit 628acf0

32 files changed

Lines changed: 613 additions & 82 deletions

.github/workflows/build.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ on:
3838
required: false
3939
manual_netlify_site_id:
4040
required: false
41+
sentry_auth_token:
42+
required: false
43+
sentry_org:
44+
required: false
45+
sentry_project:
46+
required: false
4147

4248
jobs:
4349
build:
@@ -52,6 +58,14 @@ jobs:
5258
- uses: DeterminateSystems/flakehub-cache-action@main
5359
- run: nix build .#packages.${{ inputs.system }}.default .#packages.${{ inputs.system }}.binaryTarball --no-link -L
5460
- run: nix build .#packages.${{ inputs.system }}.binaryTarball --out-link tarball
61+
- run: nix build .#^debug,out
62+
- name: Upload debug info to Sentry
63+
run: ./maintainers/upload-debug-info-to-sentry.py --debug-dir ./result-debug ./result/bin/nix
64+
if: env.SENTRY_AUTH_TOKEN != ''
65+
env:
66+
SENTRY_AUTH_TOKEN: ${{ secrets.sentry_auth_token }}
67+
SENTRY_ORG: ${{ secrets.sentry_org }}
68+
SENTRY_PROJECT: ${{ secrets.sentry_project }}
5569
- uses: actions/upload-artifact@v6
5670
with:
5771
name: ${{ inputs.system }}

.github/workflows/ci.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ jobs:
4444
secrets:
4545
manual_netlify_auth_token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
4646
manual_netlify_site_id: ${{ secrets.NETLIFY_SITE_ID }}
47+
sentry_auth_token: ${{ secrets.SENTRY_AUTH_TOKEN }}
48+
sentry_org: ${{ secrets.SENTRY_ORG }}
49+
sentry_project: ${{ secrets.SENTRY_PROJECT }}
4750

4851
build_aarch64-linux:
4952
uses: ./.github/workflows/build.yml
@@ -62,6 +65,10 @@ jobs:
6265
runner: UbuntuLatest32Cores128GArm
6366
runner_for_virt: UbuntuLatest32Cores128GArm
6467
runner_small: UbuntuLatest32Cores128GArm
68+
secrets:
69+
sentry_auth_token: ${{ secrets.SENTRY_AUTH_TOKEN }}
70+
sentry_org: ${{ secrets.SENTRY_ORG }}
71+
sentry_project: ${{ secrets.SENTRY_PROJECT }}
6572

6673
build_aarch64-darwin:
6774
uses: ./.github/workflows/build.yml
@@ -70,6 +77,10 @@ jobs:
7077
runner: namespace-profile-mac-m2-12c28g
7178
runner_for_virt: namespace-profile-mac-m2-12c28g
7279
runner_small: macos-latest-xlarge
80+
secrets:
81+
sentry_auth_token: ${{ secrets.SENTRY_AUTH_TOKEN }}
82+
sentry_org: ${{ secrets.SENTRY_ORG }}
83+
sentry_project: ${{ secrets.SENTRY_PROJECT }}
7384

7485
success:
7586
runs-on: ubuntu-latest

.version-determinate

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.17.3
1+
3.18.0

doc/manual/generate-manpage.nix

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ let
7676
subcommands = if length categories > 1 then listCategories else listSubcommands details.commands;
7777

7878
categories = sort (x: y: x.id < y.id) (
79-
unique (map (cmd: { inherit (cmd.category) id description; }) (attrValues details.commands))
79+
unique (
80+
map (cmd: { inherit (cmd.category) id description; }) (
81+
builtins.filter (cmd: cmd.category.id != 103) (attrValues details.commands)
82+
)
83+
)
8084
);
8185

8286
listCategories = concatStrings (map showCategory categories);

doc/manual/source/SUMMARY.md.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
- [Contributing](development/contributing.md)
149149
- [Determinate Nix Release Notes](release-notes-determinate/index.md)
150150
- [Changes between Nix and Determinate Nix](release-notes-determinate/changes.md)<!-- next -->
151+
- [Release 3.18.0 (2026-04-20)](release-notes-determinate/v3.18.0.md)
151152
- [Release 3.17.3 (2026-04-07)](release-notes-determinate/v3.17.3.md)
152153
- [Release 3.17.2 (2026-03-27)](release-notes-determinate/v3.17.2.md)
153154
- [Release 3.17.1 (2026-03-18)](release-notes-determinate/v3.17.1.md)

doc/manual/source/release-notes-determinate/changes.md

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changes between Nix and Determinate Nix
22

3-
This section lists the differences between upstream Nix 2.33 and Determinate Nix 3.17.3.<!-- differences -->
3+
This section lists the differences between upstream Nix 2.33 and Determinate Nix 3.18.0.<!-- differences -->
44

55
* In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature.
66

@@ -153,43 +153,16 @@ This section lists the differences between upstream Nix 2.33 and Determinate Nix
153153

154154
<!-- Determinate Nix version 3.15.2 -->
155155

156-
* Path inputs are now lazy [DeterminateSystems/nix-src#312](https://github.com/DeterminateSystems/nix-src/pull/312)
157-
158-
* Improved performance when fetching a lot of dependencies with curl [DeterminateSystems/nix-src#315](https://github.com/DeterminateSystems/nix-src/pull/315)
159-
160156
<!-- Determinate Nix version 3.16.0 -->
161157

162-
* Wasm support [DeterminateSystems/nix-src#309](https://github.com/DeterminateSystems/nix-src/pull/309)
163-
164-
* Fix hung downloads when `http-connections = 0` [DeterminateSystems/nix-src#327](https://github.com/DeterminateSystems/nix-src/pull/327)
165-
166-
* Support .gitattributes in subdirectories [DeterminateSystems/nix-src#335](https://github.com/DeterminateSystems/nix-src/pull/335)
167-
168-
* builtins.getFlake fixes [DeterminateSystems/nix-src#337](https://github.com/DeterminateSystems/nix-src/pull/337)
158+
* Determinate Nix has an experimental builtin `builtins.wasm` that allows the Nix language to be extended using any language that compiles to Wasm. [DeterminateSystems/nix-src#309](https://github.com/DeterminateSystems/nix-src/pull/309)
169159

170-
* builtins.getFlake: Support path values [DeterminateSystems/nix-src#338](https://github.com/DeterminateSystems/nix-src/pull/338)
160+
* `builtins.getFlake` supports path values. [DeterminateSystems/nix-src#338](https://github.com/DeterminateSystems/nix-src/pull/338)
171161

172-
* Provenance [DeterminateSystems/nix-src#321](https://github.com/DeterminateSystems/nix-src/pull/321)
173-
174-
* Add subcommand 'nix provenance show' [DeterminateSystems/nix-src#340](https://github.com/DeterminateSystems/nix-src/pull/340)
175-
176-
* Increase the open file soft limit to the hard limit [DeterminateSystems/nix-src#347](https://github.com/DeterminateSystems/nix-src/pull/347)
162+
* Determinate Nix has support for keeping track of the provenance of store paths. [DeterminateSystems/nix-src#321](https://github.com/DeterminateSystems/nix-src/pull/321)
177163

178164
<!-- Determinate Nix version 3.16.1 -->
179165

180-
181-
* Record provenance for unlocked inputs and impure evaluations in [DeterminateSystems/nix-src#354](https://github.com/DeterminateSystems/nix-src/pull/354)
182-
183-
* Add setting narinfo-cache-meta-ttl in [DeterminateSystems/nix-src#355](https://github.com/DeterminateSystems/nix-src/pull/355)
184-
185-
* Add derivationWithMeta builtin in [DeterminateSystems/nix-src#357](https://github.com/DeterminateSystems/nix-src/pull/357)
186-
187-
* Add builtins.wasi in [DeterminateSystems/nix-src#359](https://github.com/DeterminateSystems/nix-src/pull/359)
188-
189-
* Add `nix provenance verify` command in [DeterminateSystems/nix-src#356](https://github.com/DeterminateSystems/nix-src/pull/356)
190-
191-
* builtins.hashString: Devirtualize lazy paths, and re-enable lazy trees tests in [DeterminateSystems/nix-src#360](https://github.com/DeterminateSystems/nix-src/pull/360)
192-
193166
<!-- Determinate Nix version 3.16.2 -->
194167

195168

@@ -201,10 +174,12 @@ This section lists the differences between upstream Nix 2.33 and Determinate Nix
201174

202175
<!-- Determinate Nix version 3.17.1 -->
203176

204-
* Flake inputs are substituted if possible before fetching from the authoritative source, in [DeterminateSystems/nix-src#380](https://github.com/DeterminateSystems/nix-src/pull/380)
205-
206-
* Provenance now supports additional nix.conf-defined tags, in [DeterminateSystems/nix-src#374](https://github.com/DeterminateSystems/nix-src/pull/374)
207-
208177
<!-- Determinate Nix version 3.17.2 -->
209178

210179
<!-- Determinate Nix version 3.17.3 -->
180+
181+
<!-- Determinate Nix version 3.18.0 -->
182+
183+
* Determinate Nix can upload crash info to Sentry. [DeterminateSystems/nix-src#418](https://github.com/DeterminateSystems/nix-src/pull/418)
184+
185+
* Determinate Nix provides the pre-build hook with a JSON serialization of the derivation. [DeterminateSystems/nix-src#424](https://github.com/DeterminateSystems/nix-src/pull/424)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Release 3.18.0 (2026-04-20)
2+
3+
* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
4+
5+
## What's Changed
6+
7+
### Sentry integration
8+
9+
In order to more proactively keep track of crashes, Sentry is now integrated into Determinate Nix.
10+
11+
This allows us to more easily triage and remedy crashes that occur in the wild, without depending on manual use reports.
12+
13+
It can be enabled by:
14+
15+
* populating the file `/etc/nix/sentry-endpoint` with a Sentry DSN; or
16+
* setting the `NIX_SENTRY_ENDPOINT` environment variable to a Sentry DSN
17+
18+
and can be disabled by:
19+
20+
* setting the environment variable `DETSYS_IDS_TELEMETRY` to the value `disabled`; or
21+
* setting the environment variable `NIX_SENTRY_ENDPOINT` to an empty string
22+
23+
PR: [DeterminateSystems/nix-src#418](https://github.com/DeterminateSystems/nix-src/pull/418)
24+
25+
### Pre-build hook now receives the JSON serialization of the derivation
26+
27+
The pre-build hook already received the path of the derivation as an argument, but that path doesn't typically exist when called as a remote build.
28+
29+
Now, the pre-build hook is spawned with the environment variable `NIX_DERIVATION_V4` set to a file that contains the JSON representation of the derivation in v4 format, allowing instrospection of e.g. `requiredSystemFeatures` for scheduling decisions.
30+
31+
PR: [DeterminateSystems/nix-src#424](https://github.com/DeterminateSystems/nix-src/pull/424)
32+
33+
### Fix empty Git exports when using legacy Git compatibility
34+
35+
A regression introduced in v3.16.0 made it possible for there to be empty Git exports in the Nix store when using legacy Git flakes (those depending on Nix 2.19 lockfile semantics).
36+
37+
This is now fixed.
38+
39+
PR: [DeterminateSystems/nix-src#425](https://github.com/DeterminateSystems/nix-src/pull/425)
40+
41+
42+
**Full Changelog**: [v3.17.3...v3.18.0](https://github.com/DeterminateSystems/nix-src/compare/v3.17.3...v3.18.0)
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env nix
2+
#!nix shell --inputs-from . nixpkgs#sentry-cli --command python3
3+
4+
import argparse
5+
import json
6+
import os
7+
import platform
8+
import re
9+
import subprocess
10+
import sys
11+
import urllib.error
12+
import urllib.parse
13+
import urllib.request
14+
15+
NAR_DIR = "/tmp/nars"
16+
DEBUG_INFO_DIR = "/tmp/debug-info"
17+
18+
19+
def get_dynamic_libraries(executable: str) -> list[str]:
20+
if platform.system() == "Darwin":
21+
result = subprocess.run(["otool", "-L", executable], capture_output=True, text=True, check=True)
22+
libs = []
23+
for line in result.stdout.splitlines()[1:]: # skip first line (the binary path itself)
24+
# otool -L output lines look like:
25+
# /nix/store/.../libfoo.dylib (compatibility version X.Y.Z, current version A.B.C)
26+
m = re.match(r"\s+(\S+)\s+\(", line)
27+
if m:
28+
libs.append(m.group(1))
29+
return libs
30+
else:
31+
result = subprocess.run(["ldd", executable], capture_output=True, text=True, check=True)
32+
libs = []
33+
for line in result.stdout.splitlines():
34+
# ldd output lines look like:
35+
# libfoo.so.1 => /nix/store/.../libfoo.so.1 (0x...)
36+
# /lib64/ld-linux-x86-64.so.2 (0x...)
37+
m = re.search(r"=> (/\S+)", line)
38+
if m:
39+
libs.append(m.group(1))
40+
elif line.strip().startswith("/"):
41+
path = line.strip().split()[0]
42+
libs.append(path)
43+
return libs
44+
45+
46+
def get_build_id(path: str) -> str | None:
47+
result = subprocess.run(["readelf", "-n", path], capture_output=True, text=True)
48+
m = re.search(r"Build ID:\s+([0-9a-f]+)", result.stdout)
49+
return m.group(1) if m else None
50+
51+
52+
def download_nar(build_id: str, archive: str) -> str:
53+
"""Download a NAR to /tmp/nars and return the local path. Skips if already present."""
54+
base_url = f"https://cache.nixos.org/debuginfo/{build_id}"
55+
nar_url = urllib.parse.urljoin(base_url, archive)
56+
filename = nar_url.split("/")[-1]
57+
local_path = os.path.join(NAR_DIR, filename)
58+
if not os.path.exists(local_path):
59+
os.makedirs(NAR_DIR, exist_ok=True)
60+
print(f" downloading {nar_url} ...", file=sys.stderr)
61+
urllib.request.urlretrieve(nar_url, local_path)
62+
else:
63+
print(f" already have {filename}", file=sys.stderr)
64+
return local_path
65+
66+
67+
def extract_debug_symbols(nar_path: str, member: str, build_id: str) -> str:
68+
"""Extract a member from a .nar.xz into /tmp/debug-info/<build_id>.debug. Returns the output path."""
69+
out_path = os.path.join(DEBUG_INFO_DIR, f"{build_id}.debug")
70+
if os.path.exists(out_path):
71+
print(f" already extracted {out_path}", file=sys.stderr)
72+
return out_path
73+
os.makedirs(DEBUG_INFO_DIR, exist_ok=True)
74+
print(f" extracting {member} -> {out_path} ...", file=sys.stderr)
75+
xz = subprocess.Popen(["xz", "-d"], stdin=open(nar_path, "rb"), stdout=subprocess.PIPE)
76+
nar_cat = subprocess.run(
77+
["nix", "nar", "cat", "/dev/stdin", member],
78+
stdin=xz.stdout,
79+
capture_output=True,
80+
check=True,
81+
)
82+
xz.wait()
83+
with open(out_path, "wb") as f:
84+
f.write(nar_cat.stdout)
85+
return out_path
86+
87+
88+
def find_debug_file_in_dirs(build_id: str, debug_dirs: list[str]) -> str | None:
89+
"""Look for a .debug file by build ID under <dir>/lib/debug/.build-id/NN/NNN.debug."""
90+
subpath = os.path.join("lib", "debug", ".build-id", build_id[:2], build_id[2:] + ".debug")
91+
for d in debug_dirs:
92+
candidate = os.path.join(d, subpath)
93+
if os.path.exists(candidate):
94+
return candidate
95+
return None
96+
97+
98+
def fetch_debuginfo(build_id: str) -> dict | None:
99+
url = f"https://cache.nixos.org/debuginfo/{build_id}"
100+
try:
101+
with urllib.request.urlopen(url) as resp:
102+
return json.loads(resp.read())
103+
except urllib.error.HTTPError as e:
104+
if e.code == 404:
105+
return None
106+
raise
107+
108+
109+
def main():
110+
parser = argparse.ArgumentParser(
111+
description="Upload debug symbols to Sentry."
112+
)
113+
parser.add_argument("executable", help="Path to the executable (e.g. ./result/bin/nix)")
114+
parser.add_argument("--project", help="Sentry project ID")
115+
parser.add_argument("--debug-dir", action="append", default=[], metavar="DIR",
116+
help="Directory to search for debug files (may be repeated, Linux only)")
117+
args = parser.parse_args()
118+
119+
libs = [args.executable] + get_dynamic_libraries(args.executable)
120+
121+
if platform.system() == "Darwin":
122+
# On macOS there are no separate debug info files; upload the binaries directly.
123+
print("Files to upload:", file=sys.stderr)
124+
for lib in libs:
125+
print(f" {lib}", file=sys.stderr)
126+
files_to_upload = libs
127+
else:
128+
debug_files = []
129+
print("ELF files to process:", file=sys.stderr)
130+
for lib in libs:
131+
build_id = get_build_id(lib)
132+
if build_id is None:
133+
print(f" {lib} (no build ID)", file=sys.stderr)
134+
continue
135+
136+
local = find_debug_file_in_dirs(build_id, args.debug_dir)
137+
if local:
138+
print(f" {lib} ({build_id}): found locally at {local}", file=sys.stderr)
139+
debug_files.append(local)
140+
continue
141+
142+
debuginfo = fetch_debuginfo(build_id)
143+
if debuginfo is None:
144+
print(f" {lib} ({build_id}, no debug info in cache)", file=sys.stderr)
145+
continue
146+
print(f" {lib} ({build_id}): member={debuginfo['member']}", file=sys.stderr)
147+
nar_path = download_nar(build_id, debuginfo["archive"])
148+
debug_file = extract_debug_symbols(nar_path, debuginfo["member"], build_id)
149+
debug_files.append(debug_file)
150+
files_to_upload = debug_files
151+
152+
if files_to_upload:
153+
print(f"Uploading {len(files_to_upload)} file(s) to Sentry...", file=sys.stderr)
154+
cmd = ["sentry-cli", "debug-files", "upload"]
155+
if args.project:
156+
cmd += ["--project", args.project]
157+
subprocess.run(cmd + files_to_upload, check=True)
158+
159+
160+
if __name__ == "__main__":
161+
main()

packaging/dependencies.nix

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,9 @@ scope: {
142142
});
143143

144144
wasmtime = pkgs.callPackage ./wasmtime.nix { };
145+
146+
sentry-native = (pkgs.callPackage ./sentry-native.nix { }).override {
147+
# Avoid having two curls in our closure.
148+
inherit (scope) curl;
149+
};
145150
}

packaging/dev-shell.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
291291
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents2.nix-perl-bindings.mesonFlags)
292292
)
293293
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents2.nix-expr.mesonFlags)
294-
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
294+
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags)
295+
++ map (transformFlag "nix") (ignoreCrossFile pkgs.nixComponents2.nix-cli.mesonFlags);
295296

296297
nativeBuildInputs =
297298
let

0 commit comments

Comments
 (0)