feat: Add flake and ragenix package generation and dev environment
This commit is contained in:
3
.envrc
Normal file
3
.envrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Automatically load the Nix development shell when entering this directory
|
||||||
|
# Requires direnv: https://direnv.net/
|
||||||
|
use flake
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -35,3 +35,7 @@ management-dashboard-web-app/users.txt
|
|||||||
|
|
||||||
# Jupyter Notebooks
|
# Jupyter Notebooks
|
||||||
*.ipynb
|
*.ipynb
|
||||||
|
# Nix
|
||||||
|
result
|
||||||
|
result-*
|
||||||
|
.direnv/
|
||||||
264
FLAKE_SETUP.md
Normal file
264
FLAKE_SETUP.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
# USDA Vision - Nix Flake Setup
|
||||||
|
|
||||||
|
This directory now has a Nix flake for building and developing the USDA Vision system, with ragenix for managing secrets.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
|
||||||
|
Enter the development shell with all tools:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd usda-vision
|
||||||
|
nix develop
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives you:
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- Node.js 20 with npm/pnpm
|
||||||
|
- Python 3.11 with pip/virtualenv
|
||||||
|
- Supabase CLI
|
||||||
|
- Camera SDK (automatically in `LD_LIBRARY_PATH`)
|
||||||
|
- ragenix for secrets management
|
||||||
|
- All standard utilities (jq, yq, rsync, etc.)
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
Build the package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build
|
||||||
|
# Or explicitly:
|
||||||
|
nix build .#usda-vision
|
||||||
|
```
|
||||||
|
|
||||||
|
Build just the camera SDK:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build .#camera-sdk
|
||||||
|
```
|
||||||
|
|
||||||
|
## Secrets Management with ragenix
|
||||||
|
|
||||||
|
### Initial Setup
|
||||||
|
|
||||||
|
1. **Generate or use an age key**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Option 1: Generate a new age key
|
||||||
|
mkdir -p ~/.config/age
|
||||||
|
age-keygen -o ~/.config/age/keys.txt
|
||||||
|
|
||||||
|
# Option 2: Use your SSH key
|
||||||
|
ssh-to-age < ~/.ssh/id_ed25519.pub
|
||||||
|
# Copy the output to secrets/secrets.nix
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Add your public key** to [secrets/secrets.nix](secrets/secrets.nix):
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
publicKeys = [
|
||||||
|
"age1your_public_key_here"
|
||||||
|
# or
|
||||||
|
"ssh-ed25519 AAAA... user@host"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Create encrypted environment files**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix develop # Enter dev shell first
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
```
|
||||||
|
|
||||||
|
This opens your `$EDITOR` to edit the encrypted file. Add your environment variables:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Web environment (Vite)
|
||||||
|
VITE_SUPABASE_URL=http://exp-dash:54321
|
||||||
|
VITE_SUPABASE_ANON_KEY=your-anon-key-here
|
||||||
|
# ... etc
|
||||||
|
```
|
||||||
|
|
||||||
|
For Azure OAuth:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ragenix -e secrets/env.azure.age
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Secrets in Development
|
||||||
|
|
||||||
|
In the development shell, you can:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Edit secrets
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
|
||||||
|
# View decrypted content (careful in shared screens!)
|
||||||
|
age -d -i ~/.config/age/keys.txt secrets/env.age
|
||||||
|
|
||||||
|
# Re-encrypt all secrets after adding a new public key
|
||||||
|
ragenix -r
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Secrets in Production (NixOS)
|
||||||
|
|
||||||
|
The flake includes a NixOS module that handles secrets automatically:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# In your NixOS configuration
|
||||||
|
{
|
||||||
|
inputs.usda-vision.url = "path:/path/to/usda-vision";
|
||||||
|
|
||||||
|
# ... in your module:
|
||||||
|
imports = [ inputs.usda-vision.nixosModules.default ];
|
||||||
|
|
||||||
|
services.usda-vision = {
|
||||||
|
enable = true;
|
||||||
|
secretsFile = config.age.secrets.usda-vision-env.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Configure ragenix/agenix to decrypt the secrets
|
||||||
|
age.secrets.usda-vision-env = {
|
||||||
|
file = inputs.usda-vision + "/secrets/env.age";
|
||||||
|
mode = "0644";
|
||||||
|
owner = "root";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
usda-vision/
|
||||||
|
├── flake.nix # Flake definition with outputs
|
||||||
|
├── package.nix # Main application build
|
||||||
|
├── camera-sdk.nix # Camera SDK build
|
||||||
|
├── secrets.nix # ragenix configuration
|
||||||
|
├── secrets/
|
||||||
|
│ ├── secrets.nix # Public keys
|
||||||
|
│ ├── env.age # Encrypted .env (safe to commit)
|
||||||
|
│ ├── env.azure.age # Encrypted Azure config (safe to commit)
|
||||||
|
│ └── README.md # Secrets documentation
|
||||||
|
└── ... (rest of the app)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration from Old Setup
|
||||||
|
|
||||||
|
### Old Workflow
|
||||||
|
- Manual `.env` file management
|
||||||
|
- Secrets in plaintext (git-ignored)
|
||||||
|
- Build defined in parent `default.nix`
|
||||||
|
|
||||||
|
### New Workflow
|
||||||
|
- Encrypted `.age` files in git
|
||||||
|
- Secrets managed with ragenix
|
||||||
|
- Self-contained flake in `usda-vision/`
|
||||||
|
- Development shell with all tools
|
||||||
|
|
||||||
|
### Migration Steps
|
||||||
|
|
||||||
|
1. **Encrypt existing `.env` files**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd usda-vision
|
||||||
|
nix develop
|
||||||
|
|
||||||
|
# Setup your age key first (see above)
|
||||||
|
|
||||||
|
# Encrypt the main .env
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
# Paste contents of old .env file, save and exit
|
||||||
|
|
||||||
|
# Encrypt Azure config
|
||||||
|
ragenix -e secrets/env.azure.age
|
||||||
|
# Paste contents of old .env.azure file, save and exit
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Delete unencrypted files** (they're git-ignored but still local):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm .env .env.azure management-dashboard-web-app/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Commit encrypted secrets**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add secrets/env.age secrets/env.azure.age secrets/secrets.nix
|
||||||
|
git commit -m "Add encrypted secrets with ragenix"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- ✅ Secrets encrypted at rest
|
||||||
|
- ✅ Safe to commit to git
|
||||||
|
- ✅ Key-based access control
|
||||||
|
- ✅ Audit trail (git history)
|
||||||
|
|
||||||
|
### Development
|
||||||
|
- ✅ Reproducible environment
|
||||||
|
- ✅ All tools included
|
||||||
|
- ✅ No manual setup
|
||||||
|
- ✅ Version-locked dependencies
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
- ✅ Declarative secrets management
|
||||||
|
- ✅ Automatic decryption on NixOS
|
||||||
|
- ✅ No manual key distribution
|
||||||
|
- ✅ Clean integration with existing infrastructure
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
### Add a new developer
|
||||||
|
|
||||||
|
1. They generate an age key or use their SSH key
|
||||||
|
2. They send you their public key
|
||||||
|
3. You add it to `secrets/secrets.nix`
|
||||||
|
4. Re-encrypt all secrets: `ragenix -r`
|
||||||
|
5. Commit and push
|
||||||
|
|
||||||
|
### Rotate a secret
|
||||||
|
|
||||||
|
1. Edit the encrypted file: `ragenix -e secrets/env.age`
|
||||||
|
2. Update the value
|
||||||
|
3. Save and exit
|
||||||
|
4. Commit: `git commit secrets/env.age -m "Rotate API key"`
|
||||||
|
|
||||||
|
### Build without flakes
|
||||||
|
|
||||||
|
If you need to build on a system without flakes enabled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-build -E '(import (fetchTarball https://github.com/edolstra/flake-compat/archive/master.tar.gz) { src = ./.; }).defaultNix.default'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "error: getting status of '...': No such file or directory"
|
||||||
|
|
||||||
|
Make sure you're in the `usda-vision` directory when running `nix develop` or `nix build`.
|
||||||
|
|
||||||
|
### "cannot decrypt: no valid identity"
|
||||||
|
|
||||||
|
Your age private key isn't found. Check:
|
||||||
|
- `~/.config/age/keys.txt` exists
|
||||||
|
- Your public key is in `secrets/secrets.nix`
|
||||||
|
- You've run `ragenix -r` after adding your key
|
||||||
|
|
||||||
|
### "experimental feature 'flakes' not enabled"
|
||||||
|
|
||||||
|
Add to `~/.config/nix/nix.conf`:
|
||||||
|
```
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
```
|
||||||
|
|
||||||
|
Or run with: `nix --experimental-features 'nix-command flakes' develop`
|
||||||
|
|
||||||
|
## Further Reading
|
||||||
|
|
||||||
|
- [Nix Flakes](https://nixos.wiki/wiki/Flakes)
|
||||||
|
- [ragenix](https://github.com/yaxitech/ragenix)
|
||||||
|
- [age encryption](https://github.com/FiloSottile/age)
|
||||||
241
SETUP_COMPLETE.md
Normal file
241
SETUP_COMPLETE.md
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
# USDA Vision - Flake Migration Complete ✅
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Your USDA Vision repository now has:
|
||||||
|
|
||||||
|
1. **Self-contained Nix flake** (`flake.nix`)
|
||||||
|
- Independent build system
|
||||||
|
- Development environment
|
||||||
|
- NixOS module for deployment
|
||||||
|
|
||||||
|
2. **Encrypted secrets management** (ragenix)
|
||||||
|
- `.age` files safe to commit to git
|
||||||
|
- Key-based access control
|
||||||
|
- No more plaintext `.env` files
|
||||||
|
|
||||||
|
3. **Modular build** (package.nix, camera-sdk.nix)
|
||||||
|
- Cleaner organization
|
||||||
|
- Easier to maintain
|
||||||
|
- Reusable components
|
||||||
|
|
||||||
|
4. **Updated parent** (../default.nix)
|
||||||
|
- Now references the flake
|
||||||
|
- Removed 200+ lines of inline derivations
|
||||||
|
|
||||||
|
## Files Added
|
||||||
|
|
||||||
|
### Core Flake Files
|
||||||
|
- ✅ `flake.nix` - Main flake definition with outputs
|
||||||
|
- ✅ `package.nix` - Application build logic
|
||||||
|
- ✅ `camera-sdk.nix` - Camera SDK build logic
|
||||||
|
- ✅ `secrets.nix` - ragenix configuration
|
||||||
|
|
||||||
|
### Secrets Infrastructure
|
||||||
|
- ✅ `secrets/secrets.nix` - Public key list
|
||||||
|
- ✅ `secrets/README.md` - Secrets documentation
|
||||||
|
- ✅ `secrets/.gitignore` - Protect plaintext files
|
||||||
|
|
||||||
|
### Documentation & Helpers
|
||||||
|
- ✅ `FLAKE_SETUP.md` - Complete setup guide
|
||||||
|
- ✅ `setup-dev.sh` - Interactive setup script
|
||||||
|
- ✅ `.envrc` - direnv integration (optional)
|
||||||
|
|
||||||
|
### Parent Directory
|
||||||
|
- ✅ `NIX_FLAKE_MIGRATION.md` - Migration summary
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
### 1. Commit the Flake Files
|
||||||
|
|
||||||
|
The flake needs to be in git to work:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/engr-ugaif/usda-dash-config/usda-vision
|
||||||
|
|
||||||
|
# Add all new flake files
|
||||||
|
git add flake.nix package.nix camera-sdk.nix secrets.nix
|
||||||
|
git add secrets/secrets.nix secrets/README.md secrets/.gitignore
|
||||||
|
git add FLAKE_SETUP.md setup-dev.sh .envrc .gitignore
|
||||||
|
|
||||||
|
# Commit
|
||||||
|
git commit -m "Add Nix flake with ragenix secrets management
|
||||||
|
|
||||||
|
- Self-contained flake build system
|
||||||
|
- Development shell with all tools
|
||||||
|
- ragenix for encrypted secrets
|
||||||
|
- Modular package definitions
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Set Up Your Age Key
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/engr-ugaif/usda-dash-config/usda-vision
|
||||||
|
|
||||||
|
# Option A: Use the interactive setup script
|
||||||
|
./setup-dev.sh
|
||||||
|
|
||||||
|
# Option B: Manual setup
|
||||||
|
mkdir -p ~/.config/age
|
||||||
|
age-keygen -o ~/.config/age/keys.txt
|
||||||
|
# Then add your public key to secrets/secrets.nix
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Encrypt Your Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enter the development environment
|
||||||
|
nix develop
|
||||||
|
|
||||||
|
# Encrypt main .env file
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
# Paste your current .env contents, save, exit
|
||||||
|
|
||||||
|
# Encrypt Azure config
|
||||||
|
ragenix -e secrets/env.azure.age
|
||||||
|
# Paste your current .env.azure contents, save, exit
|
||||||
|
|
||||||
|
# Commit encrypted secrets
|
||||||
|
git add secrets/env.age secrets/env.azure.age
|
||||||
|
git commit -m "Add encrypted environment configuration"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Test the Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test that the build works
|
||||||
|
nix build
|
||||||
|
|
||||||
|
# Test the development shell
|
||||||
|
nix develop
|
||||||
|
# You should see a welcome message
|
||||||
|
|
||||||
|
# Inside the dev shell, verify tools
|
||||||
|
docker-compose --version
|
||||||
|
supabase --version
|
||||||
|
ragenix --help
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Update the Parent Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/engr-ugaif/usda-dash-config
|
||||||
|
|
||||||
|
# Commit the updated default.nix
|
||||||
|
git add default.nix NIX_FLAKE_MIGRATION.md
|
||||||
|
git commit -m "Update default.nix to use usda-vision flake
|
||||||
|
|
||||||
|
- Removed inline derivations
|
||||||
|
- Now references usda-vision flake packages
|
||||||
|
- Cleaner, more maintainable code
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Clean Up Old Files (Optional)
|
||||||
|
|
||||||
|
After verifying everything works, you can delete the old plaintext secrets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/engr-ugaif/usda-dash-config/usda-vision
|
||||||
|
|
||||||
|
# These are already git-ignored, but remove them locally
|
||||||
|
rm -f .env .env.azure management-dashboard-web-app/.env
|
||||||
|
|
||||||
|
echo "✅ Old plaintext secrets removed"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification Checklist
|
||||||
|
|
||||||
|
- [ ] Flake files committed to git
|
||||||
|
- [ ] Age key generated at `~/.config/age/keys.txt`
|
||||||
|
- [ ] Public key added to `secrets/secrets.nix`
|
||||||
|
- [ ] Secrets encrypted and committed
|
||||||
|
- [ ] `nix build` succeeds
|
||||||
|
- [ ] `nix develop` works
|
||||||
|
- [ ] Parent `default.nix` updated and committed
|
||||||
|
- [ ] Old `.env` files deleted
|
||||||
|
|
||||||
|
## Usage Quick Reference
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enter dev environment (one-time per session)
|
||||||
|
cd usda-vision
|
||||||
|
nix develop
|
||||||
|
|
||||||
|
# Edit secrets
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
|
||||||
|
# Normal docker-compose workflow
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build everything
|
||||||
|
nix build
|
||||||
|
|
||||||
|
# Build specific packages
|
||||||
|
nix build .#usda-vision
|
||||||
|
nix build .#camera-sdk
|
||||||
|
```
|
||||||
|
|
||||||
|
### Secrets Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Edit encrypted secret
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
|
||||||
|
# Re-key after adding a new public key
|
||||||
|
ragenix -r
|
||||||
|
|
||||||
|
# View decrypted (careful!)
|
||||||
|
age -d -i ~/.config/age/keys.txt secrets/env.age
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "cannot decrypt: no valid identity"
|
||||||
|
|
||||||
|
Your age key isn't configured. Run:
|
||||||
|
```bash
|
||||||
|
./setup-dev.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### "error: flake.nix is not in git"
|
||||||
|
|
||||||
|
Commit the flake files:
|
||||||
|
```bash
|
||||||
|
git add flake.nix package.nix camera-sdk.nix secrets.nix
|
||||||
|
git commit -m "Add flake files"
|
||||||
|
```
|
||||||
|
|
||||||
|
### "experimental feature 'flakes' not enabled"
|
||||||
|
|
||||||
|
Add to `~/.config/nix/nix.conf`:
|
||||||
|
```
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- **Full Setup Guide**: [FLAKE_SETUP.md](FLAKE_SETUP.md)
|
||||||
|
- **Secrets Guide**: [secrets/README.md](secrets/README.md)
|
||||||
|
- **Migration Summary**: [../NIX_FLAKE_MIGRATION.md](../NIX_FLAKE_MIGRATION.md)
|
||||||
|
|
||||||
|
## Questions?
|
||||||
|
|
||||||
|
Refer to [FLAKE_SETUP.md](FLAKE_SETUP.md) for detailed documentation, or run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-dev.sh # Interactive setup
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Migration completed on**: 2026-01-30
|
||||||
|
**Created by**: GitHub Copilot
|
||||||
44
camera-sdk.nix
Normal file
44
camera-sdk.nix
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{ stdenv
|
||||||
|
, lib
|
||||||
|
, makeWrapper
|
||||||
|
, libusb1
|
||||||
|
}:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "mindvision-camera-sdk";
|
||||||
|
version = "2.1.0.49";
|
||||||
|
|
||||||
|
# Use the camera_sdk directory as source
|
||||||
|
src = ./camera-management-api/camera_sdk;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
buildInputs = [ libusb1 ];
|
||||||
|
|
||||||
|
unpackPhase = ''
|
||||||
|
cp -r $src/* .
|
||||||
|
tar xzf "linuxSDK_V2.1.0.49(250108).tar.gz"
|
||||||
|
cd "linuxSDK_V2.1.0.49(250108)"
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/lib $out/include
|
||||||
|
|
||||||
|
# Copy x64 library files (SDK has arch-specific subdirs)
|
||||||
|
if [ -d lib/x64 ]; then
|
||||||
|
cp -r lib/x64/* $out/lib/ || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy header files
|
||||||
|
if [ -d include ]; then
|
||||||
|
cp -r include/* $out/include/ || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make libraries executable
|
||||||
|
chmod +x $out/lib/*.so* 2>/dev/null || true
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "MindVision Camera SDK";
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
239
flake.lock
generated
Normal file
239
flake.lock
generated
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"agenix": {
|
||||||
|
"inputs": {
|
||||||
|
"darwin": "darwin",
|
||||||
|
"home-manager": "home-manager",
|
||||||
|
"nixpkgs": [
|
||||||
|
"ragenix",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": "systems_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1761656077,
|
||||||
|
"narHash": "sha256-lsNWuj4Z+pE7s0bd2OKicOFq9bK86JE0ZGeKJbNqb94=",
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"rev": "9ba0d85de3eaa7afeab493fed622008b6e4924f5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"crane": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1760924934,
|
||||||
|
"narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=",
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"darwin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"ragenix",
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744478979,
|
||||||
|
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
|
||||||
|
"owner": "lnl7",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "lnl7",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_3"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"ragenix",
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1745494811,
|
||||||
|
"narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1769461804,
|
||||||
|
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ragenix": {
|
||||||
|
"inputs": {
|
||||||
|
"agenix": "agenix",
|
||||||
|
"crane": "crane",
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1761832913,
|
||||||
|
"narHash": "sha256-VCNVjjuRvrKPiYYwqhE3BAKIaReiKXGpxGp27lZ0MFM=",
|
||||||
|
"owner": "yaxitech",
|
||||||
|
"repo": "ragenix",
|
||||||
|
"rev": "83bccfdea758241999f32869fb6b36f7ac72f1ac",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "yaxitech",
|
||||||
|
"repo": "ragenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"ragenix": "ragenix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"ragenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1761791894,
|
||||||
|
"narHash": "sha256-myRIDh+PxaREz+z9LzbqBJF+SnTFJwkthKDX9zMyddY=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "59c45eb69d9222a4362673141e00ff77842cd219",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
176
flake.nix
Normal file
176
flake.nix
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
{
|
||||||
|
description = "USDA Vision camera management system";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
|
||||||
|
# For secrets management
|
||||||
|
ragenix = {
|
||||||
|
url = "github:yaxitech/ragenix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils, ragenix }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Import our package definition
|
||||||
|
usda-vision-package = pkgs.callPackage ./package.nix { };
|
||||||
|
camera-sdk = pkgs.callPackage ./camera-sdk.nix { };
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = {
|
||||||
|
default = usda-vision-package;
|
||||||
|
usda-vision = usda-vision-package;
|
||||||
|
camera-sdk = camera-sdk;
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
name = "usda-vision-dev";
|
||||||
|
|
||||||
|
# Input packages for the development shell
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
# Core development tools
|
||||||
|
git
|
||||||
|
vim
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
|
||||||
|
# Docker for local development
|
||||||
|
docker
|
||||||
|
docker-compose
|
||||||
|
|
||||||
|
# Supabase CLI
|
||||||
|
supabase-cli
|
||||||
|
|
||||||
|
# Node.js for web app development
|
||||||
|
nodejs_20
|
||||||
|
nodePackages.npm
|
||||||
|
nodePackages.pnpm
|
||||||
|
|
||||||
|
# Python for camera API
|
||||||
|
python311
|
||||||
|
python311Packages.pip
|
||||||
|
python311Packages.virtualenv
|
||||||
|
|
||||||
|
# Camera SDK
|
||||||
|
camera-sdk
|
||||||
|
|
||||||
|
# Secrets management
|
||||||
|
ragenix.packages.${system}.default
|
||||||
|
age
|
||||||
|
ssh-to-age
|
||||||
|
|
||||||
|
# Utilities
|
||||||
|
jq
|
||||||
|
yq
|
||||||
|
rsync
|
||||||
|
gnused
|
||||||
|
gawk
|
||||||
|
];
|
||||||
|
|
||||||
|
# Environment variables for development
|
||||||
|
shellHook = ''
|
||||||
|
export LD_LIBRARY_PATH="${camera-sdk}/lib:$LD_LIBRARY_PATH"
|
||||||
|
export CAMERA_SDK_PATH="${camera-sdk}"
|
||||||
|
|
||||||
|
# Set up Python virtual environment
|
||||||
|
if [ ! -d .venv ]; then
|
||||||
|
echo "Creating Python virtual environment..."
|
||||||
|
python -m venv .venv
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "USDA Vision Development Environment"
|
||||||
|
echo "===================================="
|
||||||
|
echo "Camera SDK: ${camera-sdk}"
|
||||||
|
echo ""
|
||||||
|
echo "Available commands:"
|
||||||
|
echo " - docker-compose: Manage containers"
|
||||||
|
echo " - supabase: Supabase CLI"
|
||||||
|
echo " - ragenix: Manage encrypted secrets"
|
||||||
|
echo " - age: Encrypt/decrypt files"
|
||||||
|
echo ""
|
||||||
|
echo "To activate Python venv: source .venv/bin/activate"
|
||||||
|
echo "To edit secrets: ragenix -e secrets/env.age"
|
||||||
|
echo ""
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Additional environment configuration
|
||||||
|
DOCKER_BUILDKIT = "1";
|
||||||
|
COMPOSE_DOCKER_CLI_BUILD = "1";
|
||||||
|
};
|
||||||
|
|
||||||
|
# NixOS module for easy integration
|
||||||
|
nixosModules.default = { config, lib, ... }: {
|
||||||
|
options.services.usda-vision = {
|
||||||
|
enable = lib.mkEnableOption "USDA Vision camera management system";
|
||||||
|
|
||||||
|
secretsFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = "Path to the ragenix-managed secrets file";
|
||||||
|
};
|
||||||
|
|
||||||
|
dataDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/usda-vision";
|
||||||
|
description = "Directory for USDA Vision application data";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.usda-vision.enable {
|
||||||
|
environment.systemPackages = [
|
||||||
|
usda-vision-package
|
||||||
|
camera-sdk
|
||||||
|
pkgs.docker-compose
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.variables.LD_LIBRARY_PATH = "${camera-sdk}/lib";
|
||||||
|
|
||||||
|
virtualisation.docker = {
|
||||||
|
enable = true;
|
||||||
|
autoPrune.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.usda-vision = {
|
||||||
|
description = "USDA Vision Docker Compose Stack";
|
||||||
|
after = [ "docker.service" "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
preStart = ''
|
||||||
|
# Sync application code
|
||||||
|
${pkgs.rsync}/bin/rsync -av --delete \
|
||||||
|
--checksum \
|
||||||
|
--exclude='node_modules' \
|
||||||
|
--exclude='.env' \
|
||||||
|
--exclude='__pycache__' \
|
||||||
|
--exclude='.venv' \
|
||||||
|
${usda-vision-package}/opt/usda-vision/ ${config.services.usda-vision.dataDir}/
|
||||||
|
|
||||||
|
# Copy secrets if managed by ragenix
|
||||||
|
if [ -f "${config.services.usda-vision.secretsFile}" ]; then
|
||||||
|
cp "${config.services.usda-vision.secretsFile}" ${config.services.usda-vision.dataDir}/.env
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
WorkingDirectory = config.services.usda-vision.dataDir;
|
||||||
|
ExecStart = "${pkgs.docker-compose}/bin/docker-compose up -d --build";
|
||||||
|
ExecStop = "${pkgs.docker-compose}/bin/docker-compose down";
|
||||||
|
TimeoutStartSec = 300;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
131
package.nix
Normal file
131
package.nix
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, makeWrapper
|
||||||
|
, rsync
|
||||||
|
, gnused
|
||||||
|
, gawk
|
||||||
|
, docker-compose
|
||||||
|
}:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "usda-vision";
|
||||||
|
version = "1.0.0";
|
||||||
|
|
||||||
|
# Use the directory from this repository with explicit source filtering
|
||||||
|
src = lib.cleanSourceWith {
|
||||||
|
src = ./.;
|
||||||
|
filter = path: type:
|
||||||
|
let
|
||||||
|
baseName = baseNameOf path;
|
||||||
|
in
|
||||||
|
# Exclude git, but include everything else
|
||||||
|
baseName != ".git" &&
|
||||||
|
baseName != ".cursor" &&
|
||||||
|
baseName != "__pycache__" &&
|
||||||
|
baseName != "node_modules" &&
|
||||||
|
baseName != ".venv" &&
|
||||||
|
baseName != ".age" &&
|
||||||
|
baseName != "flake.nix" &&
|
||||||
|
baseName != "flake.lock" &&
|
||||||
|
baseName != "package.nix" &&
|
||||||
|
baseName != "camera-sdk.nix";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [ makeWrapper rsync ];
|
||||||
|
|
||||||
|
# Don't run these phases, we'll do everything in installPhase
|
||||||
|
dontBuild = true;
|
||||||
|
dontConfigure = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/opt/usda-vision
|
||||||
|
|
||||||
|
# Debug: show what's in source
|
||||||
|
echo "Source directory contents:"
|
||||||
|
ls -la $src/ || true
|
||||||
|
|
||||||
|
# Process docker-compose.yml - replace paths and configure SDK from Nix
|
||||||
|
if [ -f $src/docker-compose.yml ]; then
|
||||||
|
# Basic path replacements with sed
|
||||||
|
${gnused}/bin/sed \
|
||||||
|
-e 's|env_file:.*management-dashboard-web-app/\.env|env_file: /var/lib/usda-vision/.env|g' \
|
||||||
|
-e 's|\./management-dashboard-web-app/\.env|/var/lib/usda-vision/.env|g' \
|
||||||
|
-e 's|\./management-dashboard-web-app|/var/lib/usda-vision/management-dashboard-web-app|g' \
|
||||||
|
-e 's|\./media-api|/var/lib/usda-vision/media-api|g' \
|
||||||
|
-e 's|\./video-remote|/var/lib/usda-vision/video-remote|g' \
|
||||||
|
-e 's|\./scheduling-remote|/var/lib/usda-vision/scheduling-remote|g' \
|
||||||
|
-e 's|\./vision-system-remote|/var/lib/usda-vision/vision-system-remote|g' \
|
||||||
|
-e 's|\./camera-management-api|/var/lib/usda-vision/camera-management-api|g' \
|
||||||
|
$src/docker-compose.yml > $TMPDIR/docker-compose-step1.yml
|
||||||
|
|
||||||
|
# Remove SDK installation blocks using awk for better multi-line handling
|
||||||
|
${gawk}/bin/awk '
|
||||||
|
/# Only install system packages if not already installed/ { skip=1 }
|
||||||
|
skip && /^ fi$/ { skip=0; next }
|
||||||
|
/# Install camera SDK if not already installed/ { skip_sdk=1 }
|
||||||
|
skip_sdk && /^ fi;$/ { skip_sdk=0; next }
|
||||||
|
!skip && !skip_sdk { print }
|
||||||
|
' $TMPDIR/docker-compose-step1.yml > $TMPDIR/docker-compose.yml
|
||||||
|
|
||||||
|
rm -f $TMPDIR/docker-compose-step1.yml
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy all application files using rsync with chmod
|
||||||
|
${rsync}/bin/rsync -av \
|
||||||
|
--chmod=Du+w \
|
||||||
|
--exclude='.git' \
|
||||||
|
--exclude='docker-compose.yml' \
|
||||||
|
--exclude='.env' \
|
||||||
|
--exclude='*.age' \
|
||||||
|
--exclude='flake.nix' \
|
||||||
|
--exclude='flake.lock' \
|
||||||
|
--exclude='package.nix' \
|
||||||
|
--exclude='camera-sdk.nix' \
|
||||||
|
--exclude='management-dashboard-web-app/.env' \
|
||||||
|
$src/ $out/opt/usda-vision/
|
||||||
|
|
||||||
|
# Copy the processed docker-compose.yml
|
||||||
|
if [ -f $TMPDIR/docker-compose.yml ]; then
|
||||||
|
cp $TMPDIR/docker-compose.yml $out/opt/usda-vision/docker-compose.yml
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify files were copied
|
||||||
|
echo "Destination directory contents:"
|
||||||
|
ls -la $out/opt/usda-vision/ || true
|
||||||
|
|
||||||
|
# Create convenience scripts
|
||||||
|
mkdir -p $out/bin
|
||||||
|
|
||||||
|
cat > $out/bin/usda-vision-start <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cd $out/opt/usda-vision
|
||||||
|
${docker-compose}/bin/docker-compose up -d --build
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > $out/bin/usda-vision-stop <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cd $out/opt/usda-vision
|
||||||
|
${docker-compose}/bin/docker-compose down
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > $out/bin/usda-vision-logs <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cd $out/opt/usda-vision
|
||||||
|
${docker-compose}/bin/docker-compose logs -f "$@"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > $out/bin/usda-vision-restart <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cd $out/opt/usda-vision
|
||||||
|
${docker-compose}/bin/docker-compose restart "$@"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x $out/bin/usda-vision-*
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "USDA Vision camera management system";
|
||||||
|
maintainers = [ "UGA Innovation Factory" ];
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
14
secrets.nix
Normal file
14
secrets.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Ragenix Configuration
|
||||||
|
# This file defines which secrets to manage and their permissions
|
||||||
|
|
||||||
|
let
|
||||||
|
# Import public keys from secrets.nix
|
||||||
|
keys = import ./secrets.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Main environment file
|
||||||
|
"env.age".publicKeys = keys.publicKeys;
|
||||||
|
|
||||||
|
# Azure OAuth configuration
|
||||||
|
"env.azure.age".publicKeys = keys.publicKeys;
|
||||||
|
}
|
||||||
11
secrets/.gitignore
vendored
Normal file
11
secrets/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Ignore unencrypted secrets
|
||||||
|
*.env
|
||||||
|
!*.env.example
|
||||||
|
.env.*
|
||||||
|
!.env.*.example
|
||||||
|
|
||||||
|
# Ignore age private keys (if accidentally placed here)
|
||||||
|
*.txt
|
||||||
|
|
||||||
|
# Keep encrypted files
|
||||||
|
!*.age
|
||||||
75
secrets/README.md
Normal file
75
secrets/README.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# USDA Vision Secrets Management
|
||||||
|
|
||||||
|
This directory contains encrypted secrets managed by [ragenix](https://github.com/yaxitech/ragenix).
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. **Generate an age key** (if you don't have one):
|
||||||
|
```bash
|
||||||
|
# Generate a new age key
|
||||||
|
age-keygen -o ~/.config/age/keys.txt
|
||||||
|
|
||||||
|
# Or convert your SSH key
|
||||||
|
ssh-to-age < ~/.ssh/id_ed25519.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Add your public key to `secrets.nix`**:
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
publicKeys = [
|
||||||
|
"age1..." # Your age public key
|
||||||
|
"ssh-ed25519 ..." # Or your SSH public key
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Create and encrypt environment files**:
|
||||||
|
```bash
|
||||||
|
# Create the encrypted .env file
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
|
||||||
|
# Create the encrypted .env.azure file
|
||||||
|
ragenix -e secrets/env.azure.age
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage in Development
|
||||||
|
|
||||||
|
In the development shell:
|
||||||
|
```bash
|
||||||
|
# Edit encrypted secrets
|
||||||
|
ragenix -e secrets/env.age
|
||||||
|
|
||||||
|
# Re-key secrets after adding a new public key
|
||||||
|
ragenix -r
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage in NixOS
|
||||||
|
|
||||||
|
The flake's NixOS module automatically handles decryption:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
services.usda-vision = {
|
||||||
|
enable = true;
|
||||||
|
secretsFile = config.age.secrets.usda-vision-env.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
age.secrets.usda-vision-env = {
|
||||||
|
file = ./usda-vision/secrets/env.age;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `secrets.nix` - Public keys configuration
|
||||||
|
- `env.age` - Encrypted main .env file
|
||||||
|
- `env.azure.age` - Encrypted Azure OAuth configuration
|
||||||
|
- `README.md` - This file
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- Never commit unencrypted `.env` files
|
||||||
|
- Keep your age private key secure (`~/.config/age/keys.txt`)
|
||||||
|
- The `.age` encrypted files are safe to commit to git
|
||||||
14
secrets/secrets.nix
Normal file
14
secrets/secrets.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Public keys for secret encryption
|
||||||
|
# Add your age or SSH public keys here
|
||||||
|
{
|
||||||
|
publicKeys = [
|
||||||
|
# Example age public key:
|
||||||
|
# "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3ekg8p"
|
||||||
|
|
||||||
|
# Example SSH public key (ed25519):
|
||||||
|
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@host"
|
||||||
|
|
||||||
|
# Add your keys below:
|
||||||
|
# TODO: Add your age or SSH public keys
|
||||||
|
];
|
||||||
|
}
|
||||||
77
setup-dev.sh
Executable file
77
setup-dev.sh
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Quick setup script for USDA Vision development
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "======================================"
|
||||||
|
echo "USDA Vision - Quick Setup"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if we're in the right directory
|
||||||
|
if [ ! -f "flake.nix" ]; then
|
||||||
|
echo "❌ Error: Must run from usda-vision directory"
|
||||||
|
echo " cd to the directory containing flake.nix"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for age key
|
||||||
|
if [ ! -f "$HOME/.config/age/keys.txt" ]; then
|
||||||
|
echo "📝 No age key found at ~/.config/age/keys.txt"
|
||||||
|
echo ""
|
||||||
|
read -p "Would you like to generate one? (y/n) " -n 1 -r
|
||||||
|
echo ""
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
mkdir -p "$HOME/.config/age"
|
||||||
|
age-keygen -o "$HOME/.config/age/keys.txt"
|
||||||
|
echo "✅ Age key generated!"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "❌ Cannot proceed without an age key"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get public key
|
||||||
|
AGE_PUBLIC_KEY=$(grep "public key:" "$HOME/.config/age/keys.txt" | cut -d: -f2 | xargs)
|
||||||
|
|
||||||
|
echo "Your age public key is:"
|
||||||
|
echo " $AGE_PUBLIC_KEY"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if key is already in secrets.nix
|
||||||
|
if grep -q "$AGE_PUBLIC_KEY" secrets/secrets.nix 2>/dev/null; then
|
||||||
|
echo "✅ Your key is already in secrets/secrets.nix"
|
||||||
|
else
|
||||||
|
echo "⚠️ Your key is NOT in secrets/secrets.nix"
|
||||||
|
echo ""
|
||||||
|
read -p "Would you like to add it now? (y/n) " -n 1 -r
|
||||||
|
echo ""
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
# Backup original
|
||||||
|
cp secrets/secrets.nix secrets/secrets.nix.backup
|
||||||
|
|
||||||
|
# Add the key
|
||||||
|
sed -i "/publicKeys = \[/a\ \"$AGE_PUBLIC_KEY\"" secrets/secrets.nix
|
||||||
|
|
||||||
|
echo "✅ Key added to secrets/secrets.nix"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "======================================"
|
||||||
|
echo "Setup complete! Next steps:"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
echo "1. Enter development environment:"
|
||||||
|
echo " $ nix develop"
|
||||||
|
echo ""
|
||||||
|
echo "2. Create/edit encrypted secrets:"
|
||||||
|
echo " $ ragenix -e secrets/env.age"
|
||||||
|
echo " $ ragenix -e secrets/env.azure.age"
|
||||||
|
echo ""
|
||||||
|
echo "3. Start development:"
|
||||||
|
echo " $ docker-compose up -d"
|
||||||
|
echo ""
|
||||||
|
echo "For more information, see FLAKE_SETUP.md"
|
||||||
|
echo ""
|
||||||
Reference in New Issue
Block a user