From b033823e763d1457bf639dcfc56a885f66a36f59 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 20:59:03 +0000 Subject: [PATCH] Pin the toolchain with Nix and automate dependency bumps Ports the setup from moq-dev/moq so this repo's tooling and dependencies stop drifting on their own. - flake.nix / flake.lock pin bun, node, and just. nixpkgs and flake-utils are locked to the same revisions moq uses, so the two repos share a toolchain rather than each tracking their own. - .envrc loads that shell through direnv, verbatim from moq. - .github/dependabot.yml groups weekly bun and github-actions updates behind a 7 day cooldown, so a compromised release has time to be yanked before it lands. The cargo and uv ecosystems don't apply here. - .github/workflows/update-flake.yml opens a monthly flake.lock PR, since Dependabot has no nix ecosystem. The pinned nixpkgs ships bun 1.3.13 while the repo pinned 1.3.4, so the dev shell would have disagreed with CI from the first commit: a bare `bun i` on the newer bun rewrites bun.lock. packageManager and pr.yml move to 1.3.13 to match, and the three pins are documented as a set that moves together when update-flake.yml bumps nixpkgs. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019QuBDkctYkSCveimFsCHch --- .envrc | 22 +++++++++++ .github/dependabot.yml | 37 ++++++++++++++++++ .github/workflows/pr.yml | 5 ++- .github/workflows/update-flake.yml | 32 ++++++++++++++++ .gitignore | 5 +++ CLAUDE.md | 8 +++- README.md | 12 +++++- flake.lock | 61 ++++++++++++++++++++++++++++++ flake.nix | 50 ++++++++++++++++++++++++ package.json | 2 +- 10 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 .envrc create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/update-flake.yml create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..76439bd --- /dev/null +++ b/.envrc @@ -0,0 +1,22 @@ +# Automatically load the Nix development shell when entering this directory +# Requires direnv: https://direnv.net/ +# +# To enable: +# 1. Install direnv +# 2. Run: direnv allow +# +# This will automatically install all required dependencies for the project. +if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.0/direnvrc" "sha256-yMJ2OVMzrFaDPn7q8nCBZFRYpL/f0RcHzhmw/i6btJM=" +fi +use_flake + +# Reclaim stale Nix store paths in the background, at most once per week. +# nix-direnv pins the current dev shell, so only older versions are freed. +if has nix-collect-garbage; then + _gc_stamp="$PWD/.direnv/nix-gc-stamp" + if [ ! -f "$_gc_stamp" ] || [ -n "$(find "$_gc_stamp" -mtime +7 2>/dev/null)" ]; then + touch "$_gc_stamp" + (nix-collect-garbage --delete-older-than 7d >/dev/null 2>&1 &) + fi +fi diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ca60fb6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +# +# cooldown.default-days holds back any newly published version until it is at +# least N days old. This buys time for a compromised release (supply-chain +# attack) to be noticed and yanked before we pull it in. Security updates +# bypass the cooldown. It only gates Dependabot-driven updates, not a manual +# `bun update`. +# +# Nix has no Dependabot ecosystem, so flake.lock is bumped by the monthly +# update-flake.yml workflow instead. + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: "bun" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + groups: + bun: + patterns: + - "*" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 4fa2c1d..3f359f1 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -10,9 +10,12 @@ jobs: steps: - uses: actions/checkout@v4 + # Keep in step with the bun in flake.nix (via nixpkgs) and with + # `packageManager` in package.json, so a local `nix develop` shell and CI + # agree on the version that writes bun.lock. - uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.4 + bun-version: 1.3.13 - run: bun install --frozen-lockfile - run: bun run check diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml new file mode 100644 index 0000000..c25e702 --- /dev/null +++ b/.github/workflows/update-flake.yml @@ -0,0 +1,32 @@ +name: Update Flake + +permissions: + contents: write + pull-requests: write + +on: + workflow_dispatch: # Allow manual triggering + schedule: + - cron: '0 12 1 * *' # Run monthly on the 1st at noon UTC + +jobs: + update-flake: + name: Update flake.lock + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@1d87d45818068401a10cf16bdc5f00b24994a83f # main + with: + determinate: false + + - name: Update flake.lock + uses: DeterminateSystems/update-flake-lock@f21d5f4a9e57815a4941a2e7c3860f4664cb3a96 # main + with: + pr-title: "Update flake.lock" + pr-labels: | + dependencies + automated diff --git a/.gitignore b/.gitignore index 82fd71b..a20575a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,11 @@ dist/ .astro/ tsconfig.tsbuildinfo +# Nix / direnv +.direnv/ +result +result-* + # Mac shit .DS_Store diff --git a/CLAUDE.md b/CLAUDE.md index 5a09f0e..18e21ca 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,8 +41,14 @@ just fix # Auto-fix code formatting/lint issues - **Styling**: Tailwind CSS - **Build**: Vite - **Code Quality**: Biome for linting/formatting -- **Package Manager**: bun v1.3.4 +- **Package Manager**: bun v1.3.13 - **Task Runner**: just +- **Toolchain**: pinned in `flake.nix`; `nix develop` (or direnv, via `.envrc`) provides bun, node, and just + +The bun version lives in three places that must agree: `flake.nix` (via +nixpkgs), `packageManager` in `package.json`, and `bun-version` in +`.github/workflows/pr.yml`. When the monthly `update-flake.yml` PR moves +nixpkgs, move the other two to match. ### Key Components diff --git a/README.md b/README.md index b15b74a..5ec9b05 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,17 @@ Join the [Discord](https://discord.moq.dev) for updates and discussion. ## Setup -Install the dependencies with `bun`: +The toolchain (`bun`, `node`, `just`) is pinned in `flake.nix`: + +```bash +nix develop -c just dev +``` + +With [direnv](https://direnv.net/) installed, `direnv allow` loads that shell +automatically on every `cd` into the repo. + +Don't have Nix? Install `bun` and `just` yourself, matching the `bun` version in +`packageManager`. Either way, the dependencies come from `bun`: ```bash bun i diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bf64e52 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "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" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1787964612, + "narHash": "sha256-0N9nghg3nwzX6b6qc77EzjR9cu/Z+UR66FlfsCqiURs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e8be7818e19ada32105a8af937a6a473b38167ca", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d5df627 --- /dev/null +++ b/flake.nix @@ -0,0 +1,50 @@ +{ + description = "moq.dev - the blog, moq.pub, and moq.watch"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + nixpkgs, + flake-utils, + ... + }: + flake-utils.lib.eachSystem + [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + ] + ( + system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + # Everything in the justfile runs through bun: astro, vite, biome, + # tsc, and wrangler are all `bun run` or `bunx`. + # + # This is the version `packageManager` and pr.yml pin to. A bare + # `bun i` on a newer bun rewrites bun.lock, which is noise in a + # diff, so the three pins are kept in step. `nix flake update` + # moving bun is the signal to move the other two. + bun + + # Astro and Vite target node, and parts of their toolchains shell + # out to it rather than to bun. + nodejs_24 + + # The task runner every recipe in the justfile is written for. + just + ]; + }; + + formatter = pkgs.nixfmt-tree; + } + ); +} diff --git a/package.json b/package.json index 6665138..6cfc7b3 100644 --- a/package.json +++ b/package.json @@ -38,5 +38,5 @@ "vite-plugin-static-copy": "^2.3.2", "wrangler": "^4.100.0" }, - "packageManager": "bun@1.3.4" + "packageManager": "bun@1.3.13" }