Add NixOS VM integration tests and update CI/CD pipeline configuration. Introduce checks for backend integration, full-stack, performance, and security tests using native NixOS services. Remove legacy GitHub Actions workflow and replace with Gitea Actions runner configuration. Update README and quickstart guide to reflect new development environment setup and testing commands.

This commit is contained in:
Danilo Reyes
2025-11-01 23:04:32 -06:00
parent 1bc657e0fd
commit 6dea130421
9 changed files with 744 additions and 277 deletions

112
nixos/gitea-runner.nix Normal file
View File

@@ -0,0 +1,112 @@
{ config, pkgs, lib, ... }:
{
# Gitea Actions Runner Configuration
# This module configures a Gitea runner for CI/CD with Nix support
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
bash
coreutils
curl
git
nix
# Project-specific
nodejs
python3
postgresql
# Binary cache
attic-client
# Container runtime (optional)
docker
docker-compose
];
};
};
};
# Enable Docker for service containers (PostgreSQL, MinIO, etc.)
virtualisation.docker = {
enable = true;
autoPrune.enable = true;
autoPrune.dates = "weekly";
};
# Ensure the runner user has access to Docker
users.users.gitea-runner = {
isSystemUser = true;
group = "gitea-runner";
extraGroups = [ "docker" ];
};
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" ];
# Optimize for CI performance
max-jobs = "auto";
cores = 0; # Use all available cores
};
# Network access for downloading packages
networking.firewall = {
# If your runner needs to expose ports, configure them here
# allowedTCPPorts = [ ];
};
# Systemd service optimizations
systemd.services."gitea-runner-webref-runner" = {
serviceConfig = {
# Resource limits (adjust based on your hardware)
MemoryMax = "8G";
CPUQuota = "400%"; # 4 cores
# Restart policy
Restart = "always";
RestartSec = "10s";
};
};
}

211
nixos/tests.nix Normal file
View File

@@ -0,0 +1,211 @@
{ pkgs, ... }:
let
# Import the flake to get our packages
webref = builtins.getFlake (toString ../.);
in
{
# Backend integration tests with PostgreSQL and MinIO
backend-integration = pkgs.nixosTest {
name = "webref-backend-integration";
nodes = {
machine = { config, pkgs, ... }: {
# PostgreSQL service
services.postgresql = {
enable = true;
ensureDatabases = [ "webref_test" ];
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
'';
};
# Ensure our dev environment is available
environment.systemPackages = with pkgs; [
webref.devShells.${system}.default.inputDerivation
];
# 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)
# Create test database
machine.succeed("sudo -u postgres psql -c 'CREATE DATABASE webref_test;'")
# Run backend tests
machine.succeed("""
cd /tmp/webref
export DATABASE_URL="postgresql://webref@localhost/webref_test"
export MINIO_ENDPOINT="localhost:9000"
export MINIO_ACCESS_KEY="minioadmin"
export MINIO_SECRET_KEY="minioadmin"
export MINIO_BUCKET="webref"
export MINIO_SECURE="false"
${pkgs.python3}/bin/python -m pytest backend/tests/ -v
""")
machine.succeed("echo ' Backend integration tests passed'")
'';
};
# Full stack test with backend + frontend + database
full-stack = pkgs.nixosTest {
name = "webref-full-stack";
nodes = {
server = { config, 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
'';
};
# Backend API (FastAPI)
systemd.services.webref-backend = {
description = "WebRef Backend API";
after = [ "postgresql.service" "minio.service" ];
wantedBy = [ "multi-user.target" ];
environment = {
DATABASE_URL = "postgresql://webref@localhost/webref";
MINIO_ENDPOINT = "localhost:9000";
MINIO_ACCESS_KEY = "minioadmin";
MINIO_SECRET_KEY = "minioadmin";
SECRET_KEY = "test-secret-key-do-not-use-in-production";
};
serviceConfig = {
ExecStart = "${pkgs.python3}/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000";
WorkingDirectory = "/tmp/webref/backend";
Restart = "always";
};
};
networking.firewall.allowedTCPPorts = [ 8000 9000 ];
};
client = { config, pkgs, ... }: {
environment.systemPackages = [ pkgs.curl pkgs.jq ];
};
};
testScript = ''
start_all()
# Wait for all services
server.wait_for_unit("postgresql.service")
server.wait_for_unit("minio.service")
server.wait_for_unit("webref-backend.service")
server.wait_for_open_port(8000)
# Test API health
client.wait_for_unit("multi-user.target")
client.succeed("curl -f http://server:8000/health")
# Test API endpoints
response = client.succeed("curl -s http://server:8000/health | jq -r .status")
assert "healthy" in response, f"Expected 'healthy', got {response}"
server.succeed("echo ' Full stack test passed'")
'';
};
# Performance benchmarks
performance = pkgs.nixosTest {
name = "webref-performance";
nodes = {
machine = { config, pkgs, ... }: {
services.postgresql.enable = true;
services.minio.enable = true;
environment.systemPackages = with pkgs; [
apache-bench
wrk
];
};
};
testScript = ''
start_all()
machine.wait_for_unit("postgresql.service")
# Run performance tests
machine.succeed("""
cd /tmp/webref/backend
${pkgs.python3}/bin/pytest tests/performance/ --benchmark-only
""")
machine.succeed("echo ' Performance tests passed'")
'';
};
# Security tests
security = pkgs.nixosTest {
name = "webref-security";
nodes = {
machine = { config, pkgs, ... }: {
services.postgresql.enable = true;
environment.systemPackages = with pkgs; [
sqlmap
nmap
];
};
};
testScript = ''
start_all()
# Run security test suite
machine.succeed("""
cd /tmp/webref/backend
${pkgs.python3}/bin/pytest tests/security/ -v
""")
machine.succeed("echo ' Security tests passed'")
'';
};
}