stella CLI - Build and Distribution Matrix

Sprint: SPRINT_4100_0006_0006 - CLI Documentation Overhaul

Overview

StellaOps CLI is distributed in four regional variants to comply with export control regulations and cryptographic standards. Each distribution includes different cryptographic plugins based on regional requirements.

Key Principles:

  1. Build-time Selection: Crypto plugins are conditionally compiled based on build flags
  2. Export Compliance: Each distribution complies with export control laws
  3. Deterministic Builds: Same source + flags = same binary (reproducible builds)
  4. Validation: Automated validation ensures correct plugin inclusion

Distribution Matrix

DistributionCrypto PluginsBuild FlagTarget AudienceExport Restrictions
stella-internationalDefault (.NET, BouncyCastle)NoneGlobal (unrestricted)✅ No restrictions
stella-russiaDefault + GOSTStellaOpsEnableGOST=trueRussia, CIS states⚠️ Russia/CIS only
stella-euDefault + eIDASStellaOpsEnableEIDAS=trueEuropean Union⚠️ EU/EEA only
stella-chinaDefault + SMStellaOpsEnableSM=trueChina⚠️ China only

The MSBuild property is the complete selector: the CLI project defines the matching STELLAOPS_ENABLE_* constant and includes the regional project references. Do not pass a separate DefineConstants override.

At startup, a GOST build composes the managed verification provider and the OpenSSL, PKCS#11, and Windows CryptoPro signing routes without registering the base crypto registry twice. An SM build composes cn.sm.soft and the typed cn.sm.remote.http client. The remote provider reads the canonical StellaOps:Crypto:SmRemote section; the legacy StellaOps:Crypto:Profiles:sm-remote section remains accepted, with canonical values winning when both are present.

Production SM deployments must set an absolute HTTP(S) BaseAddress, explicit logical-to-remote key mappings, AllowImplicitKeyMapping=false, SkipProbe=false, and RequireVendorAdapterContract=true. Distribution inclusion proves composition only; a production claim still requires a real SM HSM/SDF/PKCS#11 adapter or GOST token/licensed CSP forcing run.

Crypto Provider Matrix

ProviderInternationalRussiaEUChina
.NET Crypto (RSA, ECDSA, EdDSA)
BouncyCastle (Extended algorithms)
GOST (R 34.10-2012, R 34.11-2012)
eIDAS (QES, AES, AdES)
SM (SM2, SM3, SM4)

Build Instructions

Prerequisites

Build Environment Setup

# Clone repository
git clone https://git.stella-ops.org/stella-ops.org/git.stella-ops.org
cd git.stella-ops.org

# Verify .NET SDK
dotnet --version
# Expected: 10.0.0 or later

Building Regional Distributions

Container Image for Released Deployments

Every release channel must publish a source-free CLI image in addition to any binary/package-manager artifacts. Build the image from devops/docker/Dockerfile.cli; build binary/package-manager artifacts through .gitea/scripts/build/build-cli.sh. Both paths must carry the same manifest-backed CLI plug-in payload and push it with the same version/channel metadata as the service images:

docker build -f devops/docker/Dockerfile.cli \
  --build-arg SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0-noble@sha256:<sdk-digest> \
  --build-arg RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:10.0-noble@sha256:<runtime-digest> \
  --build-arg VERSION=<release-version> \
  --build-arg CHANNEL=<release-channel> \
  --build-arg GIT_SHA=<commit-sha> \
  -t registry.example.com/stellaops/cli:<release-version> .

Operators run the published image directly or through devops/compose/docker-compose.cli.yml:

docker run --rm registry.example.com/stellaops/cli:<release-version> --help
docker run --rm registry.example.com/stellaops/cli:<release-version> runtime --help
docker run --rm registry.example.com/stellaops/cli:<release-version> excititor --help
docker run --rm registry.example.com/stellaops/cli:<release-version> offline kit --help

cd devops/compose
STELLAOPS_CLI_IMAGE=registry.example.com/stellaops/cli:<release-version> \
  ./scripts/stella-cli.sh setup status --json

The image must include /app/plugins/cli with all current restart-time CLI plug-in manifests and assemblies: Aoc, GroundTruth, NonCore, Policy, Symbols, Timestamp, Verdict, and Vex. The plug-in loader skips duplicate root tokens that are already served by core, so release validation is incomplete if it checks only the core command tree and does not exercise plug-in-only groups such as runtime, excititor, and offline kit.

CI guards this contract with .gitea/workflows/cli-plugin-integration.yml, which runs the focused CliPluginPayloadIntegrationTests class and source-free image help smoke checks whenever CLI host, plug-in, manifest, or packaging paths change.

1. International Distribution (Default)

Includes: Default crypto providers only (no regional algorithms)

Build Command:

dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime linux-x64 \
  --self-contained true \
  --output dist/stella-international-linux-x64

Supported Platforms:

Example (all platforms):

# Linux x64
dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime linux-x64 \
  --self-contained true \
  --output dist/stella-international-linux-x64

# Linux ARM64
dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime linux-arm64 \
  --self-contained true \
  --output dist/stella-international-linux-arm64

# macOS Intel
dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime osx-x64 \
  --self-contained true \
  --output dist/stella-international-osx-x64

# macOS Apple Silicon
dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime osx-arm64 \
  --self-contained true \
  --output dist/stella-international-osx-arm64

# Windows x64
dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime win-x64 \
  --self-contained true \
  --output dist/stella-international-win-x64

2. Russia Distribution (GOST)

Includes: Default + GOST crypto providers

Build Command:

dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime linux-x64 \
  --self-contained true \
  -p:StellaOpsEnableGOST=true \
  --output dist/stella-russia-linux-x64

Important: StellaOpsEnableGOST=true conditionally includes the GOST plugin projects and defines the matching preprocessor constant.

Multi-platform Example:

#!/bin/bash
# build-russia.sh - Build all Russia distributions

set -e

RUNTIMES=("linux-x64" "linux-arm64" "osx-x64" "osx-arm64" "win-x64")

for runtime in "${RUNTIMES[@]}"; do
  echo "Building stella-russia for $runtime..."
  dotnet publish src/Cli/StellaOps.Cli \
    --configuration Release \
    --runtime "$runtime" \
    --self-contained true \
    -p:StellaOpsEnableGOST=true \
    --output "dist/stella-russia-$runtime"
done

echo "All Russia distributions built successfully"

3. EU Distribution (eIDAS)

Includes: Default + eIDAS crypto providers

Build Command:

dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime linux-x64 \
  --self-contained true \
  -p:StellaOpsEnableEIDAS=true \
  --output dist/stella-eu-linux-x64

Multi-platform Example:

#!/bin/bash
# build-eu.sh - Build all EU distributions

set -e

RUNTIMES=("linux-x64" "linux-arm64" "osx-x64" "osx-arm64" "win-x64")

for runtime in "${RUNTIMES[@]}"; do
  echo "Building stella-eu for $runtime..."
  dotnet publish src/Cli/StellaOps.Cli \
    --configuration Release \
    --runtime "$runtime" \
    --self-contained true \
    -p:StellaOpsEnableEIDAS=true \
    --output "dist/stella-eu-$runtime"
done

echo "All EU distributions built successfully"

4. China Distribution (SM)

Includes: Default + SM crypto providers

Build Command:

dotnet publish src/Cli/StellaOps.Cli \
  --configuration Release \
  --runtime linux-x64 \
  --self-contained true \
  -p:StellaOpsEnableSM=true \
  --output dist/stella-china-linux-x64

Multi-platform Example:

#!/bin/bash
# build-china.sh - Build all China distributions

set -e

RUNTIMES=("linux-x64" "linux-arm64" "osx-x64" "osx-arm64" "win-x64")

for runtime in "${RUNTIMES[@]}"; do
  echo "Building stella-china for $runtime..."
  dotnet publish src/Cli/StellaOps.Cli \
    --configuration Release \
    --runtime "$runtime" \
    --self-contained true \
    -p:StellaOpsEnableSM=true \
    --output "dist/stella-china-$runtime"
done

echo "All China distributions built successfully"

Build All Distributions

Automated build script:

#!/bin/bash
# build-all.sh - Build all distributions for all platforms

set -e

DISTRIBUTIONS=("international" "russia" "eu" "china")
RUNTIMES=("linux-x64" "linux-arm64" "osx-x64" "osx-arm64" "win-x64")

build_distribution() {
    local dist=$1
    local runtime=$2
    local flags=""

    case $dist in
        "russia")
            flags="-p:StellaOpsEnableGOST=true"
            ;;
        "eu")
            flags="-p:StellaOpsEnableEIDAS=true"
            ;;
        "china")
            flags="-p:StellaOpsEnableSM=true"
            ;;
    esac

    echo "Building stella-$dist for $runtime..."

    dotnet publish src/Cli/StellaOps.Cli \
        --configuration Release \
        --runtime "$runtime" \
        --self-contained true \
        $flags \
        --output "dist/stella-$dist-$runtime"

    # Create tarball (except Windows)
    if [[ ! $runtime =~ ^win ]]; then
        tar -czf "dist/stella-$dist-$runtime.tar.gz" -C "dist/stella-$dist-$runtime" .
        echo "✅ Created dist/stella-$dist-$runtime.tar.gz"
    else
        # Create zip for Windows
        (cd "dist/stella-$dist-$runtime" && zip -r "../stella-$dist-$runtime.zip" .)
        echo "✅ Created dist/stella-$dist-$runtime.zip"
    fi
}

for dist in "${DISTRIBUTIONS[@]}"; do
    for runtime in "${RUNTIMES[@]}"; do
        build_distribution "$dist" "$runtime"
    done
done

echo ""
echo "🎉 All distributions built successfully!"
echo "See dist/ directory for artifacts"

Distribution Validation

Automated Validation Script

#!/bin/bash
# validate-distribution.sh - Validate distribution has correct plugins

set -e

DISTRIBUTION=$1  # international, russia, eu, china
BINARY_PATH=$2

if [ -z "$DISTRIBUTION" ] || [ -z "$BINARY_PATH" ]; then
    echo "Usage: $0 <distribution> <binary-path>"
    echo "Example: $0 russia dist/stella-russia-linux-x64/stella"
    exit 1
fi

echo "Validating $DISTRIBUTION distribution: $BINARY_PATH"
echo ""

# Function to check for symbol in binary
has_symbol() {
    local symbol=$1
    if command -v objdump &> /dev/null; then
        objdump -p "$BINARY_PATH" 2>/dev/null | grep -q "$symbol"
    elif command -v nm &> /dev/null; then
        nm "$BINARY_PATH" 2>/dev/null | grep -q "$symbol"
    else
        # Fallback: check if binary contains string
        strings "$BINARY_PATH" 2>/dev/null | grep -q "$symbol"
    fi
}

# Validation rules
validate_international() {
    echo "Checking International distribution..."

    # Should NOT contain regional plugins
    if has_symbol "GostCryptoProvider" || \
       has_symbol "EidasCryptoProvider" || \
       has_symbol "SmCryptoProvider"; then
        echo "❌ FAIL: International distribution contains restricted plugins"
        return 1
    fi

    echo "✅ PASS: International distribution valid (no restricted plugins)"
    return 0
}

validate_russia() {
    echo "Checking Russia distribution..."

    # Should contain GOST
    if ! has_symbol "GostCryptoProvider"; then
        echo "❌ FAIL: Russia distribution missing GOST plugin"
        return 1
    fi

    # Should NOT contain eIDAS or SM
    if has_symbol "EidasCryptoProvider" || has_symbol "SmCryptoProvider"; then
        echo "❌ FAIL: Russia distribution contains non-GOST regional plugins"
        return 1
    fi

    echo "✅ PASS: Russia distribution valid (GOST included, no other regional plugins)"
    return 0
}

validate_eu() {
    echo "Checking EU distribution..."

    # Should contain eIDAS
    if ! has_symbol "EidasCryptoProvider"; then
        echo "❌ FAIL: EU distribution missing eIDAS plugin"
        return 1
    fi

    # Should NOT contain GOST or SM
    if has_symbol "GostCryptoProvider" || has_symbol "SmCryptoProvider"; then
        echo "❌ FAIL: EU distribution contains non-eIDAS regional plugins"
        return 1
    fi

    echo "✅ PASS: EU distribution valid (eIDAS included, no other regional plugins)"
    return 0
}

validate_china() {
    echo "Checking China distribution..."

    # Should contain SM
    if ! has_symbol "SmCryptoProvider"; then
        echo "❌ FAIL: China distribution missing SM plugin"
        return 1
    fi

    # Should NOT contain GOST or eIDAS
    if has_symbol "GostCryptoProvider" || has_symbol "EidasCryptoProvider"; then
        echo "❌ FAIL: China distribution contains non-SM regional plugins"
        return 1
    fi

    echo "✅ PASS: China distribution valid (SM included, no other regional plugins)"
    return 0
}

# Run validation
case $DISTRIBUTION in
    "international")
        validate_international
        ;;
    "russia")
        validate_russia
        ;;
    "eu")
        validate_eu
        ;;
    "china")
        validate_china
        ;;
    *)
        echo "❌ ERROR: Unknown distribution '$DISTRIBUTION'"
        echo "Valid distributions: international, russia, eu, china"
        exit 1
        ;;
esac

exit $?

Usage:

# Validate Russia distribution
./validate-distribution.sh russia dist/stella-russia-linux-x64/stella

# Output:
# Validating russia distribution: dist/stella-russia-linux-x64/stella
#
# Checking Russia distribution...
# ✅ PASS: Russia distribution valid (GOST included, no other regional plugins)

Runtime Validation

Verify correct plugins are available at runtime:

# International distribution
./stella crypto providers
# Expected output:
# Available Crypto Providers:
# - default (.NET Crypto, BouncyCastle)

# Russia distribution
./stella crypto providers
# Expected output:
# Available Crypto Providers:
# - default (.NET Crypto, BouncyCastle)
# - gost (GOST R 34.10-2012, GOST R 34.11-2012)

# EU distribution
./stella crypto providers
# Expected output:
# Available Crypto Providers:
# - default (.NET Crypto, BouncyCastle)
# - eidas (QES, AES, AdES)

# China distribution
./stella crypto providers
# Expected output:
# Available Crypto Providers:
# - default (.NET Crypto, BouncyCastle)
# - sm (SM2, SM3, SM4)

Packaging

Tarball Creation

#!/bin/bash
# package.sh - Create distribution tarballs

DIST=$1  # stella-russia-linux-x64
OUTPUT_DIR="dist"

cd "$OUTPUT_DIR/$DIST"

# Create tarball
tar -czf "../$DIST.tar.gz" .

echo "✅ Created $OUTPUT_DIR/$DIST.tar.gz"

Checksums

#!/bin/bash
# checksums.sh - Generate checksums for all distributions

cd dist

for tarball in *.tar.gz *.zip; do
    if [ -f "$tarball" ]; then
        sha256sum "$tarball" >> checksums.txt
    fi
done

echo "✅ Checksums written to dist/checksums.txt"
cat dist/checksums.txt

CI/CD Integration

GitHub Actions / Gitea Actions

name: Build and Release CLI

on:
  push:
    tags:
      - 'v*'

jobs:
  build-matrix:
    strategy:
      matrix:
        distribution: [international, russia, eu, china]
        runtime: [linux-x64, linux-arm64, osx-x64, osx-arm64, win-x64]

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Build Distribution
        run: |
          FLAGS=""
          case "${{ matrix.distribution }}" in
            "russia")
              FLAGS="-p:StellaOpsEnableGOST=true"
              ;;
            "eu")
              FLAGS="-p:StellaOpsEnableEIDAS=true"
              ;;
            "china")
              FLAGS="-p:StellaOpsEnableSM=true"
              ;;
          esac

          dotnet publish src/Cli/StellaOps.Cli \
            --configuration Release \
            --runtime ${{ matrix.runtime }} \
            --self-contained true \
            $FLAGS \
            --output dist/stella-${{ matrix.distribution }}-${{ matrix.runtime }}

      - name: Validate Distribution
        run: |
          chmod +x scripts/validate-distribution.sh
          ./scripts/validate-distribution.sh \
            ${{ matrix.distribution }} \
            dist/stella-${{ matrix.distribution }}-${{ matrix.runtime }}/stella

      - name: Create Tarball
        if: ${{ !contains(matrix.runtime, 'win') }}
        run: |
          cd dist/stella-${{ matrix.distribution }}-${{ matrix.runtime }}
          tar -czf ../stella-${{ matrix.distribution }}-${{ matrix.runtime }}.tar.gz .

      - name: Upload Artifact
        uses: actions/upload-artifact@v4
        with:
          name: stella-${{ matrix.distribution }}-${{ matrix.runtime }}
          path: dist/stella-${{ matrix.distribution }}-${{ matrix.runtime }}.tar.gz

Distribution Deployment

Release Structure

releases/
├── v2.1.0/
│   ├── stella-international-linux-x64.tar.gz
│   ├── stella-international-linux-arm64.tar.gz
│   ├── stella-international-osx-x64.tar.gz
│   ├── stella-international-osx-arm64.tar.gz
│   ├── stella-international-win-x64.zip
│   ├── stella-russia-linux-x64.tar.gz
│   ├── stella-russia-linux-arm64.tar.gz
│   ├── stella-russia-osx-x64.tar.gz
│   ├── stella-russia-osx-arm64.tar.gz
│   ├── stella-russia-win-x64.zip
│   ├── stella-eu-linux-x64.tar.gz
│   ├── stella-eu-linux-arm64.tar.gz
│   ├── stella-eu-osx-x64.tar.gz
│   ├── stella-eu-osx-arm64.tar.gz
│   ├── stella-eu-win-x64.zip
│   ├── stella-china-linux-x64.tar.gz
│   ├── stella-china-linux-arm64.tar.gz
│   ├── stella-china-osx-x64.tar.gz
│   ├── stella-china-osx-arm64.tar.gz
│   ├── stella-china-win-x64.zip
│   ├── checksums.txt
│   └── RELEASE_NOTES.md
└── latest -> v2.1.0

Public Release Server:

https://releases.stella-ops.org/cli/
├── latest/
│   ├── stella-international-linux-x64.tar.gz
│   ├── stella-russia-linux-x64.tar.gz
│   ├── stella-eu-linux-x64.tar.gz
│   └── stella-china-linux-x64.tar.gz
├── v2.1.0/
├── v2.0.0/
└── checksums.txt

User Installation:

# International (unrestricted)
wget https://releases.stella-ops.org/cli/latest/stella-international-linux-x64.tar.gz

# Russia (GOST)
wget https://releases.stella-ops.org/cli/russia/latest/stella-russia-linux-x64.tar.gz

# EU (eIDAS)
wget https://releases.stella-ops.org/cli/eu/latest/stella-eu-linux-x64.tar.gz

# China (SM)
wget https://releases.stella-ops.org/cli/china/latest/stella-china-linux-x64.tar.gz

Export Control Statement

StellaOps CLI regional distributions contain cryptographic software subject to export control laws.

  • stella-international: No export restrictions (standard commercial crypto)
  • stella-russia: Authorized for Russia and CIS states only
  • stella-eu: Authorized for EU/EEA member states only
  • stella-china: Authorized for China only

Unauthorized export, re-export, or transfer may violate applicable laws. Users are responsible for compliance with export control regulations in their jurisdiction.

License Compliance

All distributions are licensed under BUSL-1.1, with regional plugins subject to additional vendor licenses (e.g., CryptoPro CSP requires commercial license).


See Also