+2
-5
.tangled/workflows/build.yml
+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
+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
+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
[](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
+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
+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
+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
-7
lib/default.nix
+2
-4
modules/blacksky/community.nix
+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
-2
modules/blacksky/default.nix
+2
-4
modules/blacksky/rsky/feedgen.nix
+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
-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
-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
-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
-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
-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;
+111
-26
modules/microcosm/constellation.nix
+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
-4
modules/microcosm/default.nix
-42
modules/microcosm/jetstream.nix
-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
+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
+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
+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
+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
+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
+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
+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
-8
overlays/cfg-if-fix.nix
+2
-2
pkgs/blacksky/default.nix
+2
-2
pkgs/blacksky/default.nix
+36
-45
pkgs/blacksky/rsky/default.nix
+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
-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
+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
+
}