001-reference-board-viewer #1
136
flake.nix
136
flake.nix
@@ -6,37 +6,41 @@
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
outputs =
|
||||
{ self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
pythonEnv = pkgs.python3.withPackages (ps: with ps; [
|
||||
# Core backend dependencies
|
||||
fastapi
|
||||
uvicorn
|
||||
sqlalchemy
|
||||
alembic
|
||||
pydantic
|
||||
pydantic-settings # Settings management
|
||||
psycopg2 # PostgreSQL driver
|
||||
# Auth & Security
|
||||
python-jose
|
||||
passlib
|
||||
bcrypt # Password hashing backend for passlib
|
||||
email-validator # Email validation for pydantic
|
||||
# Image processing
|
||||
pillow
|
||||
# Storage
|
||||
boto3
|
||||
# HTTP & uploads
|
||||
httpx
|
||||
python-multipart
|
||||
# Testing
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-asyncio
|
||||
]);
|
||||
|
||||
pythonEnv = pkgs.python3.withPackages (
|
||||
ps: with ps; [
|
||||
# Core backend dependencies
|
||||
fastapi
|
||||
uvicorn
|
||||
sqlalchemy
|
||||
alembic
|
||||
pydantic
|
||||
pydantic-settings # Settings management
|
||||
psycopg2 # PostgreSQL driver
|
||||
# Auth & Security
|
||||
python-jose
|
||||
passlib
|
||||
bcrypt # Password hashing backend for passlib
|
||||
email-validator # Email validation for pydantic
|
||||
# Image processing
|
||||
pillow
|
||||
# Storage
|
||||
boto3
|
||||
# HTTP & uploads
|
||||
httpx
|
||||
python-multipart
|
||||
# Testing
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-asyncio
|
||||
]
|
||||
);
|
||||
in
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
@@ -45,25 +49,25 @@
|
||||
pythonEnv
|
||||
uv
|
||||
ruff
|
||||
|
||||
|
||||
# Database
|
||||
postgresql
|
||||
|
||||
|
||||
# Frontend
|
||||
nodejs
|
||||
nodePackages.npm
|
||||
|
||||
|
||||
# Image processing
|
||||
imagemagick
|
||||
|
||||
|
||||
# Storage
|
||||
minio
|
||||
minio-client
|
||||
|
||||
|
||||
# Development tools
|
||||
git
|
||||
direnv
|
||||
|
||||
|
||||
# Optional: monitoring/debugging
|
||||
# redis
|
||||
];
|
||||
@@ -89,7 +93,7 @@
|
||||
echo " App: http://localhost:5173"
|
||||
echo " MinIO UI: http://localhost:9001"
|
||||
echo ""
|
||||
|
||||
|
||||
# Set up environment variables
|
||||
export DATABASE_URL="postgresql://localhost/webref"
|
||||
export PYTHONPATH="$PWD/backend:$PYTHONPATH"
|
||||
@@ -98,12 +102,24 @@
|
||||
|
||||
# Apps - Scripts that can be run with `nix run`
|
||||
apps = {
|
||||
default = {
|
||||
type = "app";
|
||||
program = "${pkgs.writeShellScript "help" ''
|
||||
echo "Available commands:"
|
||||
echo " nix run .#lint - Run linting checks"
|
||||
echo " nix run .#lint-fix - Auto-fix linting issues"
|
||||
''}";
|
||||
meta = {
|
||||
description = "Show available commands";
|
||||
};
|
||||
};
|
||||
|
||||
# Unified linting for all code
|
||||
lint = {
|
||||
type = "app";
|
||||
program = "${pkgs.writeShellScript "lint" ''
|
||||
set -e
|
||||
|
||||
|
||||
# Backend Python linting
|
||||
echo "🔍 Linting backend Python code..."
|
||||
if [ -d "backend" ]; then
|
||||
@@ -115,7 +131,7 @@
|
||||
echo "⚠ Not in project root (backend/ not found)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Frontend linting (if node_modules exists)
|
||||
if [ -d "frontend/node_modules" ]; then
|
||||
echo ""
|
||||
@@ -128,18 +144,21 @@
|
||||
else
|
||||
echo "⚠ Frontend node_modules not found, run 'npm install' first"
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "✅ All linting checks passed!"
|
||||
''}";
|
||||
meta = {
|
||||
description = "Run linting checks on backend and frontend code";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
# Auto-fix linting issues
|
||||
lint-fix = {
|
||||
type = "app";
|
||||
program = "${pkgs.writeShellScript "lint-fix" ''
|
||||
set -e
|
||||
|
||||
|
||||
echo "🔧 Auto-fixing backend Python code..."
|
||||
if [ -d "backend" ]; then
|
||||
cd backend
|
||||
@@ -150,7 +169,7 @@
|
||||
echo "⚠ Not in project root (backend/ not found)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ -d "frontend/node_modules" ]; then
|
||||
echo ""
|
||||
echo "🔧 Auto-fixing frontend code..."
|
||||
@@ -158,33 +177,52 @@
|
||||
${pkgs.nodePackages.prettier}/bin/prettier --write src/
|
||||
cd ..
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "✅ Auto-fix complete!"
|
||||
''}";
|
||||
meta = {
|
||||
description = "Auto-fix linting issues in backend and frontend code";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Package definitions (for production deployment)
|
||||
packages = {
|
||||
packages = rec {
|
||||
# Backend package
|
||||
backend = pkgs.python3Packages.buildPythonApplication {
|
||||
pname = "webref-backend";
|
||||
version = "1.0.0";
|
||||
pyproject = true;
|
||||
src = ./backend;
|
||||
|
||||
build-system = with pkgs.python3Packages; [
|
||||
setuptools
|
||||
];
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [
|
||||
fastapi
|
||||
uvicorn
|
||||
sqlalchemy
|
||||
alembic
|
||||
pydantic
|
||||
pydantic-settings
|
||||
psycopg2
|
||||
python-jose
|
||||
passlib
|
||||
pillow
|
||||
boto3
|
||||
httpx
|
||||
python-multipart
|
||||
email-validator
|
||||
bcrypt
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "Reference Board Viewer - Backend API";
|
||||
homepage = "https://github.com/yourusername/webref";
|
||||
license = pkgs.lib.licenses.mit;
|
||||
};
|
||||
};
|
||||
|
||||
# Frontend package
|
||||
@@ -192,7 +230,7 @@
|
||||
pname = "webref-frontend";
|
||||
version = "1.0.0";
|
||||
src = ./frontend;
|
||||
npmDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Update after first build
|
||||
npmDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Update after first build
|
||||
buildPhase = ''
|
||||
npm run build
|
||||
'';
|
||||
@@ -200,7 +238,14 @@
|
||||
mkdir -p $out
|
||||
cp -r build/* $out/
|
||||
'';
|
||||
meta = {
|
||||
description = "Reference Board Viewer - Frontend SPA";
|
||||
homepage = "https://github.com/yourusername/webref";
|
||||
license = pkgs.lib.licenses.mit;
|
||||
};
|
||||
};
|
||||
|
||||
default = backend;
|
||||
};
|
||||
|
||||
# NixOS VM tests
|
||||
@@ -208,4 +253,3 @@
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
# Gitea Actions Runner Configuration
|
||||
@@ -6,36 +6,36 @@
|
||||
|
||||
services.gitea-actions-runner = {
|
||||
package = pkgs.gitea-actions-runner;
|
||||
|
||||
|
||||
instances = {
|
||||
# Main runner instance for webref project
|
||||
webref-runner = {
|
||||
enable = true;
|
||||
|
||||
|
||||
# Runner name (will appear in Gitea)
|
||||
name = "nixos-runner-webref";
|
||||
|
||||
|
||||
# Gitea instance URL
|
||||
url = "https://your-gitea-instance.com";
|
||||
|
||||
|
||||
# Runner token - Generate this from Gitea:
|
||||
# Settings -> Actions -> Runners -> Create New Runner
|
||||
# Store the token in a file and reference it here
|
||||
tokenFile = "/var/secrets/gitea-runner-token";
|
||||
|
||||
|
||||
# Labels define what jobs this runner can handle
|
||||
# Format: "label:docker_image" or just "label" for host execution
|
||||
labels = [
|
||||
# Native execution with Nix
|
||||
"nix:native"
|
||||
|
||||
|
||||
# Ubuntu-like for compatibility
|
||||
"ubuntu-latest:docker://node:20-bookworm"
|
||||
|
||||
|
||||
# Specific for this project
|
||||
"webref:native"
|
||||
];
|
||||
|
||||
|
||||
# Host packages available to the runner
|
||||
hostPackages = with pkgs; [
|
||||
# Essential tools
|
||||
@@ -44,15 +44,15 @@
|
||||
curl
|
||||
git
|
||||
nix
|
||||
|
||||
|
||||
# Project-specific
|
||||
nodejs
|
||||
python3
|
||||
postgresql
|
||||
|
||||
|
||||
# Binary cache
|
||||
attic-client
|
||||
|
||||
|
||||
# Container runtime (optional)
|
||||
docker
|
||||
docker-compose
|
||||
@@ -75,16 +75,19 @@
|
||||
extraGroups = [ "docker" ];
|
||||
};
|
||||
|
||||
users.groups.gitea-runner = {};
|
||||
users.groups.gitea-runner = { };
|
||||
|
||||
# Allow runner to use Nix
|
||||
nix.settings = {
|
||||
allowed-users = [ "gitea-runner" ];
|
||||
trusted-users = [ "gitea-runner" ];
|
||||
|
||||
|
||||
# Enable flakes for the runner
|
||||
experimental-features = [ "nix-command" "flakes" ];
|
||||
|
||||
experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
|
||||
# Optimize for CI performance
|
||||
max-jobs = "auto";
|
||||
cores = 0; # Use all available cores
|
||||
@@ -102,11 +105,10 @@
|
||||
# Resource limits (adjust based on your hardware)
|
||||
MemoryMax = "8G";
|
||||
CPUQuota = "400%"; # 4 cores
|
||||
|
||||
|
||||
# Restart policy
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
248
nixos/tests.nix
248
nixos/tests.nix
@@ -4,189 +4,203 @@
|
||||
# Backend integration tests with PostgreSQL and MinIO
|
||||
backend-integration = pkgs.testers.nixosTest {
|
||||
name = "webref-backend-integration";
|
||||
|
||||
|
||||
nodes = {
|
||||
machine = { config, pkgs, ... }: {
|
||||
# PostgreSQL service
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "webref" ];
|
||||
ensureUsers = [{
|
||||
name = "webref";
|
||||
ensureDBOwnership = true;
|
||||
}];
|
||||
authentication = ''
|
||||
local all all trust
|
||||
host all all 127.0.0.1/32 trust
|
||||
host all all ::1/128 trust
|
||||
'';
|
||||
machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# PostgreSQL service
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "webref" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "webref";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
authentication = ''
|
||||
local all all trust
|
||||
host all all 127.0.0.1/32 trust
|
||||
host all all ::1/128 trust
|
||||
'';
|
||||
};
|
||||
|
||||
# MinIO service
|
||||
services.minio = {
|
||||
enable = true;
|
||||
rootCredentialsFile = pkgs.writeText "minio-credentials" ''
|
||||
MINIO_ROOT_USER=minioadmin
|
||||
MINIO_ROOT_PASSWORD=minioadmin
|
||||
'';
|
||||
};
|
||||
|
||||
# Install required packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
python3Packages.pytest
|
||||
python3Packages.fastapi
|
||||
postgresql
|
||||
curl
|
||||
];
|
||||
|
||||
# Network configuration
|
||||
networking.firewall.enable = false;
|
||||
};
|
||||
|
||||
# MinIO service
|
||||
services.minio = {
|
||||
enable = true;
|
||||
rootCredentialsFile = pkgs.writeText "minio-credentials" ''
|
||||
MINIO_ROOT_USER=minioadmin
|
||||
MINIO_ROOT_PASSWORD=minioadmin
|
||||
'';
|
||||
};
|
||||
|
||||
# Install required packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
python3Packages.pytest
|
||||
python3Packages.fastapi
|
||||
postgresql
|
||||
curl
|
||||
];
|
||||
|
||||
# Network configuration
|
||||
networking.firewall.enable = false;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
|
||||
# Wait for PostgreSQL
|
||||
machine.wait_for_unit("postgresql.service")
|
||||
machine.wait_for_open_port(5432)
|
||||
|
||||
|
||||
# Wait for MinIO
|
||||
machine.wait_for_unit("minio.service")
|
||||
machine.wait_for_open_port(9000)
|
||||
|
||||
|
||||
# Verify PostgreSQL is working
|
||||
machine.succeed("sudo -u postgres psql -c 'SELECT 1;'")
|
||||
|
||||
|
||||
# Verify MinIO is working
|
||||
machine.succeed("curl -f http://localhost:9000/minio/health/live")
|
||||
|
||||
|
||||
machine.succeed("echo '✅ Backend integration test passed'")
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
# Full stack test with backend + database
|
||||
full-stack = pkgs.testers.nixosTest {
|
||||
name = "webref-full-stack";
|
||||
|
||||
|
||||
nodes = {
|
||||
machine = { config, pkgs, ... }: {
|
||||
# PostgreSQL
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "webref" ];
|
||||
ensureUsers = [{
|
||||
name = "webref";
|
||||
ensureDBOwnership = true;
|
||||
}];
|
||||
machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# PostgreSQL
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "webref" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "webref";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# MinIO
|
||||
services.minio = {
|
||||
enable = true;
|
||||
rootCredentialsFile = pkgs.writeText "minio-credentials" ''
|
||||
MINIO_ROOT_USER=minioadmin
|
||||
MINIO_ROOT_PASSWORD=minioadmin
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
curl
|
||||
jq
|
||||
];
|
||||
|
||||
networking.firewall.enable = false;
|
||||
};
|
||||
|
||||
# MinIO
|
||||
services.minio = {
|
||||
enable = true;
|
||||
rootCredentialsFile = pkgs.writeText "minio-credentials" ''
|
||||
MINIO_ROOT_USER=minioadmin
|
||||
MINIO_ROOT_PASSWORD=minioadmin
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
curl
|
||||
jq
|
||||
];
|
||||
|
||||
networking.firewall.enable = false;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
|
||||
# Wait for services
|
||||
machine.wait_for_unit("postgresql.service")
|
||||
machine.wait_for_unit("minio.service")
|
||||
machine.wait_for_open_port(5432)
|
||||
machine.wait_for_open_port(9000)
|
||||
|
||||
|
||||
# Test database connectivity
|
||||
machine.succeed("sudo -u postgres psql -c 'SELECT version();'")
|
||||
|
||||
|
||||
# Test MinIO API
|
||||
machine.succeed("curl -f http://localhost:9000/minio/health/live")
|
||||
|
||||
|
||||
machine.succeed("echo '✅ Full stack test passed'")
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
# Performance benchmarks
|
||||
performance = pkgs.testers.nixosTest {
|
||||
name = "webref-performance";
|
||||
|
||||
|
||||
nodes = {
|
||||
machine = { config, pkgs, ... }: {
|
||||
services.postgresql.enable = true;
|
||||
services.minio.enable = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
];
|
||||
};
|
||||
machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.postgresql.enable = true;
|
||||
services.minio.enable = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("postgresql.service")
|
||||
|
||||
|
||||
machine.succeed("echo '✅ Performance test passed'")
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
# Security tests
|
||||
security = pkgs.testers.nixosTest {
|
||||
name = "webref-security";
|
||||
|
||||
|
||||
nodes = {
|
||||
machine = { config, pkgs, ... }: {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "webref" ];
|
||||
ensureUsers = [{
|
||||
name = "webref";
|
||||
ensureDBOwnership = true;
|
||||
}];
|
||||
machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "webref" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "webref";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Create system user for testing
|
||||
users.users.webref = {
|
||||
isSystemUser = true;
|
||||
group = "webref";
|
||||
};
|
||||
users.groups.webref = { };
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
nmap
|
||||
];
|
||||
};
|
||||
|
||||
# Create system user for testing
|
||||
users.users.webref = {
|
||||
isSystemUser = true;
|
||||
group = "webref";
|
||||
};
|
||||
users.groups.webref = {};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
python3
|
||||
nmap
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("postgresql.service")
|
||||
|
||||
|
||||
# Wait for PostgreSQL setup scripts to complete (database and user creation)
|
||||
import time
|
||||
machine.wait_for_unit("postgresql-setup.service", timeout=30)
|
||||
time.sleep(2) # Give it a moment to finalize
|
||||
|
||||
|
||||
# Verify database role exists
|
||||
machine.succeed("sudo -u postgres psql -c '\\du' | grep webref")
|
||||
|
||||
|
||||
# Verify database is accessible with webref user
|
||||
machine.succeed("sudo -u webref psql webref -c 'SELECT 1;'")
|
||||
|
||||
|
||||
machine.succeed("echo '✅ Security test passed'")
|
||||
'';
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user