-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathflake.nix
More file actions
367 lines (333 loc) · 16.3 KB
/
Copy pathflake.nix
File metadata and controls
367 lines (333 loc) · 16.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
{
description = "SSTIM Workbench — open sensory-stimulation reference environment and Graph Navigator";
# Single pinned input. flake.lock records the exact nixpkgs revision so the
# toolchain is byte-reproducible across contributor machines and CI.
# Regenerate the pin with: nix flake update
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }:
let
# Tier-1 dev/CI platforms: Linux + Apple Silicon/Intel macOS.
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f (import nixpkgs { inherit system; }));
in
{
# `nix develop` / direnv `use flake` — the canonical SSTIM Workbench dev environment.
devShells = forAllSystems (pkgs:
let
py = pkgs.python312;
# pySHACL and its OWL-RL dependency are not currently packaged in
# nixpkgs (confirmed against the pinned revision and the registry —
# `nix search nixpkgs shacl` is empty), so we vendor both from PyPI.
# This also pins exact validator versions, which the old unpinned CI
# `pip install pyshacl` never did. Bump version + hash to upgrade.
owlrl = py.pkgs.buildPythonPackage rec {
pname = "owlrl";
version = "6.0.2";
pyproject = true;
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-kE4zEP9N8VEBR1d2aT0kJ9H4JE7ppqn54Tw8V/rpC3Q=";
};
build-system = [ py.pkgs.setuptools ];
dependencies = [ py.pkgs.rdflib ];
dontCheckRuntimeDeps = true;
doCheck = false;
pythonImportsCheck = [ "owlrl" ];
};
# HED validation for ADR 0025. `hedtools` is the reference
# implementation from the HED Working Group and is what ADR 0025
# decision 7 means by "HED validation against the pinned schema".
# `make hed-crosswalk` used to check only that each tag existed in the
# schema, which is not the same thing and passed a mapping that would
# never have validated anywhere; it now runs hedtools. Two of its
# dependencies are also absent from nixpkgs, so all three are vendored
# from PyPI here on the same pattern as pySHACL. Bump version + hash to
# upgrade; the HED *schema* version is pinned separately, in
# static/schemas/sstim-hed-event-map.json.
click-option-group = py.pkgs.buildPythonPackage rec {
pname = "click_option_group";
version = "0.5.9";
pyproject = true;
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-+U7SvEz2kFLg8pWSvR53GheJvXv8SC3QvEghNK/5WCM=";
};
# hatchling + hatch-vcs, not setuptools. hatch-vcs derives the
# version from git metadata that a PyPI sdist does not carry, so it
# is supplied explicitly.
build-system = with py.pkgs; [ hatchling hatch-vcs ];
env.HATCH_VCS_PRETEND_VERSION = version;
dependencies = [ py.pkgs.click ];
dontCheckRuntimeDeps = true;
doCheck = false;
pythonImportsCheck = [ "click_option_group" ];
};
semantic-version = py.pkgs.buildPythonPackage rec {
pname = "semantic_version";
version = "2.10.0";
pyproject = true;
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-vau20zaZjLs3jUuds6S1ah4yNXAdwF6iaQ2amX7VBBw=";
};
build-system = [ py.pkgs.setuptools ];
dontCheckRuntimeDeps = true;
doCheck = false;
pythonImportsCheck = [ "semantic_version" ];
};
hedtools = py.pkgs.buildPythonPackage rec {
pname = "hedtools";
version = "1.2.0";
pyproject = true;
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-7mHiWfMPDDPjfEqpRql/X7b6w5JlPN4CHPwzPF+vSNE=";
};
# setuptools-scm also derives the version from git; the sdist has
# none, so it is pretended here.
build-system = with py.pkgs; [ setuptools setuptools-scm ];
env.SETUPTOOLS_SCM_PRETEND_VERSION = version;
dependencies = with py.pkgs; [
click defusedxml inflect numpy openpyxl pandas portalocker typeguard
] ++ [ click-option-group semantic-version ];
dontCheckRuntimeDeps = true;
doCheck = false;
pythonImportsCheck = [ "hed" ];
};
pyshacl = py.pkgs.buildPythonApplication rec {
pname = "pyshacl";
version = "0.26.0";
pyproject = true;
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-SNRPMXzZqtjj/bXfiqVwb6ktxrJ0ZBlpgDXoSjIPuJ0=";
};
build-system = [ py.pkgs.poetry-core ];
# nixpkgs ships poetry-core 2.x; pySHACL 0.26.0 caps it at <2 out of
# caution, but it builds cleanly with v2. Drop the cap so the wheel
# build's dependency check passes. (Both spellings handled.)
postPatch = ''
substituteInPlace pyproject.toml \
--replace-quiet "poetry-core>=1.9.0,<2.0.0" "poetry-core>=1.9.0" \
--replace-quiet "poetry-core>=1.9.0,<2" "poetry-core>=1.9.0"
'';
dependencies = [
py.pkgs.rdflib
owlrl
py.pkgs.prettytable
py.pkgs.packaging
];
# We supply nixpkgs' rdflib (7.x); ignore pySHACL's own pins/extras.
dontCheckRuntimeDeps = true;
doCheck = false; # upstream test suite needs bundled fixtures
pythonImportsCheck = [ "pyshacl" ];
meta.mainProgram = "pyshacl";
};
# pyLODE 2.13.2 — SKOS-aware HTML docs (vocpub profile) for the
# vocabulary module. WIDOCO is OWL-centric; pyLODE renders SKOS
# concept schemes. Pinned at 2.x (setuptools, deps all in nixpkgs);
# 3.x pulls in kurra → shacl-rules/sparqlib, not worth the cascade.
pylode = py.pkgs.buildPythonApplication rec {
pname = "pyLODE";
version = "2.13.2";
format = "setuptools";
src = pkgs.fetchPypi {
inherit pname version;
hash = "sha256-+NU+mbpvh7hly2yuuN+KrTxtc1cr/kIGq0fwl8g99kI=";
};
# The 2.13.2 sdist omits requirements.txt, which setup.py reads for
# install_requires. Recreate it; nix supplies the deps below.
preBuild = ''
printf 'rdflib\nrequests\njinja2\nmarkdown\n' > requirements.txt
'';
dependencies = [
py.pkgs.rdflib
py.pkgs.requests
py.pkgs.jinja2
py.pkgs.markdown
];
dontCheckRuntimeDeps = true;
doCheck = false;
pythonImportsCheck = [ "pylode" ];
meta.mainProgram = "pylode";
};
robot = pkgs.stdenvNoCC.mkDerivation rec {
pname = "robot";
version = "1.9.10";
src = pkgs.fetchurl {
url = "https://github.com/ontodev/robot/releases/download/v${version}/robot.jar";
hash = "sha256-Fqc8B08981mnM4qEtOB4h4X+BhF/kxu5eW6WGep3YQU=";
};
nativeBuildInputs = [ pkgs.makeWrapper ];
dontUnpack = true;
installPhase = ''
runHook preInstall
install -Dm444 "$src" "$out/share/java/robot.jar"
makeWrapper ${pkgs.jre_headless}/bin/java "$out/bin/robot" \
--add-flags "-jar $out/share/java/robot.jar"
runHook postInstall
'';
meta = {
description = "ROBOT ontology command-line tool";
homepage = "https://robot.obolibrary.org/";
license = pkgs.lib.licenses.bsd3;
mainProgram = "robot";
platforms = pkgs.lib.platforms.unix;
};
};
widoco = pkgs.stdenvNoCC.mkDerivation rec {
pname = "widoco";
version = "1.4.25";
# The release ships one fat jar per supported JDK; pick the JDK-17
# build to match jre_headless.
src = pkgs.fetchurl {
url = "https://github.com/dgarijo/Widoco/releases/download/v${version}/widoco-${version}-jar-with-dependencies_JDK-17.jar";
hash = "sha256-vleicP/7keVYEPowhxfnBKROLnwCej1oElpJ2myLTis=";
};
nativeBuildInputs = [ pkgs.makeWrapper ];
dontUnpack = true;
installPhase = ''
runHook preInstall
install -Dm444 "$src" "$out/share/java/widoco.jar"
makeWrapper ${pkgs.jre_headless}/bin/java "$out/bin/widoco" \
--add-flags "-jar $out/share/java/widoco.jar"
runHook postInstall
'';
meta = {
description = "WIDOCO ontology documentation generator";
homepage = "https://github.com/dgarijo/Widoco";
license = pkgs.lib.licenses.asl20;
mainProgram = "widoco";
platforms = pkgs.lib.platforms.unix;
};
};
in
{
default = pkgs.mkShell {
name = "bsc-lab";
packages = [
pkgs.nodejs_24 # matches CI (.github/workflows) and package.json
(py.withPackages (ps: [ ps.rdflib ps.jsonschema hedtools ])) # RDF tooling, manifest JSON Schema validation, HED validation (ADR 0025)
pyshacl # vendored `pyshacl` CLI — SHACL for `make validate`
pylode # vendored `pylode` CLI — SKOS vocab HTML docs (`make vocab-docs`)
robot # ROBOT + HermiT/ELK — OWL DL consistency for `make reason`
widoco # WIDOCO — ontology HTML reference docs for `make ontology-docs`
pkgs.wabt # wat2wasm for `make wasm` (bsc-osc.wat → .wasm)
pkgs.gnumake # the canonical task entrypoint (Makefile)
pkgs.firebase-tools # `make deploy-firestore-rules` without npx
];
shellHook = ''
echo "SSTIM Workbench dev shell — $(node --version) node, $(python3 --version), wabt $(wat2wasm --version)"
echo "Run 'make help' for available targets."
'';
};
});
# `nix build` — the static SSTIM Workbench site as an immutable package.
#
# This closes gap G1 in docs/technical/PORTABLE_DEPLOYMENT.md and nothing
# more. It is *not* self-hosting: there is deliberately no NixOS module,
# no service definition and no container image yet. What it gives an
# operator is a reproducible artifact they can serve with any static web
# server, built from a pinned toolchain rather than from whatever Node
# happened to be on the build machine.
#
# Credential-free by construction. The flake source is the git-tracked
# tree, so an untracked, gitignored .env cannot enter the sandbox — the
# build cannot inline a developer's Firebase key even by accident. That is
# the same property `make smoke-static` asserts for ordinary builds, here
# obtained structurally instead of by convention.
packages = forAllSystems (pkgs: {
default = pkgs.buildNpmPackage (finalAttrs: {
pname = "bsc-lab";
version = "0.1.0"; # tracks package.json
src = self;
# Regenerate after any package-lock.json change:
# nix build 2>&1 | grep -A2 'specified:'
# or: nix run nixpkgs#prefetch-npm-deps -- package-lock.json
npmDepsHash = "sha256-YmOSLoPaw/fMiW9D1oZUzKxfjah2xu8jL2YKwkX5aiQ=";
nodejs = pkgs.nodejs_24; # same major as the dev shell and CI
# `npm run build` → vite build → dist/ (adapter-static).
npmBuildScript = "build";
# Pin SvelteKit's version name to the revision being built. Left to its
# default it is a timestamp, which lands in every content hash and makes
# the output differ on every run. A revision is stable for identical
# sources and still changes whenever the source does, so the service
# worker's cache name keeps invalidating correctly (ADR 0009).
BSC_BUILD_VERSION = self.shortRev or self.dirtyShortRev or "unknown";
# Vite would otherwise read a project-root .env in every mode. There is
# none in the sandbox, but point envDir at an empty path so the intent
# is explicit and a future stray file cannot change the output.
preBuild = ''
export BSC_ENV_DIR="$TMPDIR/bsc-empty-env"
mkdir -p "$BSC_ENV_DIR"
'';
installPhase = ''
runHook preInstall
mkdir -p "$out/share/bsc-lab"
cp -r dist/. "$out/share/bsc-lab/"
runHook postInstall
'';
# Fail the build rather than ship an empty or credentialed artifact.
doInstallCheck = true;
installCheckPhase = ''
runHook preInstallCheck
test -f "$out/share/bsc-lab/index.html" \
|| { echo "no index.html in package output"; exit 1; }
test -f "$out/share/bsc-lab/ontology/sstim-core.ttl" \
|| { echo "ontology assets missing from package output"; exit 1; }
test -f "$out/share/bsc-lab/ontology/manifest.json" \
|| { echo "ontology manifest missing from package output"; exit 1; }
grep -q 'bsc-lab-build-info-1' "$out/share/bsc-lab/build-info.json" \
|| { echo "package does not declare the commit it was built from"; exit 1; }
if grep -rEq 'AIza[0-9A-Za-z_-]{20,}' "$out/share/bsc-lab"; then
echo "a Firebase API key was inlined into the package output"; exit 1
fi
runHook postInstallCheck
'';
meta = {
description = "SSTIM Workbench — static sensory-stimulation workbench and Graph Navigator";
homepage = "https://w3c-cg.github.io/sstim/";
license = pkgs.lib.licenses.asl20;
platforms = pkgs.lib.platforms.all;
};
});
}
# An OCI image for operators who do not run Nix. Linux-only, and built
# from the *same* store path the NixOS module serves — the application is
# never rebuilt for it, so the deployment paths cannot drift.
// pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
oci = import ./nix/oci.nix {
inherit pkgs;
bscLabPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default;
};
});
# A NixOS service module, so an operator can run an instance
# declaratively. See nix/modules/bsc-lab.nix — it owns the two things the
# hosting platform otherwise decides for us: ontology MIME types and the
# cross-origin isolation headers that GitHub Pages cannot apply.
nixosModules.default = import ./nix/modules/bsc-lab.nix;
# `nix flake check` builds the package, so a broken build fails the same
# gate as a broken evaluation. On Linux it additionally boots a clean
# NixOS VM with the module enabled and asserts the deployment is correct —
# routes, media types, headers, real 404s, no embedded credentials.
# The VM test is Linux-only; on macOS the check set is just the package
# and CI is the machine that boots the VM.
checks = forAllSystems (pkgs:
let system = pkgs.stdenv.hostPlatform.system;
in
{
package = self.packages.${system}.default;
}
// pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
nixos-vm = import ./nix/tests/bsc-lab.nix {
inherit pkgs;
bscLabModule = self.nixosModules.default;
bscLabPackage = self.packages.${system}.default;
# One definition of a correct deployment, shared with the OCI image.
smokeScript = ./scripts/smoke-http.sh;
};
});
# `nix fmt` formats the Nix sources in this repo.
formatter = forAllSystems (pkgs: pkgs.nixpkgs-fmt);
};
}