# Nix

This directory contains Nix expressions defining the packages, and containers used to run/build Poseidon.

## Directory Structure

```
nix/
├── packages/                    # Individual Poseidon service packages
│   ├── default.nix              # Entry point - builds all packages with dependencies
│   ├── serverpack.nix
│   ├── dataagent.nix
│   ├── atlantis.nix
│   ├── atlantis-client.nix
│   ├── atlantis-client.json     # Client dependencies metadata
│   ├── atlantis-deps.json       # Atlantis backend dependencies metadata
│   ├── sorcerer.nix
│   └── archivist.nix
├── secrets/                     # Age encrypted files
│   ├── secrets.nix
│   └── *.age
├── containers.nix               # Docker & Singularity container definitions
│   ├── atlantis
│   ├── sorcerer
│   └── archivist
└── pre-commit.nix               # Pre-commit hooks for code quality
```

## Usage

Note: `nix-build` can be switched for `nom-build` for a pretty-printed output (using [Nix Output Monitor](https://github.com/maralorn/nix-output-monitor))

### Secrets

```bash
# To run nix-build
$ set -x NETRC $(agenix -d netrc.age)
```

Secrets used for development and production are stored as `*.age` files and decrypted/encrypted using agenix via ssh-keys.

```bash
# To encrypt
$ agenix -e name.age # And add to secrets.nix

# To decrypt
$ agenix -d name.age
```

In case a new key is added to the `secrets.nix` file we need to re-key the age files with:
```bash
$ agenix -r
```

### Building Individual Packages
```bash
# Build a specific service
$ nix-build -A packages.atlantis
$ nix-build -A packages.sorcerer

# Build all packages
$ nix-build -A packages
```

### Building Container Images
```bash
# Build Docker containers
$ nix-build -A containers.atlantis
$ nix-build -A containers.sorcerer

# Build Singularity container for HPC
$ nix-build -A containers.archivist
```

### Development Shell
```bash
# Enter development environment
$ nix-shell

# Or use a specific package's shell
$ nix-shell -A packages.atlantis
```

### Running Services
```bash
# Run Atlantis server
$ ./result/bin/atlantis

# Run Sorcerer API
$ ./result/bin/sorcerer
```

### Update dependencies

When updating the `npm` dependencies, the `outputHash` in `atlantis-client.nix` needs to be updated. Simply run

```bash
nix-build -A packages.atlantis-client # in the root
```

It will then fail on the wrong hash and provide the correct one.

#### Deterministic builds, vendor hashes, and lock files

Nix aims for deterministic (reproducible) builds. A key part of this is **fixed-output derivations (FODs)** such as `fetchurl`, `buildDotnetModule`’s vendor step, `fetchgit`, etc. For any FOD, Nix requires a **content hash** up front. After the build/fetch runs, Nix verifies that the resulting output’s hash exactly matches what was declared; if it doesn’t, the build fails with a “hash mismatch in fixed-output derivation” error. This protects you from drifting dependencies and ensures that CI and local builds use the exact same inputs.

#### Why vendor hashes need to be pinned

Language ecosystems resolve and download a lot of upstream content (Go modules, npm/yarn, cargo crates, vendored tarballs…). To make those fetches deterministic, Nix needs the **expected content hash**. For example, with `makeDerivation`, you must set `outputHash` so Nix knows what the fully-resolved module tree should hash to. If you bump a version or change dependencies, the **content changes** and the old hash becomes invalid—Nix will (correctly) refuse the build until you update the pinned hash.
