un-inception/docs/CI_PIPELINE.md
russell@unturf.com 90dc96c2c2 docs: Add CI pipeline architecture documentation
Explains inception testing pattern, pipeline stages, and how
42+ SDKs are tested with only a C compiler on the build server.
2026-01-17 09:23:03 -05:00

8.6 KiB

UN-Inception CI/CD Pipeline

Overview

The UN-Inception pipeline tests 42+ SDK implementations across 8 languages without requiring any language runtimes on the build server. It achieves this through inception testing - using the compiled C CLI to execute other SDKs through the unsandbox API.

Build Server (C only) → unsandbox API → SDK (Python/JS/etc) → unsandbox API → Test Code

Pipeline Stages

┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────────┐   ┌──────────┐   ┌──────────┐   ┌────────┐
│   PRE   │ → │  BUILD  │ → │  TEST   │ → │   SCIENCE   │ → │ VALIDATE │ → │ DOCUMENT │ → │ REPORT │
└─────────┘   └─────────┘   └─────────┘   └─────────────┘   └──────────┘   └──────────┘   └────────┘

Stage 1: PRE

detect-changes

  • Analyzes git diff to identify which SDKs changed
  • Outputs changes.json with list of affected languages
  • Enables selective testing (only test what changed)

generate-matrix

  • Reads changes.json
  • Generates test-matrix.yml with parallel test jobs
  • Each changed SDK gets its own test job

Stage 2: BUILD

build

  • Compiles the C CLI binary (build/un)
  • Dependencies: gcc, libcurl, libwebsockets, libssl
  • The C binary is the only compiled artifact needed
  • All other SDKs are interpreted and tested remotely
make -C clients/c cli
cp clients/c/un build/un

Stage 3: TEST (Dynamic Matrix)

Generated dynamically based on changed SDKs. Each job runs inception tests:

# Example: Testing Python SDK
build/un -n semitrusted \
    -e UNSANDBOX_PUBLIC_KEY=$KEY \
    -e UNSANDBOX_SECRET_KEY=$SECRET \
    clients/python/sync/src/un.py --help

build/un -n semitrusted \
    -e UNSANDBOX_PUBLIC_KEY=$KEY \
    -e UNSANDBOX_SECRET_KEY=$SECRET \
    clients/python/sync/src/un.py -s python 'print("test")'

What's happening:

  1. build/un (C CLI on build server) calls unsandbox API
  2. unsandbox runs un.py in a container with network access
  3. un.py calls the unsandbox API to execute test code
  4. Results bubble back through both layers

Stage 4: SCIENCE

Parallel jobs for extended validation:

science-validate-examples

  • Runs example code from all SDKs
  • Burns API pool credits for real-world testing

science-lint-sdks

  • Static analysis across SDK implementations
  • Checks for consistency and code quality

science-benchmark-clients

  • Performance testing of SDK implementations
  • Measures execution time and resource usage

Stage 5: VALIDATE

validate-examples

  • Aggregates results from science jobs
  • Generates summary statistics
  • Identifies failures across SDK matrix

Stage 6: DOCUMENT

generate-documentation

  • Auto-generates docs from test results
  • Creates verification timestamps
  • Updates SDK status information

Stage 7: REPORT

report

  • Final aggregation of all results
  • Generates JUnit XML for GitLab integration
  • Produces human-readable summary

The Inception Pattern

┌─────────────────────────────────────────────────────────────────────┐
│ Build Server                                                        │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ build/un (C binary)                                             │ │
│ │   └─→ POST api.unsandbox.com/execute                            │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Unsandbox Container (semitrusted network)                           │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ un.py / un.js / un.rb / etc                                     │ │
│ │   └─→ POST api.unsandbox.com/execute                            │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Unsandbox Container (isolated)                                      │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Test code execution                                             │ │
│ │   print("inception-test-ok")                                    │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

Build Server Requirements

Minimal dependencies - only what's needed to compile C:

apt install build-essential libcurl4-openssl-dev libwebsockets-dev libssl-dev

Not required: Python, Ruby, PHP, Go, Java, Rust, Node.js, etc.

All language runtimes exist in unsandbox containers, not on the build server.

Environment Variables

Required in GitLab CI/CD Settings → Variables:

Variable Description Protected Masked
UNSANDBOX_PUBLIC_KEY API public key Yes Yes
UNSANDBOX_SECRET_KEY API secret key Yes Yes

Artifacts

Each stage produces artifacts passed to subsequent stages:

Job Artifact Purpose
detect-changes changes.json List of changed SDKs
generate-matrix test-matrix.yml Dynamic test job definitions
build build/un Compiled C CLI
test-* test-results-*/ Per-SDK test results
science-* *-results/ Extended validation data
report final-report.xml JUnit results for GitLab

Triggering

Pipeline runs on:

  • Push to main branch
  • Tags matching v*.*.*

Local Testing

Test the inception pattern locally:

# Build C CLI
make -C clients/c cli

# Test Python SDK through inception
./clients/c/un -n semitrusted \
    -e UNSANDBOX_PUBLIC_KEY=$UNSANDBOX_PUBLIC_KEY \
    -e UNSANDBOX_SECRET_KEY=$UNSANDBOX_SECRET_KEY \
    clients/python/sync/src/un.py -s python 'print("hello")'

Files

.gitlab-ci.yml          # Pipeline definition
test-matrix.yml         # Placeholder (overwritten by generate-matrix)
scripts/
├── detect-changes.sh   # Identifies changed SDKs
├── generate-matrix.sh  # Creates dynamic test jobs
├── build-clients.sh    # Compiles C CLI
├── test-sdk.sh         # Runs inception tests
├── validate-examples.sh
├── filter-results.sh
└── science/
    ├── lint-all-sdks.sh
    └── benchmark-clients.sh