stabilize tests

This commit is contained in:
master
2026-02-01 21:37:40 +02:00
parent 55744f6a39
commit 5d5e80b2e4
6435 changed files with 33984 additions and 13802 deletions

View File

@@ -0,0 +1,49 @@
# =============================================================================
# LOCAL CI ENVIRONMENT VARIABLES
# =============================================================================
# Copy this file to .env.local and adjust values for your machine:
# cp .env.local.template .env.local
#
# .env.local is git-ignored. Do NOT commit secrets.
# =============================================================================
# ---------------------------------------------------------------------------
# Test toggles
# ---------------------------------------------------------------------------
# Set to 1 to enable RabbitMQ integration tests (requires running RabbitMQ)
STELLAOPS_TEST_RABBITMQ=0
# Set to 1 to enable Valkey/Redis integration tests (requires running Valkey)
STELLAOPS_TEST_VALKEY=0
# Enable full integration test suite (needs supporting services)
STELLAOPS_INTEGRATION_TESTS=false
# Enable live/external tests (network-dependent, not offline-safe)
STELLAOPS_LIVE_TESTS=false
# ---------------------------------------------------------------------------
# External service connections
# ---------------------------------------------------------------------------
# Testcontainers auto-configure PostgreSQL; only set for an external instance
STELLAOPS_TEST_POSTGRES_CONNECTION=
# MongoDB connection string (leave empty to skip Mongo-dependent tests)
STELLAOPS_TEST_MONGO_URI=
# ---------------------------------------------------------------------------
# HSM / crypto
# ---------------------------------------------------------------------------
# Path to SoftHSM2 shared library (leave empty to skip HSM tests)
# Linux: /usr/lib/softhsm/libsofthsm2.so
# macOS: /usr/local/lib/softhsm/libsofthsm2.so
# Windows: C:\SoftHSM2\lib\softhsm2-64.dll
STELLAOPS_SOFTHSM_LIB=
# ---------------------------------------------------------------------------
# .NET runtime
# ---------------------------------------------------------------------------
DOTNET_NOLOGO=1
DOTNET_CLI_TELEMETRY_OPTOUT=1
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
TZ=UTC

109
devops/ci-local/README.md Normal file
View File

@@ -0,0 +1,109 @@
# Local CI with act
Run Gitea CI workflows on your machine using [nektos/act](https://github.com/nektos/act) and the StellaOps CI Docker image.
## Prerequisites
| Tool | Install |
|------|---------|
| Docker Desktop | [docs.docker.com/get-docker](https://docs.docker.com/get-docker/) |
| act | **Windows:** `choco install act-cli` / **macOS:** `brew install act` / **Linux:** `curl -sSL https://raw.githubusercontent.com/nektos/act/master/install.sh \| sudo bash` |
Docker must be running before you invoke any command below.
## Quick start
```bash
# 1. Build the CI image (one-time, ~10 min first build)
docker build -t stellaops-ci:local -f devops/docker/Dockerfile.ci .
# 2. Copy the env template (edit as needed)
cp devops/ci-local/.env.local.template devops/ci-local/.env.local
# 3. List available jobs
act -l
# 4. Dry-run a workflow
act -W .gitea/workflows/test-matrix.yml -n
```
### Windows (PowerShell)
```powershell
.\devops\ci-local\run-act.ps1 -List
.\devops\ci-local\run-act.ps1 -Workflow test-matrix -DryRun
.\devops\ci-local\run-act.ps1 -Workflow build-test-deploy -Job build
```
### Linux / macOS
```bash
./devops/ci-local/run-act.sh --list
./devops/ci-local/run-act.sh --workflow test-matrix --dry-run
./devops/ci-local/run-act.sh --workflow build-test-deploy --job build
```
### Full-featured runner (bash only)
The `local-ci.sh` script supports additional modes beyond raw act invocation:
```bash
./devops/scripts/local-ci.sh smoke # Quick unit tests
./devops/scripts/local-ci.sh pr # Full PR-gating suite
./devops/scripts/local-ci.sh workflow --workflow test-matrix
./devops/scripts/local-ci.sh module --module Scanner
```
## Common workflows
| Workflow | What it tests | Example |
|----------|--------------|---------|
| `test-matrix.yml` | Unit + integration test matrix | `act -W .gitea/workflows/test-matrix.yml -n` |
| `build-test-deploy.yml` | Full build/test/deploy pipeline | `act -W .gitea/workflows/build-test-deploy.yml -n` |
| `scanner-analyzers.yml` | Scanner analyzer suite | `act -W .gitea/workflows/scanner-analyzers.yml -n` |
| `parity-tests.yml` | Cross-platform parity checks | `act -W .gitea/workflows/parity-tests.yml -n` |
| `integration-tests-gate.yml` | Integration test gate | `act -W .gitea/workflows/integration-tests-gate.yml -n` |
| `schema-validation.yml` | JSON/OAS schema validation | `act -W .gitea/workflows/schema-validation.yml -n` |
| `determinism-gate.yml` | Deterministic output checks | `act -W .gitea/workflows/determinism-gate.yml -n` |
## Environment variables
See `.env.local.template` for the full list. Key variables:
| Variable | Default | Purpose |
|----------|---------|---------|
| `STELLAOPS_TEST_RABBITMQ` | `0` | Set `1` to enable RabbitMQ tests |
| `STELLAOPS_TEST_VALKEY` | `0` | Set `1` to enable Valkey/Redis tests |
| `STELLAOPS_INTEGRATION_TESTS` | `false` | Enable integration test suite |
| `STELLAOPS_LIVE_TESTS` | `false` | Enable network-dependent tests |
| `STELLAOPS_SOFTHSM_LIB` | _(empty)_ | Path to SoftHSM2 library for HSM tests |
| `STELLAOPS_TEST_POSTGRES_CONNECTION` | _(empty)_ | External Postgres (Testcontainers auto-configure if empty) |
## Known limitations
- **Services block:** `act` does not natively support `services:` blocks in workflow YAML. Workflows that declare Postgres/Valkey/RabbitMQ services will need those services running externally (use `docker-compose.testing.yml`).
- **Secrets:** GitHub/Gitea-style secrets are not available locally. Use `.env.local` for test-only values. Never put production secrets in `.env.local`.
- **Artifact upload:** `act` provides a local artifact server (`--artifact-server-path ./out/act-artifacts`). Upload/download actions work but paths differ from real CI.
- **Composite actions:** Some nested composite actions may not resolve correctly under act.
## Troubleshooting
### Docker socket on Windows / WSL
If act cannot connect to Docker, ensure Docker Desktop has "Expose daemon on tcp://localhost:2375 without TLS" enabled, or use WSL 2 integration.
### OOM with parallel builds
The CI image runs .NET builds that can consume significant memory. If builds fail with OOM, increase Docker Desktop memory allocation (Settings > Resources > Memory) to at least 8 GB.
### MSYS path mangling (Git Bash on Windows)
Git Bash on Windows rewrites Unix-style paths. If act receives corrupted paths, prefix the command with `MSYS_NO_PATHCONV=1`:
```bash
MSYS_NO_PATHCONV=1 act -W .gitea/workflows/test-matrix.yml -n
```
### Container reuse issues
If you see stale state between runs, disable container reuse:
```bash
act --no-reuse -W .gitea/workflows/test-matrix.yml
```

View File

@@ -0,0 +1,14 @@
{
"action": "opened",
"number": 1,
"pull_request": {
"head": {
"ref": "feature-branch",
"sha": "abc1234567890abcdef1234567890abcdef123456"
},
"base": {
"ref": "main",
"sha": "def4567890abcdef1234567890abcdef12345678"
}
}
}

View File

@@ -0,0 +1,5 @@
{
"ref": "refs/heads/main",
"before": "0000000000000000000000000000000000000000",
"after": "abc1234567890abcdef1234567890abcdef123456"
}

162
devops/ci-local/run-act.ps1 Normal file
View File

@@ -0,0 +1,162 @@
<#
.SYNOPSIS
Run Gitea CI workflows locally using act.
.DESCRIPTION
PowerShell wrapper around nektos/act for local CI execution.
Builds the CI Docker image if needed, ensures .env.local exists,
and invokes act with the correct arguments.
.PARAMETER Workflow
Workflow file name (with or without .yml) under .gitea/workflows/.
.PARAMETER Job
Run only a specific job within the workflow.
.PARAMETER List
List all available workflow jobs without running them.
.PARAMETER DryRun
Dry-run mode (-n). Shows what would execute without running.
.PARAMETER Event
Event type to simulate: pull_request (default) or push.
.PARAMETER Rebuild
Force rebuild of the CI Docker image.
.PARAMETER ActVerbose
Enable verbose act output.
.EXAMPLE
.\run-act.ps1 -List
.\run-act.ps1 -Workflow test-matrix -DryRun
.\run-act.ps1 -Workflow build-test-deploy -Job build
.\run-act.ps1 -Event push -Workflow release-validation
#>
[CmdletBinding()]
param(
[string]$Workflow,
[string]$Job,
[switch]$List,
[switch]$DryRun,
[ValidateSet('pull_request', 'push')]
[string]$Event = 'pull_request',
[switch]$Rebuild,
[switch]$ActVerbose
)
$ErrorActionPreference = 'Stop'
# Resolve paths
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RepoRoot = (Resolve-Path "$ScriptDir\..\..").Path
$CiLocalDir = $ScriptDir
$CiImage = 'stellaops-ci:local'
$Dockerfile = Join-Path $RepoRoot 'devops\docker\Dockerfile.ci'
# ---- Prerequisite checks ----
# Docker
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
Write-Error "Docker is not installed or not in PATH."
exit 1
}
$ErrorActionPreference = 'Continue'
$null = docker info 2>$null
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE -ne 0) {
Write-Error "Docker is not running. Start Docker Desktop and try again."
exit 1
}
# act
if (-not (Get-Command act -ErrorAction SilentlyContinue)) {
Write-Error "act is not installed. Install with: choco install act-cli"
exit 1
}
# ---- Build CI image if needed ----
docker image inspect $CiImage 2>&1 | Out-Null
$imageExists = $LASTEXITCODE -eq 0
if ($Rebuild -or -not $imageExists) {
Write-Host "[ci-local] Building CI image $CiImage ..." -ForegroundColor Cyan
docker build -t $CiImage -f $Dockerfile $RepoRoot
if ($LASTEXITCODE -ne 0) {
Write-Error "CI image build failed."
exit 1
}
}
# ---- Ensure .env.local exists ----
$envLocal = Join-Path $CiLocalDir '.env.local'
$envTemplate = Join-Path $CiLocalDir '.env.local.template'
if (-not (Test-Path $envLocal)) {
Write-Host "[ci-local] Creating .env.local from template ..." -ForegroundColor Yellow
Copy-Item $envTemplate $envLocal
}
# ---- Assemble act arguments ----
$actArgs = @()
# List mode
if ($List) {
$actArgs += '-l'
Push-Location $RepoRoot
try { act @actArgs }
finally { Pop-Location }
exit $LASTEXITCODE
}
# Workflow
if ($Workflow) {
$wfFile = $Workflow
if (-not $wfFile.EndsWith('.yml')) { $wfFile = "$wfFile.yml" }
$wfPath = Join-Path $RepoRoot ".gitea\workflows\$wfFile"
if (-not (Test-Path $wfPath)) {
Write-Error "Workflow not found: $wfPath"
exit 1
}
$actArgs += '-W', $wfPath
}
# Job filter
if ($Job) {
$actArgs += '-j', $Job
}
# Event file
$eventMap = @{
'pull_request' = Join-Path $CiLocalDir 'events\pull-request.json'
'push' = Join-Path $CiLocalDir 'events\push.json'
}
$eventFile = $eventMap[$Event]
if (Test-Path $eventFile) {
$actArgs += '--eventpath', $eventFile
}
# Dry run
if ($DryRun) {
$actArgs += '-n'
}
# Verbose
if ($ActVerbose) {
$actArgs += '--verbose'
}
# ---- Run act ----
Write-Host "[ci-local] act $($actArgs -join ' ')" -ForegroundColor Cyan
Push-Location $RepoRoot
try {
act @actArgs
exit $LASTEXITCODE
}
finally {
Pop-Location
}

140
devops/ci-local/run-act.sh Normal file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env bash
# =============================================================================
# LOCAL ACT RUNNER (Bash)
# =============================================================================
# Thin wrapper around nektos/act for local CI execution.
# For full-featured local CI (smoke, pr, module modes) use:
# ./devops/scripts/local-ci.sh
#
# Usage:
# ./devops/ci-local/run-act.sh [options]
#
# Options:
# -w, --workflow <name> Workflow file (with or without .yml)
# -j, --job <name> Run only a specific job
# -l, --list List available jobs
# -n, --dry-run Dry-run mode
# -e, --event <type> Event type: pull_request (default) or push
# -r, --rebuild Force rebuild CI image
# -v, --verbose Verbose output
# -h, --help Show this help
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CI_IMAGE="stellaops-ci:local"
CI_DOCKERFILE="$REPO_ROOT/devops/docker/Dockerfile.ci"
# Defaults
WORKFLOW=""
JOB=""
LIST=false
DRY_RUN=false
EVENT="pull_request"
REBUILD=false
VERBOSE=false
usage() {
head -25 "$0" | grep '^#' | sed 's/^# \?//'
exit 0
}
# ---- Parse args ----
while [[ $# -gt 0 ]]; do
case "$1" in
-w|--workflow) WORKFLOW="$2"; shift 2 ;;
-j|--job) JOB="$2"; shift 2 ;;
-l|--list) LIST=true; shift ;;
-n|--dry-run) DRY_RUN=true; shift ;;
-e|--event) EVENT="$2"; shift 2 ;;
-r|--rebuild) REBUILD=true; shift ;;
-v|--verbose) VERBOSE=true; shift ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
# ---- Prerequisite checks ----
if ! docker info &>/dev/null; then
echo "ERROR: Docker is not running." >&2
exit 1
fi
if ! command -v act &>/dev/null; then
echo "ERROR: act is not installed." >&2
echo " macOS: brew install act" >&2
echo " Linux: curl -sSL https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash" >&2
echo " Windows: choco install act-cli" >&2
exit 1
fi
# ---- Build CI image if needed ----
image_exists() {
docker image inspect "$CI_IMAGE" &>/dev/null
}
if [[ "$REBUILD" == "true" ]] || ! image_exists; then
echo "[ci-local] Building CI image $CI_IMAGE ..."
docker build -t "$CI_IMAGE" -f "$CI_DOCKERFILE" "$REPO_ROOT"
fi
# ---- Ensure .env.local ----
ENV_LOCAL="$SCRIPT_DIR/.env.local"
if [[ ! -f "$ENV_LOCAL" ]]; then
echo "[ci-local] Creating .env.local from template ..."
cp "$SCRIPT_DIR/.env.local.template" "$ENV_LOCAL"
fi
# ---- Assemble act arguments ----
act_args=()
if [[ "$LIST" == "true" ]]; then
cd "$REPO_ROOT"
exec act -l
fi
if [[ -n "$WORKFLOW" ]]; then
wf_file="$WORKFLOW"
[[ "$wf_file" != *.yml ]] && wf_file="${wf_file}.yml"
wf_path="$REPO_ROOT/.gitea/workflows/$wf_file"
if [[ ! -f "$wf_path" ]]; then
echo "ERROR: Workflow not found: $wf_path" >&2
exit 1
fi
act_args+=(-W "$wf_path")
fi
if [[ -n "$JOB" ]]; then
act_args+=(-j "$JOB")
fi
# Event file
case "$EVENT" in
pull_request) event_file="$SCRIPT_DIR/events/pull-request.json" ;;
push) event_file="$SCRIPT_DIR/events/push.json" ;;
*) echo "ERROR: Unknown event type: $EVENT" >&2; exit 1 ;;
esac
if [[ -f "$event_file" ]]; then
act_args+=(--eventpath "$event_file")
fi
if [[ "$DRY_RUN" == "true" ]]; then
act_args+=(-n)
fi
if [[ "$VERBOSE" == "true" ]]; then
act_args+=(--verbose)
fi
# ---- Run ----
echo "[ci-local] act ${act_args[*]}"
cd "$REPO_ROOT"
exec act "${act_args[@]}"