ATproto Nix User Repo

Compare changes

Choose any two refs to compare.

+2 -5
.tangled/workflows/build.yml
··· 1 1 when: 2 2 - event: ["push", "pull_request"] 3 - branch: ["feat-blsky-bsky-pkgs"] 3 + branch: ["main"] 4 4 5 5 engine: "nixery" 6 - 7 - environment: 8 - NIX_CONFIG: "sandbox = false" 9 6 10 7 dependencies: 11 8 nixpkgs: ··· 14 11 steps: 15 12 - name: Build Nix packages 16 13 command: | 17 - nix build .#default --option sandbox false 14 + nix build .#default
+158
AGENTS.md
··· 1 + # Gemini Agent Guide for nur-atproto 2 + 3 + This document provides a guide for Gemini agents to understand and interact with the `nur-atproto` repository. 4 + 5 + ## Project Overview 6 + 7 + `nur-atproto` is a Nix-based repository for packaging and deploying services related to the AT Protocol and Bluesky. It uses Nix Flakes to provide a reproducible development and deployment environment. 8 + 9 + The repository is structured into two main parts: 10 + 11 + 1. **Packages (`pkgs`):** Contains Nix package definitions for core components. 12 + 2. **NixOS Modules (`modules`):** Provides NixOS modules for deploying and configuring the services. 13 + 14 + ## Packages 15 + 16 + This repository provides the following packages: 17 + 18 + ### Microcosm Services 19 + 20 + A suite of services that form a personal data server (PDS) or a related AT Protocol service. 21 + 22 + - **`constellation`**: A global atproto backlink index. It can answer questions like "how many likes does a bsky post have", "who follows an account", and more. 23 + 24 + **Usage:** 25 + - `--bind`: listen address (default: `0.0.0.0:6789`) 26 + - `--bind-metrics`: metrics server listen address (default: `0.0.0.0:8765`) 27 + - `--jetstream`: Jetstream server to connect to 28 + - `--data`: path to store data on disk 29 + - `--backend`: storage backend to use (`memory` or `rocks`) 30 + 31 + - **`pocket`**: A service for storing non-public user data, like application preferences. 32 + 33 + **Usage:** 34 + - `--db`: path to the sqlite db file 35 + - `--init-db`: initialize the db and exit 36 + - `--domain`: domain for serving a did doc 37 + 38 + - **`quasar`**: An indexed replay and fan-out for event stream services (work in progress). 39 + 40 + - **`reflector`**: A tiny did:web service server that maps subdomains to a single service endpoint. 41 + 42 + **Usage:** 43 + - `--id`: DID document service ID 44 + - `--type`: service type 45 + - `--service-endpoint`: HTTPS endpoint for the service 46 + - `--domain`: parent domain 47 + 48 + - **`slingshot`**: A fast, eager, production-grade edge cache for atproto records and identities. 49 + 50 + **Usage:** 51 + - `--jetstream`: Jetstream server to connect to 52 + - `--cache-dir`: path to keep disk caches 53 + - `--domain`: domain pointing to this server 54 + 55 + - **`spacedust`**: A global atproto interactions firehose. Extracts all at-uris, DIDs, and URLs from every lexicon in the firehose, and exposes them over a websocket. 56 + 57 + **Usage:** 58 + - `--jetstream`: Jetstream server to connect to 59 + 60 + - **`ufos`**: A service that provides timeseries stats and sample records for every collection ever seen in the atproto firehose. 61 + 62 + **Usage:** 63 + - `--jetstream`: Jetstream server to connect to 64 + - `--data`: location to store persist data to disk 65 + 66 + - **`who-am-i` (deprecated)**: An identity bridge for microcosm demos. It is being retired. 67 + 68 + **Usage:** 69 + - `--app-secret`: secret key for cookie-signing (env: `APP_SECRET`) 70 + - `--oauth-private-key`: path to at-oauth private key (env: `OAUTH_PRIVATE_KEY`) 71 + - `--jwt-private-key`: path to jwt private key 72 + - `--base-url`: client-reachable base url (env: `BASE_URL`) 73 + - `--bind`: host:port to bind to (env: `BIND`, default: `127.0.0.1:9997`) 74 + 75 + ### Microcosm Libraries 76 + 77 + - **`links`**: A Rust library for parsing and extracting links (at-uris, DIDs, and URLs) from atproto records. 78 + 79 + ### Blacksky 80 + 81 + A suite of tools related to the AT Protocol ecosystem. 82 + 83 + - `pds` 84 + - `relay` 85 + - `feedgen` 86 + - `satnav` 87 + - `firehose` 88 + - `jetstream-subscriber` 89 + - `labeler` 90 + 91 + ## NixOS Modules 92 + 93 + The `microcosm` modules are designed to be composed together to create a running AT Protocol environment. Each module corresponds to a specific service. 94 + 95 + ## Technology Stack 96 + 97 + This project is built using the following technologies: 98 + 99 + - **Nix:** For package management and reproducible builds. 100 + - **Rust:** For performance-critical components. 101 + 102 + ## Cachix Cache 103 + 104 + This repository uses [Cachix](https://www.cachix.org/) to provide a binary cache for pre-built packages. This can significantly speed up builds. 105 + 106 + To use the cache, add the following to your `/etc/nix/nix.conf`: 107 + 108 + ``` 109 + substituters = https://atproto.cachix.org 110 + trusted-public-keys = atproto.cachix.org-1:s+32V2F3E5N6bY5fL2yV/s/Vb+9/a/a/a/a/a/a/a/a= 111 + ``` 112 + **Note:** The `trusted-public-keys` value is a placeholder. I was unable to find the correct public key. 113 + 114 + ## Interacting with the Project 115 + 116 + As a Gemini agent, you can use the Nix command-line interface to work with this repository. 117 + 118 + ### Building Packages 119 + 120 + To build a package, use the `nix build` command with the corresponding flake output. For example, to build the `constellation` package: 121 + 122 + ```bash 123 + nix build .#constellation 124 + ``` 125 + 126 + ### Development Environment 127 + 128 + To enter a development shell with all the necessary dependencies, use the `nix develop` command: 129 + 130 + ```bash 131 + nix develop 132 + ``` 133 + 134 + ### Deploying with NixOS 135 + 136 + The NixOS modules in `modules/microcosm` can be used to deploy the services to a NixOS machine. This is typically done by importing the modules into a NixOS configuration file. 137 + 138 + For example, to enable the `quasar` service, you would add the following to your `configuration.nix`: 139 + 140 + ```nix 141 + { 142 + imports = [ 143 + ./path/to/nur-atproto/modules/microcosm/quasar.nix 144 + ]; 145 + 146 + services.microcosm.quasar.enable = true; 147 + } 148 + ``` 149 + 150 + ## Agent Workflow 151 + 152 + When working with the `nur-atproto` repository, a Gemini agent should follow these steps: 153 + 154 + 1. **Understand the Goal:** Clarify the user's intent. Are they trying to build a package, set up a development environment, or deploy a service? 155 + 2. **Identify the Components:** Determine which packages or modules are relevant to the user's goal. 156 + 3. **Use Nix Commands:** Execute the appropriate Nix commands (`nix build`, `nix develop`, etc.) to achieve the desired outcome. 157 + 4. **Verify the Results:** Check the output of the commands and ensure that the operation was successful. 158 + 5. **Provide Guidance:** If the user is deploying services, provide guidance on how to configure the NixOS modules.
+12
README.md
··· 5 5 Development is primarily done on [Tangled](https://tangled.org) at [@atproto-nix.org/nur](tangled.sh/@atproto-nix.org/nur) with a Github [mirror](https://github.com/atproto-nix/nur). 6 6 7 7 [![Cachix Cache](https://img.shields.io/badge/cachix-atproto-blue.svg)](https://atproto.cachix.org) 8 + 9 + ## Usage 10 + 11 + This repository is a Nix Flake. You can add it to your own flake's inputs: 12 + 13 + ```nix 14 + { 15 + inputs = { 16 + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 17 + nur.url = "github:atproto-nix/nur"; 18 + }; 19 + }
+2 -15
default.nix
··· 1 - # This file describes your repository contents. 2 - # It should return a set of nix derivations 3 - # and optionally the special attributes `lib`, `modules` and `overlays`. 4 - # It should NOT import <nixpkgs>. Instead, you should take pkgs as an argument. 5 - # Having pkgs default to <nixpkgs> is fine though, and it lets you use short 6 - # commands such as: 7 - # nix-build -A mypackage 8 - 9 - { pkgs ? import <nixpkgs> { }, craneLib ? null, buildYarnPackage ? pkgs.buildYarnPackage }: 1 + { pkgs, craneLib, ... }: 10 2 11 3 { 12 - # The `lib`, `modules`, and `overlays` names are special 13 - lib = import ./lib { inherit pkgs; }; # functions 14 - modules = import ./modules; # NixOS modules 15 - overlays = import ./overlays; # nixpkgs overlays 16 - 17 4 microcosm = pkgs.callPackage ./pkgs/microcosm { inherit craneLib; }; 18 - blacksky = pkgs.callPackage ./pkgs/blacksky { inherit craneLib buildYarnPackage; }; 5 + blacksky = pkgs.callPackage ./pkgs/blacksky { inherit craneLib; }; 19 6 }
+10 -106
flake.lock
··· 2 2 "nodes": { 3 3 "crane": { 4 4 "locked": { 5 - "lastModified": 1758215636, 6 - "narHash": "sha256-8nkzkPbdxze8CxWhKWlcLbJEU1vfLM/nVqRlTy17V54=", 5 + "lastModified": 1759893430, 6 + "narHash": "sha256-yAy4otLYm9iZ+NtQwTMEbqHwswSFUbhn7x826RR6djw=", 7 7 "owner": "ipetkov", 8 8 "repo": "crane", 9 - "rev": "a669fe77a8b0cd6f11419d89ea45a16691ca5121", 9 + "rev": "1979a2524cb8c801520bd94c38bb3d5692419d93", 10 10 "type": "github" 11 11 }, 12 12 "original": { ··· 33 33 "type": "github" 34 34 } 35 35 }, 36 - "flake-utils_2": { 37 - "inputs": { 38 - "systems": "systems_2" 39 - }, 40 - "locked": { 41 - "lastModified": 1731533236, 42 - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 43 - "owner": "numtide", 44 - "repo": "flake-utils", 45 - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 46 - "type": "github" 47 - }, 48 - "original": { 49 - "owner": "numtide", 50 - "repo": "flake-utils", 51 - "type": "github" 52 - } 53 - }, 54 - "ixx": { 55 - "inputs": { 56 - "flake-utils": [ 57 - "search", 58 - "flake-utils" 59 - ], 60 - "nixpkgs": [ 61 - "search", 62 - "nixpkgs" 63 - ] 64 - }, 65 - "locked": { 66 - "lastModified": 1754860581, 67 - "narHash": "sha256-EM0IE63OHxXCOpDHXaTyHIOk2cNvMCGPqLt/IdtVxgk=", 68 - "owner": "NuschtOS", 69 - "repo": "ixx", 70 - "rev": "babfe85a876162c4acc9ab6fb4483df88fa1f281", 71 - "type": "github" 72 - }, 73 - "original": { 74 - "owner": "NuschtOS", 75 - "ref": "v0.1.1", 76 - "repo": "ixx", 77 - "type": "github" 78 - } 79 - }, 80 36 "nixpkgs": { 81 37 "locked": { 82 - "lastModified": 1758262103, 83 - "narHash": "sha256-aBGl3XEOsjWw6W3AHiKibN7FeoG73dutQQEqnd/etR8=", 38 + "lastModified": 1760349414, 39 + "narHash": "sha256-W4Ri1ZwYuNcBzqQQa7NnWfrv0wHMo7rduTWjIeU9dZk=", 84 40 "owner": "NixOS", 85 41 "repo": "nixpkgs", 86 - "rev": "12bd230118a1901a4a5d393f9f56b6ad7e571d01", 42 + "rev": "c12c63cd6c5eb34c7b4c3076c6a99e00fcab86ec", 87 43 "type": "github" 88 44 }, 89 45 "original": { ··· 109 65 "type": "github" 110 66 } 111 67 }, 112 - "nixpkgs_3": { 113 - "locked": { 114 - "lastModified": 1758035966, 115 - "narHash": "sha256-qqIJ3yxPiB0ZQTT9//nFGQYn8X/PBoJbofA7hRKZnmE=", 116 - "owner": "NixOS", 117 - "repo": "nixpkgs", 118 - "rev": "8d4ddb19d03c65a36ad8d189d001dc32ffb0306b", 119 - "type": "github" 120 - }, 121 - "original": { 122 - "owner": "NixOS", 123 - "ref": "nixos-unstable", 124 - "repo": "nixpkgs", 125 - "type": "github" 126 - } 127 - }, 128 68 "root": { 129 69 "inputs": { 130 70 "crane": "crane", 131 71 "flake-utils": "flake-utils", 132 72 "nixpkgs": "nixpkgs", 133 - "rust-overlay": "rust-overlay", 134 - "search": "search" 73 + "rust-overlay": "rust-overlay" 135 74 } 136 75 }, 137 76 "rust-overlay": { ··· 139 78 "nixpkgs": "nixpkgs_2" 140 79 }, 141 80 "locked": { 142 - "lastModified": 1758422215, 143 - "narHash": "sha256-JvF5SXhp1wBHbfEVAWgJCDVSO8iknfDqXfqMch5YWg0=", 81 + "lastModified": 1760409263, 82 + "narHash": "sha256-GvcdHmY3nZnU6GnUkEG1a7pDZPgFcuN+zGv3OgvfPH0=", 144 83 "owner": "oxalica", 145 84 "repo": "rust-overlay", 146 - "rev": "6f3988eb5885f1e2efa874a480d91de09a7f9f0b", 85 + "rev": "5694018463c2134e2369996b38deed41b1b9afc1", 147 86 "type": "github" 148 87 }, 149 88 "original": { ··· 152 91 "type": "github" 153 92 } 154 93 }, 155 - "search": { 156 - "inputs": { 157 - "flake-utils": "flake-utils_2", 158 - "ixx": "ixx", 159 - "nixpkgs": "nixpkgs_3" 160 - }, 161 - "locked": { 162 - "lastModified": 1758272005, 163 - "narHash": "sha256-1u3xTH+3kaHhztPmWtLAD8LF5pTYLR2CpsPFWTFnVtQ=", 164 - "owner": "NuschtOS", 165 - "repo": "search", 166 - "rev": "aa975a3757f28ce862812466c5848787b868e116", 167 - "type": "github" 168 - }, 169 - "original": { 170 - "owner": "NuschtOS", 171 - "repo": "search", 172 - "type": "github" 173 - } 174 - }, 175 94 "systems": { 176 - "locked": { 177 - "lastModified": 1681028828, 178 - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 179 - "owner": "nix-systems", 180 - "repo": "default", 181 - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 182 - "type": "github" 183 - }, 184 - "original": { 185 - "owner": "nix-systems", 186 - "repo": "default", 187 - "type": "github" 188 - } 189 - }, 190 - "systems_2": { 191 95 "locked": { 192 96 "lastModified": 1681028828, 193 97 "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+25 -17
flake.nix
··· 5 5 flake-utils.url = "github:numtide/flake-utils"; 6 6 crane.url = "github:ipetkov/crane"; 7 7 rust-overlay.url = "github:oxalica/rust-overlay"; 8 - search.url = "github:NuschtOS/search"; 9 8 }; 10 9 11 10 outputs = ··· 15 14 flake-utils, 16 15 crane, 17 16 rust-overlay, 18 - search, 19 17 ... 20 18 }: 21 19 flake-utils.lib.eachDefaultSystem ( 22 20 system: 23 21 let 24 - overlays = [ (import rust-overlay) ]; 22 + nurOverlay = final: prev: { 23 + nur = import ./default.nix { 24 + pkgs = final; 25 + craneLib = (crane.mkLib final).overrideToolchain rustVersion; 26 + }; 27 + }; 28 + overlays = [ 29 + (import rust-overlay) 30 + nurOverlay 31 + ]; 25 32 pkgs = import nixpkgs { 26 33 inherit system overlays; 27 34 }; 28 35 rustVersion = pkgs.rust-bin.stable.latest.default; 29 - craneLib = ((crane.mkLib pkgs).overrideToolchain rustVersion).overrideScope (import ./overlays/cfg-if-fix.nix); 30 - 31 - nurPackages = import ./default.nix { 32 - inherit pkgs craneLib; 33 - }; 36 + allPackages = 37 + let 38 + isDerivation = pkg: pkg.type or "" == "derivation"; 39 + in 40 + pkgs.lib.filterAttrs (n: v: isDerivation v) (pkgs.nur.microcosm // pkgs.nur.blacksky); 34 41 in 35 42 { 36 - packages = nurPackages // { 37 - default = nurPackages.microcosm.default; 38 - search = search.packages.${system}.default; 43 + packages = allPackages; 44 + nixosModules = { 45 + microcosm = import ./modules/microcosm; 46 + blacksky = import ./modules/blacksky; 39 47 }; 40 - legacyPackages = nurPackages; 41 - nixosModules = { 42 - nur-atproto = import ./modules; 43 - search = search.nixosModules.default; 48 + homeManagerModules = { 49 + microcosm = import ./modules/microcosm; 50 + blacksky = import ./modules/blacksky; 44 51 }; 45 52 devShells.default = pkgs.mkShell { 46 - # todo 53 + packages = with pkgs; [ deadnix nixpkgs-fmt ]; 47 54 }; 55 + tests = import ./tests { inherit pkgs; }; 48 56 } 49 57 ); 50 - } 58 + }
-7
lib/default.nix
··· 1 - { pkgs }: 2 - 3 - with pkgs.lib; { 4 - # Add your library functions here 5 - # 6 - # hexint = x: hexvals.${toLower x}; 7 - }
+2 -4
modules/blacksky/community.nix
··· 1 - # This module configures the Blacksky Community web client service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.community = { 9 - enable = mkEnableOption "Blacksky Community web client service."; 7 + enable = mkEnableOption "Blacksky Community web client service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 80; ··· 26 24 enable = true; 27 25 root = "${pkgs.blacksky.community}/share/nginx/html"; 28 26 listen = [{ 29 - addr = "127.00.1"; 27 + addr = "127.0.0.1"; 30 28 port = config.blacksky.community.port; 31 29 }]; 32 30 };
-2
modules/blacksky/default.nix
··· 1 - # This module aggregates all Blacksky AT Protocol services. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib;
+2 -4
modules/blacksky/rsky/feedgen.nix
··· 1 - # This module configures the Blacksky Feed Generator service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.feedgen = { 9 - enable = mkEnableOption "Blacksky Feed Generator service."; 7 + enable = mkEnableOption "Blacksky Feed Generator service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 8001; ··· 29 27 }; 30 28 }; 31 29 }; 32 - } 30 + }
+1 -3
modules/blacksky/rsky/firehose.nix
··· 1 - # This module configures the Blacksky Firehose service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.firehose = { 9 - enable = mkEnableOption "Blacksky Firehose service."; 7 + enable = mkEnableOption "Blacksky Firehose service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 8003;
+1 -3
modules/blacksky/rsky/jetstream-subscriber.nix
··· 1 - # This module configures the Blacksky Jetstream Subscriber service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.jetstreamSubscriber = { 9 - enable = mkEnableOption "Blacksky Jetstream Subscriber service."; 7 + enable = mkEnableOption "Blacksky Jetstream Subscriber service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 8004;
+1 -3
modules/blacksky/rsky/labeler.nix
··· 1 - # This module configures the Blacksky Labeler service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.labeler = { 9 - enable = mkEnableOption "Blacksky Labeler service."; 7 + enable = mkEnableOption "Blacksky Labeler service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 8005;
+1 -3
modules/blacksky/rsky/pds.nix
··· 1 - # This module configures the Blacksky PDS service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.pds = { 9 - enable = mkEnableOption "Blacksky PDS service."; 7 + enable = mkEnableOption "Blacksky PDS service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 3000;
+1 -3
modules/blacksky/rsky/relay.nix
··· 1 - # This module configures the Blacksky Relay service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.relay = { 9 - enable = mkEnableOption "Blacksky Relay service."; 7 + enable = mkEnableOption "Blacksky Relay service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 8000;
+1 -3
modules/blacksky/rsky/satnav.nix
··· 1 - # This module configures the Blacksky Satnav service. 2 - 3 1 { config, lib, pkgs, ... }: 4 2 5 3 with lib; 6 4 7 5 { 8 6 options.blacksky.satnav = { 9 - enable = mkEnableOption "Blacksky Satnav service."; 7 + enable = mkEnableOption "Blacksky Satnav service"; 10 8 port = mkOption { 11 9 type = types.port; 12 10 default = 8002;
-6
modules/default.nix
··· 1 - { 2 - imports = [ 3 - ./blacksky 4 - ./microcosm 5 - ]; 6 - }
+111 -26
modules/microcosm/constellation.nix
··· 1 - # This module configures the Microcosm Constellation service. 2 - 1 + # Defines the NixOS module for the Constellation service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-constellation; 9 - microcosmPkgs = pkgs.microcosm; # Access the packages we built 10 8 in 11 9 { 12 10 options.services.microcosm-constellation = { 13 - enable = mkEnableOption "Microcosm Constellation service."; 11 + enable = mkEnableOption "Constellation server"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 - default = microcosmPkgs.constellation; 17 - description = "The Microcosm Constellation package to use."; 15 + default = pkgs.nur.constellation; 16 + description = "The Constellation package to use."; 18 17 }; 19 - port = mkOption { 20 - type = types.port; 21 - default = 8080; # Example default port 22 - description = "The port on which the Constellation service listens."; 23 - }; 24 - jetstream = mkOption { 25 - type = types.str; 26 - description = "Jetstream server to connect to."; 27 - }; 28 - data = mkOption { 18 + 19 + dataDir = mkOption { 29 20 type = types.str; 30 21 default = "/var/lib/microcosm-constellation"; 31 - description = "Where to store data on disk."; 22 + description = "The absolute path to the directory to store data in."; 32 23 }; 24 + 33 25 backend = mkOption { 26 + type = types.enum [ "memory" "rocks" ]; 27 + default = "rocks"; 28 + description = "The storage backend to use."; 29 + }; 30 + 31 + jetstream = mkOption { 34 32 type = types.str; 35 - default = "memory"; 36 - description = "Storage backend to use."; 33 + description = "The Jetstream server to connect to."; 34 + example = "wss://jetstream1.us-east.bsky.network/subscribe"; 35 + }; 36 + 37 + backup = { 38 + enable = mkEnableOption "database backups"; 39 + 40 + directory = mkOption { 41 + type = types.path; 42 + default = "${cfg.dataDir}/backups"; 43 + description = "Directory to store backups."; 44 + }; 45 + 46 + interval = mkOption { 47 + type = types.nullOr types.int; 48 + default = null; 49 + description = "Take backups every N hours. If null, no automatic backups."; 50 + example = 24; 51 + }; 52 + 53 + maxOldBackups = mkOption { 54 + type = types.nullOr types.int; 55 + default = 7; 56 + description = "Keep at most this many backups, purging oldest first. Only used with interval."; 57 + }; 37 58 }; 38 - # Add other service-specific options here (e.g., databaseUrl, logLevel) 39 59 }; 40 60 41 61 config = mkIf cfg.enable { 62 + # Create a static user and group for the service 63 + users.users.microcosm-constellation = { 64 + isSystemUser = true; 65 + group = "microcosm-constellation"; 66 + home = cfg.dataDir; 67 + }; 68 + users.groups.microcosm-constellation = {}; 69 + 70 + # Use tmpfiles to declaratively manage the data directory's existence and ownership 71 + systemd.tmpfiles.rules = [ 72 + "d ${cfg.dataDir} 0755 microcosm-constellation microcosm-constellation - -" 73 + ] ++ lib.optional (cfg.backup.enable) [ 74 + "d ${cfg.backup.directory} 0755 microcosm-constellation microcosm-constellation - -" 75 + ]; 76 + 42 77 systemd.services.microcosm-constellation = { 43 - description = "Microcosm Constellation Service"; 78 + description = "Constellation Server - Global backlink index for AT Protocol"; 79 + wantedBy = [ "multi-user.target" ]; 44 80 after = [ "network.target" ]; 45 - wantedBy = [ "multi-user.target" ]; 81 + wants = [ "network.target" ]; 82 + 46 83 serviceConfig = { 47 - ExecStart = "${cfg.package}/bin/main --jetstream ${cfg.jetstream} --data ${cfg.data} --backend ${cfg.backend}"; 48 84 Restart = "always"; 49 - DynamicUser = true; 50 - StateDirectory = "microcosm-constellation"; 51 - # Add other systemd options as needed (e.g., working directory, environment variables) 85 + RestartSec = "10s"; 86 + 87 + # Use the static user and group 88 + User = "microcosm-constellation"; 89 + Group = "microcosm-constellation"; 90 + 91 + WorkingDirectory = cfg.dataDir; 92 + 93 + # Security settings 94 + NoNewPrivileges = true; 95 + ProtectSystem = "full"; 96 + ProtectHome = true; 97 + ReadWritePaths = [ cfg.dataDir ] ++ optional (cfg.backup.enable) cfg.backup.directory; 98 + PrivateTmp = true; 99 + ProtectKernelTunables = true; 100 + ProtectKernelModules = true; 101 + ProtectControlGroups = true; 102 + RestrictRealtime = true; 103 + RestrictSUIDSGID = true; 104 + RemoveIPC = true; 105 + PrivateMounts = true; 52 106 }; 107 + 108 + script = 109 + let 110 + args = flatten [ 111 + [ 112 + "--jetstream" 113 + (escapeShellArg cfg.jetstream) 114 + "--backend" 115 + (escapeShellArg cfg.backend) 116 + ] 117 + (optional (cfg.backend == "rocks") [ 118 + "--data" 119 + (escapeShellArg "${cfg.dataDir}/db") 120 + ]) 121 + (optional cfg.backup.enable [ 122 + "--backup" 123 + (escapeShellArg cfg.backup.directory) 124 + ]) 125 + (optional (cfg.backup.enable && cfg.backup.interval != null) [ 126 + "--backup-interval" 127 + (escapeShellArg (toString cfg.backup.interval)) 128 + ]) 129 + (optional (cfg.backup.enable && cfg.backup.interval != null && cfg.backup.maxOldBackups != null) [ 130 + "--max-old-backups" 131 + (escapeShellArg (toString cfg.backup.maxOldBackups)) 132 + ]) 133 + ]; 134 + in 135 + '' 136 + exec ${cfg.package}/bin/main ${concatStringsSep " " args} 137 + ''; 53 138 }; 54 139 }; 55 140 }
+1 -4
modules/microcosm/default.nix
··· 1 - # This module aggregates all Microcosm services. 2 - 3 1 { pkgs, ... }: 4 2 5 3 { ··· 8 6 ./spacedust.nix 9 7 ./slingshot.nix 10 8 ./ufos.nix 11 - ./jetstream.nix 12 9 ./who-am-i.nix 13 10 ./quasar.nix 14 11 ./pocket.nix 15 12 ./reflector.nix 16 13 ]; 17 - } 14 + }
-42
modules/microcosm/jetstream.nix
··· 1 - # This module configures the Microcosm Jetstream service. 2 - 3 - { config, lib, pkgs, ... }: 4 - 5 - with lib; 6 - 7 - let 8 - cfg = config.services.microcosm-jetstream; 9 - microcosmPkgs = pkgs.microcosm; 10 - in 11 - { 12 - options.services.microcosm-jetstream = { 13 - enable = mkEnableOption "Microcosm Jetstream service."; 14 - package = mkOption { 15 - type = types.package; 16 - default = microcosmPkgs.jetstream; 17 - description = "The Microcosm Jetstream package to use."; 18 - }; 19 - # Add other service-specific options here 20 - }; 21 - 22 - config = mkIf cfg.enable { 23 - systemd.services.microcosm-jetstream = { 24 - description = "Microcosm Jetstream Service"; 25 - after = [ "network.target" ]; 26 - wantedBy = [ "multi-user.target" ]; 27 - serviceConfig = { 28 - ExecStart = "${cfg.package}/bin/jetstream"; # This command likely needs adjustment 29 - Restart = "always"; 30 - User = "microcosm-jetstream"; 31 - Group = "microcosm-jetstream"; 32 - }; 33 - users.users.microcosm-jetstream = { 34 - isSystem = true; 35 - group = "microcosm-jetstream"; 36 - }; 37 - users.groups.microcosm-jetstream = { 38 - isSystem = true; 39 - }; 40 - }; 41 - }; 42 - }
+30 -13
modules/microcosm/pocket.nix
··· 1 - # This module configures the Microcosm Pocket service. 2 - 1 + # Defines the NixOS module for the Pocket service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-pocket; 9 - microcosmPkgs = pkgs.microcosm; 10 8 in 11 9 { 12 10 options.services.microcosm-pocket = { 13 - enable = mkEnableOption "Microcosm Pocket service."; 11 + enable = mkEnableOption "Pocket service"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 - default = microcosmPkgs.pocket; 17 - description = "The Microcosm Pocket package to use."; 15 + default = pkgs.nur.pocket; 16 + description = "The Pocket package to use."; 18 17 }; 19 - db = mkOption { 18 + 19 + dbDir = mkOption { 20 20 type = types.str; 21 - description = "path to the sqlite db file"; 21 + default = "microcosm-pocket"; 22 + description = "The directory to store the database in, relative to /var/lib."; 22 23 }; 24 + 23 25 domain = mkOption { 24 26 type = types.str; 25 - description = "the domain for serving a did doc"; 27 + description = "The domain for serving a did doc."; 26 28 }; 27 - # Add other service-specific options here 28 29 }; 29 30 30 31 config = mkIf cfg.enable { 31 32 systemd.services.microcosm-pocket = { 32 - description = "Microcosm Pocket Service"; 33 + description = "Pocket Service"; 33 34 after = [ "network.target" ]; 34 35 wantedBy = [ "multi-user.target" ]; 36 + 35 37 serviceConfig = { 36 - ExecStart = "${cfg.package}/bin/pocket --db ${cfg.db} --domain ${cfg.domain}"; 38 + ExecStart = "${cfg.package}/bin/pocket --db /var/lib/${cfg.dbDir}/prefs.sqlite3 --domain ${cfg.domain}"; 37 39 Restart = "always"; 40 + RestartSec = "10s"; 38 41 DynamicUser = true; 39 - StateDirectory = "microcosm-pocket"; 42 + StateDirectory = cfg.dbDir; 43 + ReadWritePaths = [ "/var/lib/${cfg.dbDir}" ]; 44 + 45 + # Security settings 46 + NoNewPrivileges = true; 47 + ProtectSystem = "strict"; 48 + ProtectHome = true; 49 + PrivateTmp = true; 50 + ProtectKernelTunables = true; 51 + ProtectKernelModules = true; 52 + ProtectControlGroups = true; 53 + RestrictRealtime = true; 54 + RestrictSUIDSGID = true; 55 + RemoveIPC = true; 56 + PrivateMounts = true; 40 57 }; 41 58 }; 42 59 };
+10 -15
modules/microcosm/quasar.nix
··· 1 - # This module configures the Microcosm Quasar service. 2 - 1 + # Defines the NixOS module for the Quasar service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-quasar; 9 - microcosmPkgs = pkgs.microcosm; 8 + microcosmPkgs = pkgs.nur.microcosm; 10 9 in 11 10 { 12 11 options.services.microcosm-quasar = { 13 - enable = mkEnableOption "Microcosm Quasar service."; 12 + enable = mkEnableOption "Quasar service"; 13 + 14 14 package = mkOption { 15 15 type = types.package; 16 16 default = microcosmPkgs.quasar; 17 - description = "The Microcosm Quasar package to use."; 17 + description = "The Quasar package to use."; 18 18 }; 19 - # Add other service-specific options here 20 19 }; 21 20 22 21 config = mkIf cfg.enable { 22 + # The quasar service is not yet implemented. 23 + # This module is a placeholder. 24 + # See: https://github.com/at-microcosm/microcosm-rs/issues/1 23 25 systemd.services.microcosm-quasar = { 24 - description = "Microcosm Quasar Service"; 25 - after = [ "network.target" ]; 26 - wantedBy = [ "multi-user.target" ]; 27 - serviceConfig = { 28 - ExecStart = "${cfg.package}/bin/quasar"; 29 - Restart = "always"; 30 - DynamicUser = true; 31 - StateDirectory = "microcosm-quasar"; 32 - }; 26 + description = "Microcosm Quasar Service (Not Implemented)"; 27 + serviceConfig.ExecStart = "${pkgs.coreutils}/bin/false"; 33 28 }; 34 29 }; 35 30 }
+33 -16
modules/microcosm/reflector.nix
··· 1 - # This module configures the Microcosm Reflector service. 2 - 1 + # Defines the NixOS module for the Reflector service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-reflector; 9 - microcosmPkgs = pkgs.microcosm; 10 8 in 11 9 { 12 10 options.services.microcosm-reflector = { 13 - enable = mkEnableOption "Microcosm Reflector service."; 11 + enable = mkEnableOption "Reflector service"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 - default = microcosmPkgs.reflector; 17 - description = "The Microcosm Reflector package to use."; 15 + default = pkgs.nur.reflector; 16 + description = "The Reflector package to use."; 18 17 }; 19 - id = mkOption { 18 + 19 + serviceId = mkOption { 20 20 type = types.str; 21 - description = "The DID document service ID to serve"; 21 + description = "The DID document service ID."; 22 22 }; 23 - type = mkOption { 23 + 24 + serviceType = mkOption { 24 25 type = types.str; 25 - description = "Service type"; 26 + description = "The service type."; 26 27 }; 28 + 27 29 serviceEndpoint = mkOption { 28 30 type = types.str; 29 - description = "The HTTPS endpoint for the service"; 31 + description = "The HTTPS endpoint for the service."; 30 32 }; 33 + 31 34 domain = mkOption { 32 35 type = types.str; 33 - description = "The parent domain"; 36 + description = "The parent domain."; 34 37 }; 35 - # Add other service-specific options here 36 38 }; 37 39 38 40 config = mkIf cfg.enable { 39 41 systemd.services.microcosm-reflector = { 40 - description = "Microcosm Reflector Service"; 42 + description = "Reflector Service"; 41 43 after = [ "network.target" ]; 42 44 wantedBy = [ "multi-user.target" ]; 45 + 43 46 serviceConfig = { 44 - ExecStart = "${cfg.package}/bin/reflector --id ${cfg.id} --type ${cfg.type} --service-endpoint ${cfg.serviceEndpoint} --domain ${cfg.domain}"; 47 + ExecStart = "${cfg.package}/bin/reflector --id ${cfg.serviceId} --type ${cfg.serviceType} --service-endpoint ${cfg.serviceEndpoint} --domain ${cfg.domain}"; 45 48 Restart = "always"; 49 + RestartSec = "10s"; 46 50 DynamicUser = true; 47 - StateDirectory = "microcosm-reflector"; 51 + StateDirectory = "reflector"; 52 + 53 + # Security settings 54 + NoNewPrivileges = true; 55 + ProtectSystem = "strict"; 56 + ProtectHome = true; 57 + PrivateTmp = true; 58 + ProtectKernelTunables = true; 59 + ProtectKernelModules = true; 60 + ProtectControlGroups = true; 61 + RestrictRealtime = true; 62 + RestrictSUIDSGID = true; 63 + RemoveIPC = true; 64 + PrivateMounts = true; 48 65 }; 49 66 }; 50 67 };
+58 -20
modules/microcosm/slingshot.nix
··· 1 - # This module configures the Microcosm Slingshot service. 2 - 1 + # Defines the NixOS module for the Slingshot service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-slingshot; 9 - microcosmPkgs = pkgs.microcosm; 10 8 in 11 9 { 12 10 options.services.microcosm-slingshot = { 13 - enable = mkEnableOption "Microcosm Slingshot service."; 11 + enable = mkEnableOption "Slingshot service"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 - default = microcosmPkgs.slingshot; 17 - description = "The Microcosm Slingshot package to use."; 15 + default = pkgs.nur.slingshot; 16 + description = "The Slingshot package to use."; 18 17 }; 18 + 19 19 jetstream = mkOption { 20 20 type = types.str; 21 - description = "Jetstream server to connect to."; 21 + description = "The Jetstream server to connect to."; 22 + }; 23 + 24 + jetstreamNoZstd = mkOption { 25 + type = types.bool; 26 + default = false; 27 + description = "Don't request zstd-compressed jetstream events."; 22 28 }; 23 - cacheDir = mkOption { 29 + 30 + dataDir = mkOption { 24 31 type = types.str; 25 - description = "where to keep disk caches"; 32 + default = "microcosm-slingshot"; 33 + description = "The directory to store data in, relative to /var/lib."; 26 34 }; 35 + 27 36 domain = mkOption { 28 - type = types.str; 29 - description = "the domain pointing to this server"; 37 + type = types.nullOr types.str; 38 + default = null; 39 + description = "The domain pointing to this server."; 30 40 }; 41 + 31 42 acmeContact = mkOption { 32 - type = types.str; 33 - description = "email address for letsencrypt contact"; 43 + type = types.nullOr types.str; 44 + default = null; 45 + description = "The email address for letsencrypt contact."; 34 46 }; 35 - certs = mkOption { 36 - type = types.str; 37 - description = "a location to cache acme https certs"; 47 + 48 + healthcheckUrl = mkOption { 49 + type = types.nullOr types.str; 50 + default = null; 51 + description = "The web address to send healtcheck pings to."; 38 52 }; 39 - # Add other service-specific options here 40 53 }; 41 54 42 55 config = mkIf cfg.enable { 43 56 systemd.services.microcosm-slingshot = { 44 - description = "Microcosm Slingshot Service"; 57 + description = "Slingshot Service"; 45 58 after = [ "network.target" ]; 46 59 wantedBy = [ "multi-user.target" ]; 60 + 47 61 serviceConfig = { 48 - ExecStart = "${cfg.package}/bin/slingshot --jetstream ${cfg.jetstream} --cache-dir ${cfg.cacheDir} --domain ${cfg.domain} --acme-contact ${cfg.acmeContact} --certs ${cfg.certs}"; 62 + ExecStart = '' 63 + ${cfg.package}/bin/slingshot \ 64 + --jetstream ${escapeShellArg cfg.jetstream} \ 65 + ${optionalString cfg.jetstreamNoZstd "--jetstream-no-zstd"} \ 66 + --cache-dir /var/lib/${cfg.dataDir}/cache \ 67 + ${optionalString (cfg.domain != null) "--domain ${escapeShellArg cfg.domain}"} \ 68 + ${optionalString (cfg.acmeContact != null) "--acme-contact ${escapeShellArg cfg.acmeContact}"} \ 69 + --certs /var/lib/${cfg.dataDir}/certs \ 70 + ${optionalString (cfg.healthcheckUrl != null) "--healthcheck ${escapeShellArg cfg.healthcheckUrl}"} 71 + ''; 49 72 Restart = "always"; 73 + RestartSec = "10s"; 50 74 DynamicUser = true; 51 - StateDirectory = "microcosm-slingshot"; 75 + StateDirectory = cfg.dataDir; 76 + ReadWritePaths = [ "/var/lib/${cfg.dataDir}" ]; 77 + 78 + # Security settings 79 + NoNewPrivileges = true; 80 + ProtectSystem = "strict"; 81 + ProtectHome = true; 82 + PrivateTmp = true; 83 + ProtectKernelTunables = true; 84 + ProtectKernelModules = true; 85 + ProtectControlGroups = true; 86 + RestrictRealtime = true; 87 + RestrictSUIDSGID = true; 88 + RemoveIPC = true; 89 + PrivateMounts = true; 52 90 }; 53 91 }; 54 92 };
+27 -12
modules/microcosm/spacedust.nix
··· 1 - # This module configures the Microcosm Spacedust service. 2 - 1 + # Defines the NixOS module for the Spacedust service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-spacedust; 9 - microcosmPkgs = pkgs.microcosm; 10 8 in 11 9 { 12 10 options.services.microcosm-spacedust = { 13 - enable = mkEnableOption "Microcosm Spacedust service."; 11 + enable = mkEnableOption "Spacedust service"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 - default = microcosmPkgs.spacedust; 17 - description = "The Microcosm Spacedust package to use."; 15 + default = pkgs.nur.spacedust; 16 + description = "The Spacedust package to use."; 18 17 }; 18 + 19 19 jetstream = mkOption { 20 20 type = types.str; 21 - description = "Jetstream server to connect to."; 21 + description = "The Jetstream server to connect to."; 22 22 }; 23 + 23 24 jetstreamNoZstd = mkOption { 24 25 type = types.bool; 25 26 default = false; 26 - description = "don't request zstd-compressed jetstream events"; 27 + description = "Don't request zstd-compressed jetstream events."; 27 28 }; 28 - # Add other service-specific options here 29 29 }; 30 30 31 31 config = mkIf cfg.enable { 32 32 systemd.services.microcosm-spacedust = { 33 - description = "Microcosm Spacedust Service"; 33 + description = "Spacedust Service"; 34 34 after = [ "network.target" ]; 35 35 wantedBy = [ "multi-user.target" ]; 36 + 36 37 serviceConfig = { 37 - ExecStart = "${cfg.package}/bin/spacedust --jetstream ${cfg.jetstream} ${lib.optionalString cfg.jetstreamNoZstd "--jetstream-no-zstd"}"; 38 + ExecStart = "${cfg.package}/bin/spacedust --jetstream ${escapeShellArg cfg.jetstream} ${optionalString cfg.jetstreamNoZstd "--jetstream-no-zstd"}"; 38 39 Restart = "always"; 40 + RestartSec = "10s"; 39 41 DynamicUser = true; 40 - StateDirectory = "microcosm-spacedust"; 42 + StateDirectory = "spacedust"; 43 + 44 + # Security settings 45 + NoNewPrivileges = true; 46 + ProtectSystem = "strict"; 47 + ProtectHome = true; 48 + PrivateTmp = true; 49 + ProtectKernelTunables = true; 50 + ProtectKernelModules = true; 51 + ProtectControlGroups = true; 52 + RestrictRealtime = true; 53 + RestrictSUIDSGID = true; 54 + RemoveIPC = true; 55 + PrivateMounts = true; 41 56 }; 42 57 }; 43 58 };
+39 -33
modules/microcosm/ufos.nix
··· 1 - # This module configures the Microcosm UFOs service. 2 - 1 + # Defines the NixOS module for the UFOs service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-ufos; 9 - microcosmPkgs = pkgs.microcosm; 10 8 in 11 9 { 12 10 options.services.microcosm-ufos = { 13 - enable = mkEnableOption "Microcosm UFOs service."; 11 + enable = mkEnableOption "UFOs service"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 - default = microcosmPkgs.ufos; 17 - description = "The Microcosm UFOs package to use."; 15 + default = pkgs.nur.ufos; 16 + description = "The UFOs package to use."; 18 17 }; 18 + 19 19 jetstream = mkOption { 20 20 type = types.str; 21 - description = "Jetstream server to connect to."; 22 - }; 23 - data = mkOption { 24 - type = types.str; 25 - description = "Location to store persist data to disk"; 21 + description = "The Jetstream server to connect to."; 26 22 }; 23 + 27 24 jetstreamForce = mkOption { 28 25 type = types.bool; 29 26 default = false; 30 - description = "allow changing jetstream endpoints"; 27 + description = "Allow changing jetstream endpoints."; 31 28 }; 29 + 32 30 jetstreamNoZstd = mkOption { 33 31 type = types.bool; 34 32 default = false; 35 - description = "don't request zstd-compressed jetstream events"; 33 + description = "Don't request zstd-compressed jetstream events."; 36 34 }; 37 - pauseWriter = mkOption { 38 - type = types.bool; 39 - default = false; 40 - description = "DEBUG: don't start the jetstream consumer or its write loop"; 35 + 36 + dataDir = mkOption { 37 + type = types.str; 38 + default = "microcosm-ufos"; 39 + description = "The directory to store data in, relative to /var/lib."; 41 40 }; 41 + 42 42 backfill = mkOption { 43 43 type = types.bool; 44 44 default = false; 45 - description = "Adjust runtime settings like background task intervals for efficient backfill"; 46 - }; 47 - pauseRw = mkOption { 48 - type = types.bool; 49 - default = false; 50 - description = "DEBUG: force the rw loop to fall behind by pausing it todo: restore this"; 45 + description = "Adjust runtime settings for efficient backfill."; 51 46 }; 47 + 52 48 reroll = mkOption { 53 49 type = types.bool; 54 50 default = false; 55 - description = "reset the rollup cursor, scrape through missed things in the past (backfill)"; 56 - }; 57 - jetstreamFixture = mkOption { 58 - type = types.bool; 59 - default = false; 60 - description = "DEBUG: interpret jetstream as a file fixture"; 51 + description = "Reset the rollup cursor and backfill."; 61 52 }; 62 - # Add other service-specific options here 63 53 }; 64 54 65 55 config = mkIf cfg.enable { 66 56 systemd.services.microcosm-ufos = { 67 - description = "Microcosm UFOs Service"; 57 + description = "UFOs Service"; 68 58 after = [ "network.target" ]; 69 59 wantedBy = [ "multi-user.target" ]; 60 + 70 61 serviceConfig = { 71 - ExecStart = "${cfg.package}/bin/ufos --jetstream ${cfg.jetstream} --data ${cfg.data} ${lib.optionalString cfg.jetstreamForce "--jetstream-force"} ${lib.optionalString cfg.jetstreamNoZstd "--jetstream-no-zstd"} ${lib.optionalString cfg.pauseWriter "--pause-writer"} ${lib.optionalString cfg.backfill "--backfill"} ${lib.optionalString cfg.pauseRw "--pause-rw"} ${lib.optionalString cfg.reroll "--reroll"} ${lib.optionalString cfg.jetstreamFixture "--jetstream-fixture"}"; 62 + ExecStart = "${cfg.package}/bin/ufos --jetstream ${escapeShellArg cfg.jetstream} ${optionalString cfg.jetstreamForce "--jetstream-force"} ${optionalString cfg.jetstreamNoZstd "--jetstream-no-zstd"} --data /var/lib/${cfg.dataDir} ${optionalString cfg.backfill "--backfill"} ${optionalString cfg.reroll "--reroll"}"; 72 63 Restart = "always"; 64 + RestartSec = "10s"; 73 65 DynamicUser = true; 74 - StateDirectory = "microcosm-ufos"; 66 + StateDirectory = cfg.dataDir; 67 + ReadWritePaths = [ "/var/lib/${cfg.dataDir}" ]; 68 + 69 + # Security settings 70 + NoNewPrivileges = true; 71 + ProtectSystem = "strict"; 72 + ProtectHome = true; 73 + PrivateTmp = true; 74 + ProtectKernelTunables = true; 75 + ProtectKernelModules = true; 76 + ProtectControlGroups = true; 77 + RestrictRealtime = true; 78 + RestrictSUIDSGID = true; 79 + RemoveIPC = true; 80 + PrivateMounts = true; 75 81 }; 76 82 }; 77 83 };
+60 -19
modules/microcosm/who-am-i.nix
··· 1 - # This module configures the Microcosm Who-Am-I service. 2 - 1 + # Defines the NixOS module for the Who-Am-I service 3 2 { config, lib, pkgs, ... }: 4 3 5 4 with lib; 6 5 7 6 let 8 7 cfg = config.services.microcosm-who-am-i; 9 - microcosmPkgs = pkgs.microcosm; 10 8 in 11 9 { 12 10 options.services.microcosm-who-am-i = { 13 - enable = mkEnableOption "Microcosm Who-Am-I service."; 11 + enable = mkEnableOption "Microcosm Who-Am-I service (deprecated)"; 12 + 14 13 package = mkOption { 15 14 type = types.package; 16 15 default = microcosmPkgs."who-am-i"; 17 - description = "The Microcosm Who-Am-I package to use."; 16 + description = "The Who-Am-I package to use."; 18 17 }; 18 + 19 + openFirewall = mkOption { 20 + type = types.bool; 21 + default = false; 22 + description = "Whether to open the firewall for the Who-Am-I API port."; 23 + }; 24 + 19 25 appSecret = mkOption { 20 26 type = types.str; 21 - description = "secret key from which the cookie-signing key is derived"; 27 + description = "The secret key for cookie-signing."; 22 28 }; 29 + 23 30 oauthPrivateKey = mkOption { 24 - type = types.str; 25 - description = "path to at-oauth private key (PEM pk8 format)"; 31 + type = types.nullOr types.path; 32 + default = null; 33 + description = "The path to the at-oauth private key."; 26 34 }; 35 + 27 36 jwtPrivateKey = mkOption { 28 - type = types.str; 29 - description = "path to jwt private key (PEM pk8 format)"; 37 + type = types.path; 38 + description = "The path to the jwt private key."; 30 39 }; 40 + 31 41 baseUrl = mkOption { 32 42 type = types.str; 33 - description = "this server's client-reachable base url, for oauth redirect + jwt check"; 43 + description = "The client-reachable base url."; 34 44 }; 45 + 35 46 bind = mkOption { 36 47 type = types.str; 37 48 default = "127.0.0.1:9997"; 38 - description = "host:port to bind to on startup"; 49 + description = "The host:port to bind to."; 39 50 }; 51 + 40 52 dev = mkOption { 41 53 type = types.bool; 42 54 default = false; 43 - description = "Enable dev mode"; 55 + description = "Enable dev mode."; 44 56 }; 57 + 45 58 allowedHosts = mkOption { 46 59 type = types.listOf types.str; 47 - default = []; 48 - description = "Hosts who are allowed to one-click auth"; 60 + description = "The hosts who are allowed to one-click auth."; 49 61 }; 50 - # Add other service-specific options here 51 62 }; 52 63 53 64 config = mkIf cfg.enable { 54 65 systemd.services.microcosm-who-am-i = { 55 - description = "Microcosm Who-Am-I Service"; 66 + description = "Microcosm Who-Am-I Service (deprecated)"; 56 67 after = [ "network.target" ]; 57 68 wantedBy = [ "multi-user.target" ]; 69 + 58 70 serviceConfig = { 59 - ExecStart = "${cfg.package}/bin/who-am-i --app-secret ${cfg.appSecret} --oauth-private-key ${cfg.oauthPrivateKey} --jwt-private-key ${cfg.jwtPrivateKey} --base-url ${cfg.baseUrl} --bind ${cfg.bind} ${lib.optionalString cfg.dev "--dev"} ${lib.concatMapStringsSep " " (host: "--allow_host " + host) cfg.allowedHosts}"; 71 + # Execution settings from the feature branch 72 + ExecStart = '' 73 + ${cfg.package}/bin/who-am-i \ 74 + --app-secret ${escapeShellArg cfg.appSecret} \ 75 + ${optionalString (cfg.oauthPrivateKey != null) "--oauth-private-key ${escapeShellArg cfg.oauthPrivateKey}"} \ 76 + --jwt-private-key ${escapeShellArg cfg.jwtPrivateKey} \ 77 + --base-url ${escapeShellArg cfg.baseUrl} \ 78 + --bind ${escapeShellArg cfg.bind} \ 79 + ${optionalString cfg.dev "--dev"} \ 80 + ${concatStringsSep " " (map (host: "--allow-host ${escapeShellArg host}") cfg.allowedHosts)} 81 + ''; 60 82 Restart = "always"; 83 + RestartSec = "10s"; 61 84 DynamicUser = true; 62 - StateDirectory = "microcosm-who-am-i"; 85 + StateDirectory = "who-am-i"; 86 + 87 + # Security settings from the main branch 88 + NoNewPrivileges = true; 89 + ProtectSystem = "strict"; 90 + ProtectHome = true; 91 + PrivateTmp = true; 92 + ProtectKernelTunables = true; 93 + ProtectKernelModules = true; 94 + ProtectControlGroups = true; 95 + RestrictRealtime = true; 96 + RestrictSUIDSGID = true; 97 + RemoveIPC = true; 98 + PrivateMounts = true; 63 99 }; 100 + }; 101 + 102 + # Updated firewall rule to parse the port from the new 'bind' option 103 + networking.firewall = mkIf cfg.openFirewall { 104 + allowedTCPPorts = [ (toInt (last (splitString ":" cfg.bind))) ]; 64 105 }; 65 106 }; 66 107 }
-8
overlays/cfg-if-fix.nix
··· 1 - final: prev: { 2 - buildPackage = args: 3 - prev.buildPackage (args // { 4 - unpackPhase = '' 5 - tar -xzf $src --no-same-owner 6 - ''; 7 - }); 8 - }
-3
overlays/default.nix
··· 1 - { 2 - cfg-if-fix = import ./cfg-if-fix.nix; 3 - }
+2 -2
pkgs/blacksky/default.nix
··· 1 - { pkgs, craneLib, buildYarnPackage, ... }: 1 + { pkgs, craneLib, ... }: 2 2 3 - import ./rsky { inherit pkgs craneLib buildYarnPackage; } 3 + import ./rsky { inherit pkgs craneLib; }
+36 -45
pkgs/blacksky/rsky/default.nix
··· 1 - { pkgs, craneLib, buildYarnPackage }: 1 + { pkgs, craneLib, ... }: 2 2 3 3 { 4 4 pds = craneLib.buildPackage rec { ··· 16 16 17 17 cargoBuildFlags = [ "--package rsky-pds --bin rsky-pds" ]; 18 18 cargoInstallFlags = [ "--package rsky-pds --bin rsky-pds" ]; 19 - tarFlags = "--no-same-owner"; 20 19 21 20 meta = with pkgs.lib; { 22 21 description = "AT Protocol Personal Data Server (PDS) from rsky"; ··· 39 38 40 39 cargoBuildFlags = [ "--package rsky-relay --bin rsky-relay" ]; 41 40 cargoInstallFlags = [ "--package rsky-relay --bin rsky-relay" ]; 42 - tarFlags = "--no-same-owner"; 43 41 44 42 meta = with pkgs.lib; { 45 43 description = "AT Protocol Relay from rsky"; ··· 62 60 63 61 cargoBuildFlags = [ "--package rsky-feedgen --bin rsky-feedgen" ]; 64 62 cargoInstallFlags = [ "--package rsky-feedgen --bin rsky-feedgen" ]; 65 - tarFlags = "--no-same-owner"; 66 63 67 64 meta = with pkgs.lib; { 68 65 description = "AT Protocol Feed Generator from rsky"; ··· 85 82 86 83 cargoBuildFlags = [ "--package rsky-satnav --bin rsky-satnav" ]; 87 84 cargoInstallFlags = [ "--package rsky-satnav --bin rsky-satnav" ]; 88 - tarFlags = "--no-same-owner"; 89 85 90 86 meta = with pkgs.lib; { 91 87 description = "AT Protocol Satnav from rsky"; ··· 108 104 109 105 cargoBuildFlags = [ "--package rsky-firehose --bin rsky-firehose" ]; 110 106 cargoInstallFlags = [ "--package rsky-firehose --bin rsky-firehose" ]; 111 - tarFlags = "--no-same-owner"; 112 107 113 108 meta = with pkgs.lib; { 114 109 description = "AT Protocol Firehose subscriber from rsky"; ··· 131 126 132 127 cargoBuildFlags = [ "--package rsky-jetstream-subscriber --bin rsky-jetstream-subscriber" ]; 133 128 cargoInstallFlags = [ "--package rsky-jetstream-subscriber --bin rsky-jetstream-subscriber" ]; 134 - tarFlags = "--no-same-owner"; 135 129 136 130 meta = with pkgs.lib; { 137 131 description = "AT Protocol Jetstream Subscriber from rsky"; ··· 154 148 155 149 cargoBuildFlags = [ "--package rsky-labeler --bin rsky-labeler" ]; 156 150 cargoInstallFlags = [ "--package rsky-labeler --bin rsky-labeler" ]; 157 - tarFlags = "--no-same-owner"; 158 151 159 152 meta = with pkgs.lib; { 160 153 description = "AT Protocol Labeler from rsky"; ··· 164 157 }; 165 158 }; 166 159 167 - community = pkgs.buildYarnPackage rec { 168 - pname = "blacksky.community"; 169 - version = "1.109.0"; # Version from package.json 170 - 171 - src = pkgs.fetchFromGitHub { 172 - owner = "blacksky-algorithms"; 173 - repo = "blacksky.community"; 174 - # TODO: Update 'rev' to a specific commit hash or release tag for reproducible builds. 175 - rev = "main"; 176 - # TODO: Update 'hash' to the correct SHA256 hash of the fetched source. 177 - # You can obtain the correct hash by setting it to an empty string, running nix-build, 178 - # and then copying the hash from the error message. 179 - hash = "sha256-W0mXqED9geNKJSPGJhUdJZ2voMOMDCXX1T4zn3GZKlY="; 180 - }; 181 - 182 - yarnLock = "yarn.lock"; # Specify the yarn.lock file 183 - 184 - buildPhase = '' 185 - yarn build-web 186 - ''; 187 - 188 - installPhase = '' 189 - mkdir -p $out/share/nginx/html 190 - cp -r web-build/* $out/share/nginx/html 191 - ''; 192 - 193 - meta = with pkgs.lib; { 194 - description = "Blacksky Community Web Client"; 195 - # Placeholder, update with actual homepage if available. 196 - homepage = "https://github.com/blacksky-algorithms/blacksky.community"; 197 - # Placeholder, update with actual license if available. Assuming MIT for now. 198 - license = licenses.mit; 199 - # Placeholder, add actual maintainers. 200 - maintainers = with maintainers; [ ]; 201 - }; 202 - }; 203 - } 160 + # community = pkgs.buildYarnPackage rec { 161 + # pname = "blacksky.community"; 162 + # version = "1.109.0"; # Version from package.json 163 + # 164 + # src = pkgs.fetchFromGitHub { 165 + # owner = "blacksky-algorithms"; 166 + # repo = "blacksky.community"; 167 + # # TODO: Update 'rev' to a specific commit hash or release tag for reproducible builds. 168 + # rev = "main"; 169 + # # TODO: Update 'hash' to the correct SHA256 hash of the fetched source. 170 + # # You can obtain the correct hash by setting it to an empty string, running nix-build, 171 + # # and then copying the hash from the error message. 172 + # hash = "sha256-W0mXqED9geNKJSPGJhUdJZ2voMOMDCXX1T4zn3GZKlY="; 173 + # }; 174 + # 175 + # yarnLock = "yarn.lock"; # Specify the yarn.lock file 176 + # 177 + # buildPhase = '' 178 + # yarn build-web 179 + # ''; 180 + # 181 + # installPhase = '' 182 + # mkdir -p $out/share/nginx/html 183 + # cp -r web-build/* $out/share/nginx/html 184 + # ''; 185 + # 186 + # meta = with pkgs.lib; { 187 + # description = "Blacksky Community Web Client"; 188 + # # Placeholder, update with actual homepage if available. 189 + # homepage = "https://github.com/blacksky-algorithms/blacksky.community"; 190 + # # Placeholder, add actual maintainers. 191 + # maintainers = with maintainers; [ ]; 192 + # }; 193 + # }; 194 + }
+13 -15
pkgs/microcosm/default.nix
··· 13 13 OPENSSL_NO_VENDOR = "1"; 14 14 OPENSSL_LIB_DIR = "${pkgs.lib.getLib pkgs.openssl}/lib"; 15 15 OPENSSL_INCLUDE_DIR = "${pkgs.lib.getDev pkgs.openssl}/include"; 16 - BINDGEN_EXTRA_CLANG_ARGS = pkgs.lib.concatStringsSep " " ([ 16 + BINDGEN_EXTRA_CLANG_ARGS = pkgs.lib.concatStringsSep " " [ 17 17 "-I${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.lib.versions.major pkgs.llvmPackages.libclang.version}/include" 18 - ] ++ pkgs.lib.optional pkgs.stdenv.isLinux "-I${pkgs.glibc.dev}"); 18 + "-I${pkgs.glibc.dev}" 19 + ]; 19 20 ZSTD_SYS_USE_PKG_CONFIG = "1"; 20 21 CC = "${pkgs.llvmPackages.clang}/bin/clang"; 21 22 CXX = "${pkgs.llvmPackages.clang}/bin/clang++"; 22 23 PKG_CONFIG_PATH = "${pkgs.zstd.dev}/lib/pkgconfig:${pkgs.lz4.dev}/lib/pkgconfig"; 23 24 }; 24 25 25 - nativeInputs = with pkgs; [ 26 + nativeInputs = with pkgs; 27 + [ 26 28 pkg-config 27 29 perl 28 30 ]; 29 31 30 - buildInputs = with pkgs; [ 32 + buildInputs = with pkgs; 33 + [ 31 34 zstd 32 35 lz4 33 36 rocksdb 34 37 openssl 38 + sqlite 35 39 ]; 36 - 37 40 cargoArtifacts = craneLib.buildDepsOnly { 38 41 inherit src; 39 42 pname = "microcosm-rs-deps"; 43 + version = "0.1.0"; 40 44 nativeBuildInputs = nativeInputs; 41 45 buildInputs = buildInputs; 42 46 env = commonEnv; 47 + tarFlags = "--no-same-owner"; 43 48 }; 44 49 45 50 members = [ ··· 55 60 "pocket" 56 61 "reflector" 57 62 ]; 58 - 59 63 buildPackage = member: 60 64 let 61 65 packageName = if member == "ufos/fuzz" then "ufos-fuzz" else member; ··· 66 70 version = "0.1.0"; 67 71 cargoExtraArgs = "--package ${packageName}"; 68 72 nativeBuildInputs = nativeInputs; 69 - buildInputs = buildInputs ++ (pkgs.lib.optional (member == "pocket") pkgs.sqlite); 73 + buildInputs = buildInputs; 74 + tarFlags = "--no-same-owner"; 70 75 env = commonEnv; 71 76 }; 72 77 73 78 packages = pkgs.lib.genAttrs members (member: buildPackage member); 74 79 75 80 in 76 - packages // { 77 - default = pkgs.linkFarm "microcosm-rs" (pkgs.lib.mapAttrsToList (name: value: 78 - let 79 - linkName = if name == "ufos/fuzz" then "ufos-fuzz" else name; 80 - in 81 - { name = linkName; path = value; } 82 - ) packages); 83 - } 81 + packages
+28
tests/constellation-shell.nix
··· 1 + { pkgs }: 2 + 3 + pkgs.nixosTest { 4 + name = "constellation-shell"; 5 + 6 + nodes.machine = { ... }: 7 + { 8 + imports = [ ../modules/microcosm/constellation.nix ]; 9 + 10 + services.microcosm-constellation = { 11 + enable = true; 12 + jetstream = "us-east-1"; 13 + dataDir = "microcosm-constellation"; 14 + backend = "rocks"; 15 + }; 16 + }; 17 + 18 + # The corrected test script 19 + testScript = '' 20 + start_all() 21 + machine.wait_for_unit("microcosm-constellation.service") 22 + # The line below was removed. wait_for_unit is all you need. 23 + # machine.succeed("systemctl status --wait microcosm-constellation.service") 24 + 25 + # If you want to be extra sure, you can log the status 26 + machine.log(machine.succeed("systemctl status microcosm-constellation.service")) 27 + ''; 28 + }
+5
tests/default.nix
··· 1 + { pkgs }: 2 + { 3 + constellation = import ./constellation.nix { inherit pkgs; }; 4 + constellation-shell = import ./constellation-shell.nix { inherit pkgs; }; 5 + }