From 410b57df4ad8c018ceeaeeedb58c83b02dc5f2b4 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 12 Jun 2026 12:56:00 +0000 Subject: [PATCH 1/4] Add devcontainer for sandboxed Claude Code development Provides a containerized dev environment so Claude Code can be run with --dangerously-skip-permissions while confining the blast radius to the container's filesystem. - Base on Microsoft's digest-pinned devcontainers/base:ubuntu24.04, which ships a non-root `vscode` user (UID 1000) with passwordless sudo. - Install the project toolchain via single-user Nix + direnv/nix-direnv, matching the project's flake (python, uv, make, wabt, K Framework). - Install the Claude Code CLI to a per-user npm prefix. - init: true for proper PID 1 / zombie reaping. - Share the host git identity read-only and expose it through a writable GIT_CONFIG_GLOBAL (~/.gitconfig.local) so every user can git commit and run git config inside the container; openssh-client enables SSH remotes via the forwarded host SSH agent. Claude Code runs in its normal permission-prompting mode by default; users opt into bypass per session with --dangerously-skip-permissions. Co-Authored-By: Claude Opus 4.8 --- .devcontainer/Dockerfile | 75 +++++++++++++++++++++++++++++++++ .devcontainer/devcontainer.json | 27 ++++++++++++ .devcontainer/setup-git.sh | 30 +++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/setup-git.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..68ced77 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,75 @@ +# Microsoft's official devcontainer base (Ubuntu 24.04), pinned by digest for +# reproducibility. It ships a non-root `vscode` user (UID 1000) with passwordless +# sudo plus the common dev tools (git, curl, sudo, ca-certificates, openssh-client), +# so no manual user creation is needed here. +FROM mcr.microsoft.com/devcontainers/base:ubuntu24.04@sha256:4bcb1b466771b1ba1ea110e2a27daea2f6093f9527fb75ee59703ec89b5561cb + +ENV DEBIAN_FRONTEND=noninteractive \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 + +# The base already provides git/sudo/ca-certificates/curl/openssh-client; we only +# strictly need xz-utils for the Nix installer tarball. The rest are listed +# defensively (apt is idempotent and skips already-present packages). +RUN apt-get update && apt-get install -y --no-install-recommends \ + git sudo ca-certificates curl less xz-utils openssh-client \ + && rm -rf /var/lib/apt/lists/* + +# Pre-create /nix owned by the vscode user and a system-wide nix.conf. Two things to note: +# - Sandboxing relies on CAP_SYS_ADMIN (sethostname etc.), which container +# builds don't grant — without `sandbox = false` both the Nix self-install +# and every subsequent `nix profile install` fail. +# - The K Framework binary caches let `kup install k` pull prebuilt K binaries +# instead of compiling from source. Single-user Nix (vscode owns /nix) honors +# these substituters from the system config, so no per-user nix.conf needed. +RUN mkdir -m 0755 /nix \ + && chown vscode:vscode /nix \ + && mkdir -p /etc/nix \ + && printf '%s\n' \ + 'sandbox = false' \ + 'filter-syscalls = false' \ + 'experimental-features = nix-command flakes' \ + 'substituters = https://cache.nixos.org https://k-framework.cachix.org https://k-framework-binary.cachix.org' \ + 'trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= k-framework.cachix.org-1:jeyMXB2h28gpNRjuVkehg+zLj62ma1RnyyopA/20yFE= k-framework-binary.cachix.org-1:pJedQ8iG19BW3v/DMMmiRVtwRBGO3fyMv2Ws0OpBADs=' \ + > /etc/nix/nix.conf + +USER vscode +WORKDIR /home/vscode + +# Single-user Nix install — the variant that works in containers without +# systemd / a running daemon. +RUN curl -fsSL https://nixos.org/nix/install | sh -s -- --no-daemon --no-channel-add + +ENV PATH=/home/vscode/.nix-profile/bin:/home/vscode/.npm-global/bin:$PATH + +# Pin the `nixpkgs` flake to nixos-25.05 (matches the project's flake.nix), then +# install only the container-level bootstrap/runtime tooling via Nix: +# - direnv + nix-direnv → auto-load and cache the flake's `nix develop` shell on +# entry to /workspace; this is what actually provides the +# project toolchain (python, uv, make, wabt, K Framework), +# so those live in flake.nix's devShell, not here. +# - nodejs_22 → host for the Claude Code CLI (run as `claude` from +# anywhere, so it stays globally on PATH, not in the shell) +RUN . /home/vscode/.nix-profile/etc/profile.d/nix.sh \ + && nix registry add nixpkgs github:NixOS/nixpkgs/nixos-25.05 \ + && nix profile install \ + nixpkgs#direnv \ + nixpkgs#nix-direnv \ + nixpkgs#nodejs_22 + +# Claude Code CLI — installed to a per-user prefix so root isn't required. +RUN . /home/vscode/.nix-profile/etc/profile.d/nix.sh \ + && npm config set prefix /home/vscode/.npm-global \ + && npm install -g @anthropic-ai/claude-code + +# Wire up nix-direnv, then hook direnv into interactive shells. Order matters: +# Nix must be sourced before the direnv hook so the profile PATH is in place when +# direnv evaluates the flake. +RUN mkdir -p /home/vscode/.config/direnv \ + && echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > /home/vscode/.config/direnv/direnvrc \ + && printf '%s\n' \ + '. /home/vscode/.nix-profile/etc/profile.d/nix.sh' \ + 'eval "$(direnv hook bash)"' \ + >> /home/vscode/.bashrc + +WORKDIR /workspace diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..8764954 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,27 @@ +{ + "name": "komet_node", + "build": { + "dockerfile": "Dockerfile" + }, + "remoteUser": "vscode", + "workspaceFolder": "/workspace", + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", + "init": true, + "mounts": [ + "source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume", + "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,readonly" + ], + "containerEnv": { + "CLAUDE_CONFIG_DIR": "/home/vscode/.claude", + "GIT_CONFIG_GLOBAL": "/home/vscode/.gitconfig.local" + }, + "postCreateCommand": "sudo chown -R vscode:vscode /home/vscode/.claude && bash .devcontainer/setup-git.sh && direnv allow /workspace && nix develop /workspace --command bash -c 'uv sync --frozen'", + "customizations": { + "vscode": { + "extensions": [ + "anthropic.claude-code", + "mkhl.direnv" + ] + } + } +} diff --git a/.devcontainer/setup-git.sh b/.devcontainer/setup-git.sh new file mode 100644 index 0000000..9f02f03 --- /dev/null +++ b/.devcontainer/setup-git.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Wire up a writable global git config that inherits the host user's identity. +# +# devcontainer.json bind-mounts the host ~/.gitconfig read-only at +# /home/vscode/.gitconfig and sets GIT_CONFIG_GLOBAL=/home/vscode/.gitconfig.local. +# Git therefore writes global config to the (writable) .gitconfig.local while +# still reading the host's name/email/aliases through the include set up below. +# +# The result: every user of this container can `git commit` with their own host +# identity and run `git config --global ...` inside the container, without the +# EBUSY breakage a directly-writable bind mount over ~/.gitconfig would cause. +# +# Adapted from trailofbits/claude-code-devcontainer's post_install.py. Invoked +# from devcontainer.json's postCreateCommand. Idempotent — safe to re-run. +set -euo pipefail + +host_gitconfig="/home/vscode/.gitconfig" +local_gitconfig="/home/vscode/.gitconfig.local" + +if [ -f "${host_gitconfig}" ]; then + # Host provided a ~/.gitconfig (bind-mounted as a regular file): inherit it. + printf '[include]\n\tpath = %s\n' "${host_gitconfig}" > "${local_gitconfig}" + echo "setup-git: global config includes host identity from ${host_gitconfig}" +else + # No host ~/.gitconfig — the missing bind source is materialized as an empty + # directory, which must NOT be included. Leave an empty writable global. + : > "${local_gitconfig}" + echo "setup-git: no host ~/.gitconfig found; created empty ${local_gitconfig}" + echo "setup-git: set your identity with 'git config --global user.name ...' / user.email" +fi From d85917ee62a4be8a8b97aa3dda0feea55b66c891 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 12 Jun 2026 13:11:41 +0000 Subject: [PATCH 2/4] Add Nix dev environment backing the devcontainer The devcontainer loads the project toolchain via direnv + `nix develop`, so it needs the flake the container provisions: - flake.nix: add k-framework, wabt, and gnumake to the devShell (the toolchain the project's Makefile and integration tests rely on), pin UV_LINK_MODE=copy. - flake.lock: pin all flake inputs for reproducible `nix develop`. - .envrc: `use flake` so direnv auto-loads the dev shell on entry. - .gitignore: ignore the .direnv/ cache the container creates. Co-Authored-By: Claude Opus 4.8 --- .envrc | 1 + .gitignore | 1 + flake.lock | 595 +++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 14 +- 4 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 98fe5a7..06c6c9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /dist/ __pycache__/ .coverage +.direnv/ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6488b9f --- /dev/null +++ b/flake.lock @@ -0,0 +1,595 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "fmt-src": { + "flake": false, + "locked": { + "lastModified": 1661615830, + "narHash": "sha256-rP6ymyRc7LnKxUXwPpzhHOQvpJkpnRFOt2ctvUNlYI0=", + "owner": "fmtlib", + "repo": "fmt", + "rev": "a33701196adfad74917046096bf5a2aa0ab0bb50", + "type": "github" + }, + "original": { + "owner": "fmtlib", + "ref": "9.1.0", + "repo": "fmt", + "type": "github" + } + }, + "haskell-backend": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "k-framework", + "nixpkgs" + ], + "rv-nix-tools": [ + "k-framework", + "rv-nix-tools" + ], + "some-cabal-hashes-lib": "some-cabal-hashes-lib", + "z3": "z3" + }, + "locked": { + "lastModified": 1769721341, + "narHash": "sha256-tHHaCWhdBXAeIeOoRqwLke+PkfYflFD9wH7a4Q+iCis=", + "owner": "runtimeverification", + "repo": "haskell-backend", + "rev": "bf7eaa523d856ac0c0fe72109cb35034338b885b", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "ref": "v0.1.145", + "repo": "haskell-backend", + "type": "github" + } + }, + "immer-src": { + "flake": false, + "locked": { + "lastModified": 1708038459, + "narHash": "sha256-aV/mQFuPzioy1PxROc85ypeP7/d0nn+xcBPzy9taw2s=", + "owner": "runtimeverification", + "repo": "immer", + "rev": "4b0914f0b2acb33befe0ba4cd3a7954f2687e9bb", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "repo": "immer", + "rev": "4b0914f0b2acb33befe0ba4cd3a7954f2687e9bb", + "type": "github" + } + }, + "k-framework": { + "inputs": { + "flake-utils": [ + "k-framework", + "llvm-backend", + "utils" + ], + "haskell-backend": "haskell-backend", + "llvm-backend": "llvm-backend", + "nixpkgs": [ + "k-framework", + "rv-nix-tools", + "nixpkgs" + ], + "nixpkgs-unstable": "nixpkgs-unstable", + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": [ + "k-framework", + "uv2nix", + "pyproject-nix" + ], + "rv-nix-tools": "rv-nix-tools_2", + "uv2nix": "uv2nix" + }, + "locked": { + "lastModified": 1777293866, + "narHash": "sha256-FjpyrMez/5uHThx48uHAnCOJj1flv8Ij2o44TvRp1no=", + "owner": "runtimeverification", + "repo": "k", + "rev": "1469129d4f6f203461ed1bfd626625d837e523d6", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "ref": "v7.1.319", + "repo": "k", + "type": "github" + } + }, + "llvm-backend": { + "inputs": { + "flake-compat": "flake-compat", + "fmt-src": "fmt-src", + "immer-src": "immer-src", + "nixpkgs": [ + "k-framework", + "nixpkgs" + ], + "pybind11-src": "pybind11-src", + "rapidjson-src": "rapidjson-src", + "rv-nix-tools": "rv-nix-tools", + "utils": "utils" + }, + "locked": { + "lastModified": 1760570155, + "narHash": "sha256-jgDhxUFXMe7kTqdq6eSHshRJJzm/1QTmUc8SQIjN2sE=", + "owner": "runtimeverification", + "repo": "llvm-backend", + "rev": "618f530031870d6e8a74633b122d46afb5d7ad8e", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "ref": "v0.1.139", + "repo": "llvm-backend", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1716457947, + "narHash": "sha256-Y+exebcqeprnhEpoPJrEUZmNeO60qeOxkVHhqG/OEwQ=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "69493a13eaea0dc4682fd07e8a084f17813dbeeb", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "rev": "69493a13eaea0dc4682fd07e8a084f17813dbeeb", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1716457947, + "narHash": "sha256-Y+exebcqeprnhEpoPJrEUZmNeO60qeOxkVHhqG/OEwQ=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "69493a13eaea0dc4682fd07e8a084f17813dbeeb", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "rev": "69493a13eaea0dc4682fd07e8a084f17813dbeeb", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1767313136, + "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-25.05", + "type": "indirect" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1744306051, + "narHash": "sha256-jWwqkmi8cplBu4CXUb4zdfpqKp3UJYVAs/b5m8M75sg=", + "owner": "runtimeverification", + "repo": "nixpkgs", + "rev": "e9a77bb24d408d3898f6a11fb065d350d6bc71f1", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "ref": "libmatch", + "repo": "nixpkgs", + "type": "github" + } + }, + "pybind11-src": { + "flake": false, + "locked": { + "lastModified": 1657936673, + "narHash": "sha256-/X8DZPFsNrKGbhjZ1GFOj17/NU6p4R+saCW3pLKVNeA=", + "owner": "pybind", + "repo": "pybind11", + "rev": "0ba639d6177659c5dc2955ac06ad7b5b0d22e05c", + "type": "github" + }, + "original": { + "owner": "pybind", + "repo": "pybind11", + "rev": "0ba639d6177659c5dc2955ac06ad7b5b0d22e05c", + "type": "github" + } + }, + "pyproject-build-systems": { + "inputs": { + "nixpkgs": [ + "k-framework", + "nixpkgs" + ], + "pyproject-nix": [ + "k-framework", + "uv2nix", + "pyproject-nix" + ], + "uv2nix": [ + "k-framework", + "uv2nix" + ] + }, + "locked": { + "lastModified": 1763662255, + "narHash": "sha256-4bocaOyLa3AfiS8KrWjZQYu+IAta05u3gYZzZ6zXbT0=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "042904167604c681a090c07eb6967b4dd4dae88c", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "042904167604c681a090c07eb6967b4dd4dae88c", + "type": "github" + } + }, + "pyproject-build-systems_2": { + "inputs": { + "nixpkgs": [ + "uv2nix", + "nixpkgs" + ], + "pyproject-nix": [ + "uv2nix", + "pyproject-nix" + ], + "uv2nix": [ + "uv2nix" + ] + }, + "locked": { + "lastModified": 1744599653, + "narHash": "sha256-nysSwVVjG4hKoOjhjvE6U5lIKA8sEr1d1QzEfZsannU=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "7dba6dbc73120e15b558754c26024f6c93015dd7", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "7dba6dbc73120e15b558754c26024f6c93015dd7", + "type": "github" + } + }, + "pyproject-nix": { + "inputs": { + "nixpkgs": [ + "k-framework", + "uv2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763716960, + "narHash": "sha256-PUlomle4klGbnZr0wOn8z61Mbt7tXh6Yp3hZ9/CQkq0=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "d6c61dbe0be75e2f4cf0efcdc62428175be4cfb5", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "type": "github" + } + }, + "pyproject-nix_2": { + "inputs": { + "nixpkgs": [ + "uv2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745782090, + "narHash": "sha256-c/mqxgOVDcwrdcY3FqG22MwLPGY5rCz5gte1sxISKnM=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "2db2d95ddbc4ff5e29730cb82fdba6647be258a7", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "type": "github" + } + }, + "rapidjson-src": { + "flake": false, + "locked": { + "lastModified": 1472111945, + "narHash": "sha256-SxUXSOQDZ0/3zlFI4R84J56/1fkw2jhge4mexNF6Pco=", + "owner": "Tencent", + "repo": "rapidjson", + "rev": "f54b0e47a08782a6131cc3d60f94d038fa6e0a51", + "type": "github" + }, + "original": { + "owner": "Tencent", + "repo": "rapidjson", + "rev": "f54b0e47a08782a6131cc3d60f94d038fa6e0a51", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "k-framework": "k-framework", + "nixpkgs": "nixpkgs_3", + "pyproject-build-systems": "pyproject-build-systems_2", + "pyproject-nix": [ + "uv2nix", + "pyproject-nix" + ], + "uv2nix": "uv2nix_2" + } + }, + "rv-nix-tools": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1726497185, + "narHash": "sha256-iN+5eLmDm/rLuIZezS5ZqiW1BtBpwrrM9CPPP7Z5Tog=", + "owner": "runtimeverification", + "repo": "rv-nix-tools", + "rev": "854d4f05ea78547d46e807b414faad64cea10ae4", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "repo": "rv-nix-tools", + "rev": "854d4f05ea78547d46e807b414faad64cea10ae4", + "type": "github" + } + }, + "rv-nix-tools_2": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1726497185, + "narHash": "sha256-iN+5eLmDm/rLuIZezS5ZqiW1BtBpwrrM9CPPP7Z5Tog=", + "owner": "runtimeverification", + "repo": "rv-nix-tools", + "rev": "854d4f05ea78547d46e807b414faad64cea10ae4", + "type": "github" + }, + "original": { + "owner": "runtimeverification", + "repo": "rv-nix-tools", + "rev": "854d4f05ea78547d46e807b414faad64cea10ae4", + "type": "github" + } + }, + "some-cabal-hashes-lib": { + "flake": false, + "locked": { + "lastModified": 1680222726, + "narHash": "sha256-EkXjFG2Vw2/vWCnX4oB7jQeLxEpXFXf/WSpRCUpEvbc=", + "owner": "lf-", + "repo": "nix-lib", + "rev": "c46b62b650fb4edaccaedbeb5050236901fe385e", + "type": "github" + }, + "original": { + "owner": "lf-", + "repo": "nix-lib", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "uv2nix": { + "inputs": { + "nixpkgs": [ + "k-framework", + "nixpkgs-unstable" + ], + "pyproject-nix": "pyproject-nix" + }, + "locked": { + "lastModified": 1767701098, + "narHash": "sha256-CJhKZnWb3gumR9oTRjFvCg/6lYTGbZRU7xtvcyWIRwU=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "9d357f0d2ce6f5f35ec7959d7e704452352eb4da", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "9d357f0d2ce6f5f35ec7959d7e704452352eb4da", + "type": "github" + } + }, + "uv2nix_2": { + "inputs": { + "nixpkgs": "nixpkgs_4", + "pyproject-nix": "pyproject-nix_2" + }, + "locked": { + "lastModified": 1746048139, + "narHash": "sha256-LdCLyiihLg6P2/mjzP0+W7RtraDSIaJJPTy6SCtW5Ag=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "680e2f8e637bc79b84268949d2f2b2f5e5f1d81c", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "680e2f8e637bc79b84268949d2f2b2f5e5f1d81c", + "type": "github" + } + }, + "z3": { + "flake": false, + "locked": { + "lastModified": 1734346855, + "narHash": "sha256-8hWXCr6IuNVKkOegEmWooo5jkdmln9nU7wI8T882BSE=", + "owner": "Z3Prover", + "repo": "z3", + "rev": "6f24123f0c9d1d8bd84dec275c5c7aea939a19fe", + "type": "github" + }, + "original": { + "owner": "Z3Prover", + "ref": "z3-4.13.4", + "repo": "z3", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 9e90efd..331bfb0 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,12 @@ inputs = { nixpkgs.url = "nixpkgs/nixos-25.05"; flake-utils.url = "github:numtide/flake-utils"; + # K Framework, pinned to match the `kframework` (pyk) version in uv.lock — + # pyk and the K binaries must be the same version. We consume the prebuilt + # `k` package directly (replacing the imperative `kup install k`); its + # nixpkgs is intentionally NOT followed, so the k-framework binary caches + # are hit instead of rebuilding K against our nixpkgs. + k-framework.url = "github:runtimeverification/k/v7.1.319"; uv2nix.url = "github:pyproject-nix/uv2nix/680e2f8e637bc79b84268949d2f2b2f5e5f1d81c"; # stale nixpkgs is missing the alias `lib.match` -> `builtins.match` # therefore point uv2nix to a patched nixpkgs, which introduces this alias @@ -17,7 +23,7 @@ }; pyproject-nix.follows = "uv2nix/pyproject-nix"; }; - outputs = { self, nixpkgs, flake-utils, pyproject-nix, pyproject-build-systems, uv2nix }: + outputs = { self, nixpkgs, flake-utils, pyproject-nix, pyproject-build-systems, uv2nix, k-framework }: let pythonVer = "310"; in flake-utils.lib.eachSystem [ @@ -52,11 +58,15 @@ buildInputs = [ python pkgs.uv + pkgs.gnumake # the project's Makefile drives every dev task + pkgs.wabt # wat2wasm, used by integration tests + k-framework.packages.${system}.k # K Framework (kompile/krun/...), replaces `kup install k` ]; env = { - # prevent uv from managing Python downloads and force use of specific + # prevent uv from managing Python downloads and force use of specific UV_PYTHON_DOWNLOADS = "never"; UV_PYTHON = python.interpreter; + UV_LINK_MODE = "copy"; }; shellHook = '' unset PYTHONPATH From 0d22cd477c372753e45f7524d95f556eab8e5693 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:18:58 +0000 Subject: [PATCH 3/4] Pin @anthropic-ai/claude-code to version 2.1.175 in Dockerfile --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 68ced77..b93c62d 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -60,7 +60,7 @@ RUN . /home/vscode/.nix-profile/etc/profile.d/nix.sh \ # Claude Code CLI — installed to a per-user prefix so root isn't required. RUN . /home/vscode/.nix-profile/etc/profile.d/nix.sh \ && npm config set prefix /home/vscode/.npm-global \ - && npm install -g @anthropic-ai/claude-code + && npm install -g @anthropic-ai/claude-code@2.1.175 # Wire up nix-direnv, then hook direnv into interactive shells. Order matters: # Nix must be sourced before the direnv hook so the profile PATH is in place when From 3497eec7efd78380d01252559edd77509572b029 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:19:00 +0000 Subject: [PATCH 4/4] fix: pin Nix installer to specific release URL (v2.28.3) for reproducibility --- .devcontainer/Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b93c62d..69cad95 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -36,9 +36,12 @@ RUN mkdir -m 0755 /nix \ USER vscode WORKDIR /home/vscode -# Single-user Nix install — the variant that works in containers without -# systemd / a running daemon. -RUN curl -fsSL https://nixos.org/nix/install | sh -s -- --no-daemon --no-channel-add +# Single-user Nix install — pinned to a specific release for reproducibility +# and supply-chain safety. Update the version when upgrading Nix. +ARG NIX_VERSION=2.28.3 +RUN curl -fsSL "https://releases.nixos.org/nix/nix-${NIX_VERSION}/install" -o /tmp/nix-install \ + && sh /tmp/nix-install --no-daemon --no-channel-add \ + && rm /tmp/nix-install ENV PATH=/home/vscode/.nix-profile/bin:/home/vscode/.npm-global/bin:$PATH