cesr-rs 0.2.0

CESR + KERI primitives for Rust as a single feature-gated, no_std-capable crate
Documentation
{
  description = "cesr — CESR + KERI primitives for Rust (single feature-gated crate)";
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    utils.url = "github:numtide/flake-utils";
    crane.url = "github:ipetkov/crane";
    fenix = {
      url = "github:nix-community/fenix";
      inputs = {
        nixpkgs.follows = "nixpkgs";
      };
    };
    advisory-db = {
      url = "github:rustsec/advisory-db";
      flake = false;
    };
  };
  outputs =
    {
      self,
      nixpkgs,
      utils,
      crane,
      fenix,
      advisory-db,
      ...
    }:
    utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};

        # Pinned STABLE toolchain read from rust-toolchain.toml (nexus pattern).
        # sha256 hashes the channel manifest (platform-independent) — reused
        # from nexus since cesr pins the SAME 1.95.0 channel.
        rustToolchain = fenix.packages.${system}.fromToolchainFile {
          file = ./rust-toolchain.toml;
          sha256 = "sha256-gh/xTkxKHL4eiRXzWv8KP7vfjSk61Iq48x47BEDFgfk=";
        };
        craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;

        # Crane's `cleanCargoSource` keeps only `.rs`/`.toml`/`Cargo.lock`, which
        # would strip the keripy differential corpus under `tests/corpus/keripy/**`
        # (`.jsonl`). The diff harness embeds those via `include_str!` at compile
        # time, so they MUST reach the sandbox — keep everything crane keeps PLUS
        # any file under a `tests/corpus/` directory.
        src = pkgs.lib.cleanSourceWith {
          src = ./.;
          name = "cesr-source";
          filter =
            path: type:
            (craneLib.filterCargoSources path type) || (pkgs.lib.hasInfix "/tests/corpus/" (toString path));
        };

        # Source for the isolated `fuzz/` workspace check. Crane's default
        # `cleanCargoSource` keeps only `.rs`/`.toml`/`Cargo.lock`, which would
        # strip the committed corpus seed files under `fuzz/tests/__fuzz__/**`
        # (they have no extension). bolero's DefaultEngine replays those seeds,
        # so they MUST reach the sandbox. This filter keeps everything crane
        # would keep PLUS any file living under a `__fuzz__` corpus directory.
        fuzzSrc = pkgs.lib.cleanSourceWith {
          src = ./.;
          name = "cesr-fuzz-source";
          filter =
            path: type:
            (craneLib.filterCargoSources path type) || (pkgs.lib.hasInfix "/tests/__fuzz__/" (toString path));
        };

        # The fuzz workspace has its OWN Cargo.lock (bolero + cesr path dep).
        # Vendor it separately so the check builds offline/hermetically without
        # touching the root crate's vendored deps.
        fuzzCargoArtifacts = craneLib.vendorCargoDeps { cargoLock = ./fuzz/Cargo.lock; };

        commonArgs = {
          inherit src;
          strictDeps = true;
          buildInputs = with pkgs; [ openssl ];
          nativeBuildInputs = with pkgs; [
            cmake
            pkg-config
          ];
          cargoExtraArgs = "--all-features";
        };
        cargoArtifacts = craneLib.buildDepsOnly commonArgs;

        # Repo-hygiene gate: a tiny sandboxed derivation that runs one linter and
        # succeeds (touch $out) only if it does. Keeps the seven non-cargo checks
        # below to one line each. Each was verified green before being wired —
        # never gate on a linter you haven't watched pass.
        lintCheck =
          name: nativeBuildInputs: script:
          pkgs.runCommandLocal name { inherit nativeBuildInputs; } ''
            ${script}
            touch $out
          '';
      in
      with pkgs;
      {
        checks = {
          # ---- Rust / cargo (via crane) ----
          cesr-clippy = craneLib.cargoClippy (
            commonArgs
            // {
              inherit cargoArtifacts;
              cargoClippyExtraArgs = "--all-targets -- --deny warnings";
            }
          );
          cesr-doc = craneLib.cargoDoc (commonArgs // { inherit cargoArtifacts; });
          cesr-fmt = craneLib.cargoFmt { inherit src; };
          cesr-toml-fmt = craneLib.taploFmt {
            src = pkgs.lib.sources.sourceFilesBySuffices src [ ".toml" ];
          };
          cesr-audit = craneLib.cargoAudit { inherit src advisory-db; };
          cesr-deny = craneLib.cargoDeny { inherit src; };
          cesr-nextest = craneLib.cargoNextest (
            commonArgs
            // {
              inherit cargoArtifacts;
              partitions = 1;
              partitionType = "count";
            }
          );
          cesr-doctest = craneLib.cargoDocTest (commonArgs // { inherit cargoArtifacts; });

          cesr-wasm = craneLib.mkCargoDerivation (
            commonArgs
            // {
              inherit cargoArtifacts;
              pnameSuffix = "-wasm";
              buildPhaseCargoCommand = ''
                cargo build --target wasm32-unknown-unknown \
                  --no-default-features --features alloc,core,utils,keri,serder,crypto,stream
              '';
            }
          );
          cesr-nostd = craneLib.mkCargoDerivation (
            commonArgs
            // {
              inherit cargoArtifacts;
              pnameSuffix = "-nostd";
              buildPhaseCargoCommand = ''
                cargo build --no-default-features --features alloc,core,utils,keri
              '';
            }
          );

          # Deterministic corpus-replay + bounded-random fuzz gate. Runs the
          # bolero `check!` targets in the isolated `fuzz/` workspace via plain
          # `cargo test` on the pinned STABLE toolchain (bolero's DefaultEngine
          # needs no nightly; sanitizers — which do — live in a separate
          # scheduled GitHub workflow). The source carries both the parent crate
          # (so the `cesr = { path = ".." }` dep compiles) and `fuzz/` with its
          # committed corpus seeds; `fuzzCargoArtifacts` vendors the fuzz
          # workspace's own Cargo.lock so the build is fully offline/hermetic.
          cesr-fuzz-replay = craneLib.mkCargoDerivation (
            commonArgs
            // {
              src = fuzzSrc;
              cargoVendorDir = fuzzCargoArtifacts;
              cargoArtifacts = null;
              pnameSuffix = "-fuzz-replay";
              # bolero discovers corpus relative to CARGO_MANIFEST_DIR; run from
              # the fuzz workspace root so `tests/__fuzz__/**` resolves.
              buildPhaseCargoCommand = ''
                (cd fuzz && cargo test --no-fail-fast)
              '';
            }
          );

          # ---- Repo hygiene (non-cargo) ----
          # GitHub Actions workflows — the check the pre-commit hook advertises.
          # shellcheck on PATH lets actionlint also vet inline `run:` scripts.
          cesr-actionlint = lintCheck "cesr-actionlint" [
            actionlint
            shellcheck
          ] "actionlint -color ${./.github/workflows}/*.yml";

          # All other YAML (Dependabot, issue-template config) — actionlint only
          # covers workflows, so this catches the rest (duplicate keys, indent).
          cesr-yaml = lintCheck "cesr-yaml" [
            yamllint
          ] "yamllint -c ${./.yamllint.yml} ${./.github} ${./.yamllint.yml}";

          # The git hooks are bash — shellcheck them so a broken hook can't land.
          cesr-shellcheck = lintCheck "cesr-shellcheck" [ shellcheck ] "shellcheck ${./.githooks}/*";

          # Nix formatting + dead-code, so the flake holds itself to the same bar
          # it holds the Rust to. (statix is in the dev shell for local linting;
          # it isn't gated because its single-file check is unreliable sandboxed.)
          cesr-deadnix = lintCheck "cesr-deadnix" [ deadnix ] "deadnix --fail ${./flake.nix}";
          cesr-nixfmt = lintCheck "cesr-nixfmt" [ nixfmt ] "nixfmt --check ${./flake.nix}";

          # Spell-check prose + identifiers (domain terms allowlisted in
          # _typos.toml; opaque test-vector files excluded).
          cesr-typos = lintCheck "cesr-typos" [ typos ] "typos --config ${./_typos.toml} ${./.}";
        };

        # `nix fmt` formats the flake with the same tool the gate checks.
        formatter = nixfmt;

        devShells.default = craneLib.devShell {
          checks = self.checks.${system};
          # Point git at the tracked hooks, then greet with the same figlet +
          # lolcat + cowsay banner nexus uses — one shared dev-shell ritual.
          shellHook = ''
            git config core.hooksPath .githooks
            figlet -f doom "Cesr" | lolcat -a -d 2
            cowsay -f dragon-and-cow "Welcome to the Cesr dev environment on ${system}!" | lolcat
          '';
          packages = [
            # Rust toolchain extras
            fenix.packages.${system}.rust-analyzer
            just
            bacon
            cargo-edit
            cargo-expand
            cargo-nextest
            cargo-llvm-cov
            cargo-mutants
            cargo-machete
            cargo-outdated
            cargo-semver-checks
            cargo-hack
            cargo-audit
            cargo-deny
            taplo
            # CI / lint parity with `nix flake check`
            actionlint
            shellcheck
            yamllint
            typos
            # statix 0.5.8 (this nixpkgs rev) fails its own insta snapshot
            # tests during build; skip them — the binary itself is fine and
            # statix is dev-shell-only (not part of `nix flake check`).
            (statix.overrideAttrs (_: {
              doCheck = false;
            }))
            deadnix
            nixfmt
            # Supply-chain / commit signing
            gnupg
            # General dev ergonomics
            git
            gh
            jq
            yq-go
            ripgrep
            fd
            tree
            cloc
            tmux
            # Banner glamour (nexus parity)
            figlet
            lolcat
            cowsay
          ];
        };
      }
    );
}