Merge branch 'main' of https://git.stella-ops.org/stella-ops.org/git.stella-ops.org
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
master
2025-12-09 13:08:17 +02:00
10050 changed files with 313174 additions and 7518670 deletions

View File

@@ -1,8 +1,31 @@
{
"permissions": {
"allow": [
"Bash(dotnet --list-sdks:*)",
"Bash(winget install:*)",
"Bash(dotnet restore:*)",
"Bash(dotnet nuget:*)",
"Bash(csc -parse:*)",
"Bash(grep:*)",
"Bash(dotnet build:*)",
"Bash(cat:*)",
"Bash(copy:*)",
"Bash(dotnet test:*)",
"Bash(dir:*)",
"Bash(Select-Object -ExpandProperty FullName)",
"Bash(echo:*)",
"Bash(Out-File -FilePath \"E:\\dev\\git.stella-ops.org\\src\\Scanner\\__Libraries\\StellaOps.Scanner.Surface\\StellaOps.Scanner.Surface.csproj\" -Encoding utf8)",
"Bash(wc:*)",
"Bash(sort:*)"
"Bash(find:*)",
"WebFetch(domain:docs.gradle.org)",
"WebSearch",
"Bash(dotnet msbuild:*)",
"Bash(test:*)",
"Bash(taskkill:*)",
"Bash(timeout /t)",
"Bash(dotnet clean:*)",
"Bash(if not exist \"E:\\dev\\git.stella-ops.org\\src\\Scanner\\__Tests\\StellaOps.Scanner.Analyzers.Lang.Java.Tests\\Internal\" mkdir \"E:\\dev\\git.stella-ops.org\\src\\Scanner\\__Tests\\StellaOps.Scanner.Analyzers.Lang.Java.Tests\\Internal\")",
"Bash(if not exist \"E:\\dev\\git.stella-ops.org\\src\\Scanner\\__Tests\\StellaOps.Scanner.Analyzers.Lang.Node.Tests\\Internal\" mkdir \"E:\\dev\\git.stella-ops.org\\src\\Scanner\\__Tests\\StellaOps.Scanner.Analyzers.Lang.Node.Tests\\Internal\")"
],
"deny": [],
"ask": []

23
.dockerignore Normal file
View File

@@ -0,0 +1,23 @@
.git
.gitignore
.gitea
.venv
bin
obj
**/bin
**/obj
local-nugets
.nuget
**/node_modules
**/dist
**/coverage
**/*.user
**/*.suo
**/*.cache
**/.vscode
**/.idea
**/.DS_Store
**/TestResults
**/out
**/packages
/tmp

View File

@@ -20,6 +20,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install dnslib
run: pip install dnslib
- name: Run sealed-mode smoke

View File

@@ -24,7 +24,7 @@ jobs:
aoc-guard:
runs-on: ubuntu-22.04
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
steps:
- name: Checkout
@@ -32,6 +32,9 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh
@@ -69,7 +72,7 @@ jobs:
runs-on: ubuntu-22.04
if: github.event_name != 'schedule'
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
AOC_VERIFY_SINCE: ${{ github.event.pull_request.base.sha || 'HEAD~1' }}
steps:
@@ -78,6 +81,9 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh

View File

@@ -17,6 +17,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node.js
uses: actions/setup-node@v4
with:

View File

@@ -0,0 +1,128 @@
name: Artifact Signing
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
artifact_path:
description: 'Path to artifact to sign'
required: false
default: ''
env:
COSIGN_VERSION: 'v2.2.0'
jobs:
sign-containers:
name: Sign Container Images
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: read
id-token: write
packages: write
steps:
- uses: actions/checkout@v4
- name: Install cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: ${{ env.COSIGN_VERSION }}
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Sign images (keyless)
if: ${{ !env.COSIGN_PRIVATE_KEY_B64 }}
env:
COSIGN_EXPERIMENTAL: "1"
run: |
IMAGES=(
"ghcr.io/${{ github.repository }}/concelier"
"ghcr.io/${{ github.repository }}/scanner"
"ghcr.io/${{ github.repository }}/authority"
)
for img in "${IMAGES[@]}"; do
if docker manifest inspect "${img}:${{ github.ref_name }}" > /dev/null 2>&1; then
echo "Signing ${img}:${{ github.ref_name }}..."
cosign sign --yes "${img}:${{ github.ref_name }}"
fi
done
- name: Sign images (with key)
if: ${{ env.COSIGN_PRIVATE_KEY_B64 }}
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY_B64 }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
echo "$COSIGN_PRIVATE_KEY" | base64 -d > /tmp/cosign.key
IMAGES=(
"ghcr.io/${{ github.repository }}/concelier"
"ghcr.io/${{ github.repository }}/scanner"
"ghcr.io/${{ github.repository }}/authority"
)
for img in "${IMAGES[@]}"; do
if docker manifest inspect "${img}:${{ github.ref_name }}" > /dev/null 2>&1; then
echo "Signing ${img}:${{ github.ref_name }}..."
cosign sign --key /tmp/cosign.key "${img}:${{ github.ref_name }}"
fi
done
rm -f /tmp/cosign.key
sign-sbom:
name: Sign SBOM Artifacts
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Install cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: ${{ env.COSIGN_VERSION }}
- name: Generate and sign SBOM
run: |
# Generate SBOM using syft
if command -v syft &> /dev/null; then
syft . -o cyclonedx-json > sbom.cdx.json
cosign sign-blob --yes sbom.cdx.json --output-signature sbom.cdx.json.sig
else
echo "syft not installed, skipping SBOM generation"
fi
- name: Upload signed artifacts
uses: actions/upload-artifact@v4
with:
name: signed-sbom
path: |
sbom.cdx.json
sbom.cdx.json.sig
if-no-files-found: ignore
verify-signatures:
name: Verify Existing Signatures
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: ${{ env.COSIGN_VERSION }}
- name: Verify DSSE envelopes
run: |
find . -name "*.dsse" -o -name "*.dsse.json" | while read f; do
echo "Checking $f..."
# Basic JSON validation
if ! jq empty "$f" 2>/dev/null; then
echo "Warning: Invalid JSON in $f"
fi
done

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Build bundle
run: |
chmod +x scripts/attest/build-attestation-bundle.sh

View File

@@ -58,6 +58,9 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Resolve Authority configuration
id: config
run: |

View File

@@ -8,6 +8,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Python
uses: actions/setup-python@v5

View File

@@ -37,7 +37,7 @@ on:
type: boolean
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
BUILD_CONFIGURATION: Release
CI_CACHE_ROOT: /data/.cache/stella-ops/feedser
RUNNER_TOOL_CACHE: /toolcache
@@ -111,6 +111,10 @@ jobs:
- name: Validate telemetry storage configuration
run: python3 ops/devops/telemetry/validate_storage_stack.py
- name: Task Pack offline bundle fixtures
run: |
python3 scripts/packs/run-fixtures-check.sh
- name: Telemetry tenant isolation smoke
env:
COMPOSE_DIR: ${GITHUB_WORKSPACE}/deploy/compose
@@ -203,6 +207,14 @@ jobs:
--results-directory "$TEST_RESULTS_DIR"
done
- name: Run TimelineIndexer tests (EB1 evidence linkage gate)
run: |
mkdir -p "$TEST_RESULTS_DIR"
dotnet test src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.sln \
--configuration $BUILD_CONFIGURATION \
--logger "trx;LogFileName=timelineindexer-tests.trx" \
--results-directory "$TEST_RESULTS_DIR"
- name: Lint policy DSL samples
run: dotnet run --project tools/PolicyDslValidator/PolicyDslValidator.csproj -- --strict docs/examples/policies/*.yaml

View File

@@ -22,10 +22,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.100-rc.2.25502.107"
dotnet-version: "10.0.100"
- name: Install syft (SBOM)
uses: anchore/sbom-action/download-syft@v0

View File

@@ -18,10 +18,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.100-rc.2.25502.107"
dotnet-version: "10.0.100"
- name: Chaos smoke
if: ${{ github.event.inputs.chaos == 'true' }}

View File

@@ -17,10 +17,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 preview
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.100-rc.2.25502.107'
dotnet-version: '10.0.100'
- name: Restore Concelier solution
run: dotnet restore src/Concelier/StellaOps.Concelier.sln

View File

@@ -0,0 +1,32 @@
name: Concelier STORE-AOC-19-005 Dataset
on:
workflow_dispatch: {}
jobs:
build-dataset:
runs-on: ubuntu-22.04
env:
ARTIFACT_DIR: ${{ github.workspace }}/out/linksets
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y zstd
- name: Build dataset tarball
run: |
chmod +x scripts/concelier/build-store-aoc-19-005-dataset.sh scripts/concelier/test-store-aoc-19-005-dataset.sh
scripts/concelier/build-store-aoc-19-005-dataset.sh "${ARTIFACT_DIR}/linksets-stage-backfill.tar.zst"
- name: Validate dataset
run: scripts/concelier/test-store-aoc-19-005-dataset.sh "${ARTIFACT_DIR}/linksets-stage-backfill.tar.zst"
- name: Upload dataset artifacts
uses: actions/upload-artifact@v4
with:
name: concelier-store-aoc-19-005-dataset
path: |
${ARTIFACT_DIR}/linksets-stage-backfill.tar.zst
${ARTIFACT_DIR}/linksets-stage-backfill.tar.zst.sha256

View File

@@ -1,83 +1,58 @@
name: Console CI
name: console-ci
on:
push:
branches: [ main ]
paths:
- 'src/UI/**'
- '.gitea/workflows/console-ci.yml'
- 'docs/modules/devops/console-ci-contract.md'
workflow_dispatch:
pull_request:
branches: [ main, develop ]
paths:
- 'src/UI/**'
- 'src/Web/**'
- '.gitea/workflows/console-ci.yml'
- 'docs/modules/devops/console-ci-contract.md'
- 'ops/devops/console/**'
jobs:
console-ci:
runs-on: ubuntu-22.04
lint-test-build:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: src/Web
env:
PNPM_HOME: ~/.pnpm
PLAYWRIGHT_BROWSERS_PATH: ./.playwright
SOURCE_DATE_EPOCH: ${{ github.run_id }}
PLAYWRIGHT_BROWSERS_PATH: ~/.cache/ms-playwright
CI: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js 20
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
cache-dependency-path: src/Web/package-lock.json
- name: Enable pnpm
- name: Install deps (offline-friendly)
run: npm ci --prefer-offline --no-audit --progress=false
- name: Lint
run: npm run lint -- --no-progress
- name: Console export specs (targeted)
run: bash ./scripts/ci-console-exports.sh
- name: Build
run: npm run build -- --configuration=production --progress=false
- name: Collect artifacts
if: always()
run: |
corepack enable
corepack prepare pnpm@9 --activate
- name: Cache pnpm store & node_modules
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
node_modules
./.pnpm-store
./.playwright
key: console-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (offline-first)
env:
PNPM_FETCH_RETRIES: 0
PNPM_OFFLINE: 1
run: |
pnpm install --frozen-lockfile || PNPM_OFFLINE=0 pnpm install --frozen-lockfile --prefer-offline
- name: Lint / Types
run: pnpm lint && pnpm format:check && pnpm typecheck
- name: Unit tests
run: pnpm test -- --runInBand --reporter=junit --outputFile=.artifacts/junit.xml
- name: Storybook a11y
run: |
pnpm storybook:build
pnpm storybook:a11y --ci --output .artifacts/storybook-a11y.json
- name: Playwright smoke
run: pnpm playwright test --config=playwright.config.ci.ts --reporter=list,junit=.artifacts/playwright.xml
- name: Lighthouse (CI budgets)
run: |
pnpm serve --port 4173 &
pnpm lhci autorun --config=lighthouserc.ci.js --upload.target=filesystem --upload.outputDir=.artifacts/lhci
- name: SBOM
run: pnpm exec syft packages dir:dist --output=spdx-json=.artifacts/console.spdx.json
mkdir -p ../artifacts
cp -r dist ../artifacts/dist || true
cp -r coverage ../artifacts/coverage || true
find . -maxdepth 3 -type f -name "*.xml" -o -name "*.trx" -o -name "*.json" -path "*test*" -print0 | xargs -0 -I{} cp --parents {} ../artifacts 2>/dev/null || true
- name: Upload artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: console-ci-artifacts
path: .artifacts
name: console-ci-${{ github.run_id }}
path: artifacts
retention-days: 14

View File

@@ -0,0 +1,32 @@
name: console-runner-image
on:
workflow_dispatch:
push:
paths:
- 'ops/devops/console/**'
- '.gitea/workflows/console-runner-image.yml'
jobs:
build-runner-image:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build runner image tarball (baked caches)
env:
RUN_ID: ${{ github.run_id }}
run: |
set -euo pipefail
chmod +x ops/devops/console/build-runner-image.sh ops/devops/console/build-runner-image-ci.sh
ops/devops/console/build-runner-image-ci.sh
- name: Upload runner image artifact
uses: actions/upload-artifact@v4
with:
name: console-runner-image-${{ github.run_id }}
path: ops/devops/artifacts/console-runner/
retention-days: 14

View File

@@ -25,6 +25,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

View File

@@ -0,0 +1,55 @@
name: cryptopro-linux-csp
on:
push:
branches: [main, develop]
paths:
- 'ops/cryptopro/linux-csp-service/**'
- 'opt/cryptopro/downloads/**'
- '.gitea/workflows/cryptopro-linux-csp.yml'
pull_request:
paths:
- 'ops/cryptopro/linux-csp-service/**'
- 'opt/cryptopro/downloads/**'
- '.gitea/workflows/cryptopro-linux-csp.yml'
env:
IMAGE_NAME: cryptopro-linux-csp
DOCKERFILE: ops/cryptopro/linux-csp-service/Dockerfile
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build image (accept EULA explicitly)
run: |
docker build -t $IMAGE_NAME \
--build-arg CRYPTOPRO_ACCEPT_EULA=1 \
-f $DOCKERFILE .
- name: Run container
run: |
docker run -d --rm --name $IMAGE_NAME -p 18080:8080 $IMAGE_NAME
for i in {1..20}; do
if curl -sf http://127.0.0.1:18080/health >/dev/null; then
exit 0
fi
sleep 3
done
echo "Service failed to start" && exit 1
- name: Test endpoints
run: |
curl -sf http://127.0.0.1:18080/health
curl -sf http://127.0.0.1:18080/license || true
curl -sf -X POST http://127.0.0.1:18080/hash \
-H "Content-Type: application/json" \
-d '{"data_b64":"SGVsbG8="}'
- name: Stop container
if: always()
run: docker rm -f $IMAGE_NAME || true

View File

@@ -19,10 +19,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 (preview)
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100-rc.2.25502.107
dotnet-version: 10.0.100
- name: Build CryptoPro plugin
run: |

View File

@@ -11,6 +11,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node (corepack/pnpm)
uses: actions/setup-node@v4
with:

View File

@@ -29,6 +29,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh
@@ -44,7 +47,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.100-rc.2.25502.107'
dotnet-version: '10.0.100'
- name: Link check
run: |

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Emit retention summary
env:
RETENTION_TARGET: ${{ github.event.inputs.retention_target }}
@@ -31,14 +34,35 @@ jobs:
needs: check-evidence-locker
env:
STAGED_DIR: evidence-locker/zastava/2025-12-02
MODULE_ROOT: docs/modules/zastava
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Package staged Zastava artefacts
run: |
test -d "$STAGED_DIR" || { echo "missing $STAGED_DIR" >&2; exit 1; }
tar -cf /tmp/zastava-evidence.tar -C "$STAGED_DIR" .
test -d "$MODULE_ROOT" || { echo "missing $MODULE_ROOT" >&2; exit 1; }
tmpdir=$(mktemp -d)
rsync -a --relative \
"$MODULE_ROOT/SHA256SUMS" \
"$MODULE_ROOT/schemas/" \
"$MODULE_ROOT/exports/" \
"$MODULE_ROOT/thresholds.yaml" \
"$MODULE_ROOT/thresholds.yaml.dsse" \
"$MODULE_ROOT/kit/verify.sh" \
"$MODULE_ROOT/kit/README.md" \
"$MODULE_ROOT/kit/ed25519.pub" \
"$MODULE_ROOT/kit/zastava-kit.tzst" \
"$MODULE_ROOT/kit/zastava-kit.tzst.dsse" \
"$MODULE_ROOT/evidence/README.md" \
"$tmpdir/"
(cd "$tmpdir/docs/modules/zastava" && sha256sum --check SHA256SUMS)
tar --sort=name --mtime="UTC 1970-01-01" --owner=0 --group=0 --numeric-owner \
-cf /tmp/zastava-evidence.tar -C "$tmpdir/docs/modules/zastava" .
sha256sum /tmp/zastava-evidence.tar
- name: Upload staged artefacts (fallback)
uses: actions/upload-artifact@v4

View File

@@ -20,7 +20,7 @@ jobs:
export-ci:
runs-on: ubuntu-22.04
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
MINIO_ACCESS_KEY: exportci
MINIO_SECRET_KEY: exportci123
BUCKET: export-ci
@@ -28,6 +28,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with:
fetch-depth: 0

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Trivy
uses: aquasecurity/trivy-action@v0.24.0
with:

View File

@@ -0,0 +1,325 @@
# .gitea/workflows/findings-ledger-ci.yml
# Findings Ledger CI with RLS migration validation (DEVOPS-LEDGER-TEN-48-001-REL)
name: Findings Ledger CI
on:
push:
branches: [main]
paths:
- 'src/Findings/**'
- '.gitea/workflows/findings-ledger-ci.yml'
- 'deploy/releases/2025.09-stable.yaml'
- 'deploy/releases/2025.09-airgap.yaml'
- 'deploy/downloads/manifest.json'
- 'ops/devops/release/check_release_manifest.py'
pull_request:
branches: [main, develop]
paths:
- 'src/Findings/**'
- '.gitea/workflows/findings-ledger-ci.yml'
env:
DOTNET_VERSION: '10.0.100'
POSTGRES_IMAGE: postgres:16-alpine
BUILD_CONFIGURATION: Release
jobs:
build-test:
runs-on: ubuntu-22.04
env:
TEST_RESULTS_DIR: ${{ github.workspace }}/artifacts/test-results
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
include-prerelease: true
- name: Restore dependencies
run: |
dotnet restore src/Findings/StellaOps.Findings.Ledger/StellaOps.Findings.Ledger.csproj
dotnet restore src/Findings/__Tests/StellaOps.Findings.Ledger.Tests/StellaOps.Findings.Ledger.Tests.csproj
- name: Build
run: |
dotnet build src/Findings/StellaOps.Findings.Ledger/StellaOps.Findings.Ledger.csproj \
-c ${{ env.BUILD_CONFIGURATION }} \
/p:ContinuousIntegrationBuild=true
- name: Run unit tests
run: |
mkdir -p $TEST_RESULTS_DIR
dotnet test src/Findings/__Tests/StellaOps.Findings.Ledger.Tests/StellaOps.Findings.Ledger.Tests.csproj \
-c ${{ env.BUILD_CONFIGURATION }} \
--logger "trx;LogFileName=ledger-tests.trx" \
--results-directory $TEST_RESULTS_DIR
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: ledger-test-results
path: ${{ env.TEST_RESULTS_DIR }}
migration-validation:
runs-on: ubuntu-22.04
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: ledgertest
POSTGRES_PASSWORD: ledgertest
POSTGRES_DB: ledger_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: ledgertest
PGPASSWORD: ledgertest
PGDATABASE: ledger_test
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
include-prerelease: true
- name: Install PostgreSQL client
run: |
sudo apt-get update
sudo apt-get install -y postgresql-client
- name: Wait for PostgreSQL
run: |
until pg_isready -h $PGHOST -p $PGPORT -U $PGUSER; do
echo "Waiting for PostgreSQL..."
sleep 2
done
- name: Apply prerequisite migrations (001-006)
run: |
set -euo pipefail
MIGRATION_DIR="src/Findings/StellaOps.Findings.Ledger/migrations"
for migration in 001_initial.sql 002_add_evidence_bundle_ref.sql 002_projection_offsets.sql \
003_policy_rationale.sql 004_ledger_attestations.sql 004_risk_fields.sql \
005_risk_fields.sql 006_orchestrator_airgap.sql; do
if [ -f "$MIGRATION_DIR/$migration" ]; then
echo "Applying migration: $migration"
psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -f "$MIGRATION_DIR/$migration"
fi
done
- name: Apply RLS migration (007_enable_rls.sql)
run: |
set -euo pipefail
echo "Applying RLS migration..."
psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE \
-f src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls.sql
- name: Validate RLS configuration
run: |
set -euo pipefail
echo "Validating RLS is enabled on all protected tables..."
# Check RLS enabled
TABLES_WITH_RLS=$(psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -t -A -c "
SELECT COUNT(*)
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname = 'public'
AND c.relrowsecurity = true
AND c.relname IN (
'ledger_events', 'ledger_merkle_roots', 'findings_projection',
'finding_history', 'triage_actions', 'ledger_attestations',
'orchestrator_exports', 'airgap_imports'
);
")
if [ "$TABLES_WITH_RLS" -ne 8 ]; then
echo "::error::Expected 8 tables with RLS enabled, found $TABLES_WITH_RLS"
exit 1
fi
echo "✓ All 8 tables have RLS enabled"
# Check policies exist
POLICIES=$(psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -t -A -c "
SELECT COUNT(DISTINCT tablename)
FROM pg_policies
WHERE schemaname = 'public'
AND policyname LIKE '%_tenant_isolation';
")
if [ "$POLICIES" -ne 8 ]; then
echo "::error::Expected 8 tenant isolation policies, found $POLICIES"
exit 1
fi
echo "✓ All 8 tenant isolation policies created"
# Check tenant function exists
FUNC_EXISTS=$(psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -t -A -c "
SELECT COUNT(*)
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE p.proname = 'require_current_tenant'
AND n.nspname = 'findings_ledger_app';
")
if [ "$FUNC_EXISTS" -ne 1 ]; then
echo "::error::Tenant function 'require_current_tenant' not found"
exit 1
fi
echo "✓ Tenant function 'findings_ledger_app.require_current_tenant()' exists"
echo ""
echo "=== RLS Migration Validation PASSED ==="
- name: Test rollback migration
run: |
set -euo pipefail
echo "Testing rollback migration..."
psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE \
-f src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls_rollback.sql
# Verify RLS is disabled
TABLES_WITH_RLS=$(psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -t -A -c "
SELECT COUNT(*)
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname = 'public'
AND c.relrowsecurity = true
AND c.relname IN (
'ledger_events', 'ledger_merkle_roots', 'findings_projection',
'finding_history', 'triage_actions', 'ledger_attestations',
'orchestrator_exports', 'airgap_imports'
);
")
if [ "$TABLES_WITH_RLS" -ne 0 ]; then
echo "::error::Rollback failed - $TABLES_WITH_RLS tables still have RLS enabled"
exit 1
fi
echo "✓ Rollback successful - RLS disabled on all tables"
- name: Validate release manifests (production)
run: |
set -euo pipefail
python ops/devops/release/check_release_manifest.py
- name: Re-apply RLS migration (idempotency check)
run: |
set -euo pipefail
echo "Re-applying RLS migration to verify idempotency..."
psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE \
-f src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls.sql
echo "✓ Migration is idempotent"
generate-manifest:
runs-on: ubuntu-22.04
needs: [build-test, migration-validation]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Generate migration manifest
run: |
set -euo pipefail
MIGRATION_FILE="src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls.sql"
ROLLBACK_FILE="src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls_rollback.sql"
MANIFEST_DIR="out/findings-ledger/migrations"
mkdir -p "$MANIFEST_DIR"
# Compute SHA256 hashes
MIGRATION_SHA=$(sha256sum "$MIGRATION_FILE" | awk '{print $1}')
ROLLBACK_SHA=$(sha256sum "$ROLLBACK_FILE" | awk '{print $1}')
CREATED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
cat > "$MANIFEST_DIR/007_enable_rls.manifest.json" <<EOF
{
"\$schema": "https://stella-ops.org/schemas/migration-manifest.v1.json",
"schemaVersion": "1.0.0",
"migrationId": "007_enable_rls",
"module": "findings-ledger",
"version": "2025.12.0",
"createdAt": "$CREATED_AT",
"description": "Enable Row-Level Security for Findings Ledger tenant isolation",
"taskId": "LEDGER-TEN-48-001-DEV",
"contractRef": "CONTRACT-FINDINGS-LEDGER-RLS-011",
"database": {
"engine": "postgresql",
"minVersion": "16.0"
},
"files": {
"apply": {
"path": "007_enable_rls.sql",
"sha256": "$MIGRATION_SHA"
},
"rollback": {
"path": "007_enable_rls_rollback.sql",
"sha256": "$ROLLBACK_SHA"
}
},
"affects": {
"tables": [
"ledger_events",
"ledger_merkle_roots",
"findings_projection",
"finding_history",
"triage_actions",
"ledger_attestations",
"orchestrator_exports",
"airgap_imports"
],
"schemas": ["public", "findings_ledger_app"],
"roles": ["findings_ledger_admin"]
},
"prerequisites": [
"006_orchestrator_airgap"
],
"validation": {
"type": "rls-check",
"expectedTables": 8,
"expectedPolicies": 8,
"tenantFunction": "findings_ledger_app.require_current_tenant"
},
"offlineKit": {
"includedInBundle": true,
"requiresManualApply": true,
"applyOrder": 7
}
}
EOF
echo "Generated migration manifest at $MANIFEST_DIR/007_enable_rls.manifest.json"
cat "$MANIFEST_DIR/007_enable_rls.manifest.json"
- name: Copy migration files for offline-kit
run: |
set -euo pipefail
OFFLINE_DIR="out/findings-ledger/offline-kit/migrations"
mkdir -p "$OFFLINE_DIR"
cp src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls.sql "$OFFLINE_DIR/"
cp src/Findings/StellaOps.Findings.Ledger/migrations/007_enable_rls_rollback.sql "$OFFLINE_DIR/"
cp out/findings-ledger/migrations/007_enable_rls.manifest.json "$OFFLINE_DIR/"
echo "Offline-kit migration files prepared"
ls -la "$OFFLINE_DIR"
- name: Upload migration artefacts
uses: actions/upload-artifact@v4
with:
name: findings-ledger-migrations
path: out/findings-ledger/
if-no-files-found: error

View File

@@ -22,6 +22,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install k6
run: |
sudo apt-get update -qq

View File

@@ -22,6 +22,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node
uses: actions/setup-node@v4
with:

View File

@@ -0,0 +1,68 @@
name: ICS/KISA Feed Refresh
on:
schedule:
- cron: '0 2 * * MON'
workflow_dispatch:
inputs:
live_fetch:
description: 'Attempt live RSS fetch (fallback to samples on failure)'
required: false
default: true
type: boolean
offline_snapshot:
description: 'Force offline samples only (no network)'
required: false
default: false
type: boolean
jobs:
refresh:
runs-on: ubuntu-22.04
permissions:
contents: read
env:
ICSCISA_FEED_URL: ${{ secrets.ICSCISA_FEED_URL }}
KISA_FEED_URL: ${{ secrets.KISA_FEED_URL }}
FEED_GATEWAY_HOST: concelier-webservice
FEED_GATEWAY_SCHEME: http
LIVE_FETCH: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.live_fetch || 'true' }}
OFFLINE_SNAPSHOT: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.offline_snapshot || 'false' }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set run metadata
id: meta
run: |
RUN_DATE=$(date -u +%Y%m%d)
RUN_ID="icscisa-kisa-$(date -u +%Y%m%dT%H%M%SZ)"
echo "run_date=$RUN_DATE" >> $GITHUB_OUTPUT
echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
echo "RUN_DATE=$RUN_DATE" >> $GITHUB_ENV
echo "RUN_ID=$RUN_ID" >> $GITHUB_ENV
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Run ICS/KISA refresh
run: |
python scripts/feeds/run_icscisa_kisa_refresh.py \
--out-dir out/feeds/icscisa-kisa \
--run-date "${{ steps.meta.outputs.run_date }}" \
--run-id "${{ steps.meta.outputs.run_id }}"
- name: Show fetch log
run: cat out/feeds/icscisa-kisa/${{ steps.meta.outputs.run_date }}/fetch.log
- name: Upload refresh artifacts
uses: actions/upload-artifact@v4
with:
name: icscisa-kisa-${{ steps.meta.outputs.run_date }}
path: out/feeds/icscisa-kisa/${{ steps.meta.outputs.run_date }}
if-no-files-found: error
retention-days: 21

View File

@@ -21,11 +21,14 @@ jobs:
lnm-backfill:
runs-on: ubuntu-22.04
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with:
fetch-depth: 0

View File

@@ -25,11 +25,14 @@ jobs:
vex-backfill:
runs-on: ubuntu-22.04
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with:
fetch-depth: 0

View File

@@ -0,0 +1,125 @@
name: Manifest Integrity
on:
push:
branches: [main]
paths:
- 'docs/**/*.schema.json'
- 'docs/contracts/**'
- 'docs/schemas/**'
- 'scripts/packs/**'
pull_request:
paths:
- 'docs/**/*.schema.json'
- 'docs/contracts/**'
- 'docs/schemas/**'
- 'scripts/packs/**'
jobs:
validate-schemas:
name: Validate Schema Integrity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm install -g ajv-cli ajv-formats
- name: Validate JSON schemas
run: |
EXIT_CODE=0
for schema in docs/schemas/*.schema.json; do
echo "Validating $schema..."
if ! ajv compile -s "$schema" --spec=draft2020 2>/dev/null; then
echo "Error: $schema is invalid"
EXIT_CODE=1
fi
done
exit $EXIT_CODE
validate-contracts:
name: Validate Contract Documents
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check contract structure
run: |
for contract in docs/contracts/*.md; do
echo "Checking $contract..."
# Verify required sections exist
if ! grep -q "^## " "$contract"; then
echo "Warning: $contract missing section headers"
fi
# Check for decision ID
if grep -q "Decision ID" "$contract" && ! grep -q "DECISION-\|CONTRACT-" "$contract"; then
echo "Warning: $contract missing decision ID format"
fi
done
validate-pack-fixtures:
name: Validate Pack Fixtures
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install jsonschema
- name: Run fixture validation
run: |
if [ -f scripts/packs/run-fixtures-check.sh ]; then
chmod +x scripts/packs/run-fixtures-check.sh
./scripts/packs/run-fixtures-check.sh
fi
checksum-audit:
name: Audit SHA256SUMS Files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate checksums
run: |
find . -name "SHA256SUMS" -type f | while read f; do
dir=$(dirname "$f")
echo "Validating checksums in $dir..."
cd "$dir"
# Check if all referenced files exist
while read hash file; do
if [ ! -f "$file" ]; then
echo "Warning: $file referenced in SHA256SUMS but not found"
fi
done < SHA256SUMS
cd - > /dev/null
done
merkle-consistency:
name: Verify Merkle Roots
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check DSSE Merkle roots
run: |
find . -name "*.dsse.json" -type f | while read f; do
echo "Checking Merkle root in $f..."
# Extract and validate Merkle root if present
if jq -e '.payload' "$f" > /dev/null 2>&1; then
PAYLOAD=$(jq -r '.payload' "$f" | base64 -d 2>/dev/null || echo "")
if echo "$PAYLOAD" | jq -e '._stellaops.merkleRoot' > /dev/null 2>&1; then
MERKLE=$(echo "$PAYLOAD" | jq -r '._stellaops.merkleRoot')
echo " Merkle root: $MERKLE"
fi
fi
done

View File

@@ -18,12 +18,23 @@ jobs:
with:
fetch-depth: 0
- name: Fallback to dev signing key when secret is absent (non-prod only)
run: |
if [ -z "${MIRROR_SIGN_KEY_B64}" ]; then
echo "[warn] MIRROR_SIGN_KEY_B64 not set; using repo dev key for non-production signing."
echo "MIRROR_SIGN_KEY_B64=$(base64 -w0 tools/cosign/cosign.dev.key)" >> $GITHUB_ENV
echo "REQUIRE_PROD_SIGNING=0" >> $GITHUB_ENV
fi
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100-rc.2.25502.107
dotnet-version: 10.0.100
include-prerelease: true
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Verify signing prerequisites
run: scripts/mirror/check_signing_prereqs.sh
@@ -35,6 +46,16 @@ jobs:
run: |
scripts/mirror/verify_thin_bundle.py out/mirror/thin/mirror-thin-v1.tar.gz
- name: Prepare Export Center handoff (metadata + optional schedule)
run: |
scripts/mirror/export-center-wire.sh
env:
EXPORT_CENTER_BASE_URL: ${{ secrets.EXPORT_CENTER_BASE_URL }}
EXPORT_CENTER_TOKEN: ${{ secrets.EXPORT_CENTER_TOKEN }}
EXPORT_CENTER_TENANT: ${{ secrets.EXPORT_CENTER_TENANT }}
EXPORT_CENTER_PROJECT: ${{ secrets.EXPORT_CENTER_PROJECT }}
EXPORT_CENTER_AUTO_SCHEDULE: ${{ secrets.EXPORT_CENTER_AUTO_SCHEDULE }}
- name: Upload signed artifacts
uses: actions/upload-artifact@v4
with:
@@ -46,5 +67,8 @@ jobs:
out/mirror/thin/tuf/
out/mirror/thin/oci/
out/mirror/thin/milestone.json
out/mirror/thin/export-center/export-center-handoff.json
out/mirror/thin/export-center/export-center-targets.json
out/mirror/thin/export-center/schedule-response.json
if-no-files-found: error
retention-days: 14

View File

@@ -0,0 +1,44 @@
name: mock-dev-release
on:
push:
paths:
- deploy/releases/2025.09-mock-dev.yaml
- deploy/downloads/manifest.json
- ops/devops/mock-release/**
workflow_dispatch:
jobs:
package-mock-release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Package mock dev artefacts
run: |
set -euo pipefail
mkdir -p out/mock-release
cp deploy/releases/2025.09-mock-dev.yaml out/mock-release/
cp deploy/downloads/manifest.json out/mock-release/
tar -czf out/mock-release/mock-dev-release.tgz -C out/mock-release .
- name: Compose config (dev + mock overlay)
run: |
set -euo pipefail
ops/devops/mock-release/config_check.sh
- name: Helm template (mock overlay)
run: |
set -euo pipefail
helm template mock ./deploy/helm/stellaops -f deploy/helm/stellaops/values-mock.yaml > /tmp/helm-mock.yaml
ls -lh /tmp/helm-mock.yaml
- name: Upload mock release bundle
uses: actions/upload-artifact@v3
with:
name: mock-dev-release
path: |
out/mock-release/mock-dev-release.tgz
/tmp/compose-mock-config.yaml
/tmp/helm-mock.yaml

View File

@@ -0,0 +1,102 @@
name: Notify Smoke Test
on:
push:
branches: [main]
paths:
- 'src/Notify/**'
- 'src/Notifier/**'
pull_request:
paths:
- 'src/Notify/**'
- 'src/Notifier/**'
workflow_dispatch:
env:
DOTNET_VERSION: '10.0.x'
jobs:
unit-tests:
name: Notify Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Restore dependencies
run: dotnet restore src/Notify/
- name: Build
run: dotnet build src/Notify/ --no-restore
- name: Run tests
run: dotnet test src/Notify/ --no-build --verbosity normal
notifier-tests:
name: Notifier Service Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Restore dependencies
run: dotnet restore src/Notifier/
- name: Build
run: dotnet build src/Notifier/ --no-restore
- name: Run tests
run: dotnet test src/Notifier/ --no-build --verbosity normal
smoke-test:
name: Notification Smoke Test
runs-on: ubuntu-latest
needs: [unit-tests, notifier-tests]
services:
mongodb:
image: mongo:7.0
ports:
- 27017:27017
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Build Notifier
run: dotnet build src/Notifier/StellaOps.Notifier/StellaOps.Notifier.WebService/
- name: Start service
run: |
dotnet run --project src/Notifier/StellaOps.Notifier/StellaOps.Notifier.WebService/ &
sleep 10
- name: Health check
run: |
for i in {1..30}; do
if curl -s http://localhost:5000/health > /dev/null; then
echo "Service is healthy"
exit 0
fi
sleep 1
done
echo "Service failed to start"
exit 1
- name: Test notification endpoint
run: |
# Test dry-run notification
curl -X POST http://localhost:5000/api/v1/notifications/test \
-H "Content-Type: application/json" \
-d '{"channel": "log", "message": "Smoke test", "dryRun": true}' \
|| echo "Warning: Notification test endpoint not available"

View File

@@ -20,6 +20,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node.js
uses: actions/setup-node@v4
with:

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Python (telemetry schema checks)
uses: actions/setup-python@v5
with:

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install nats CLI
run: |
curl -sSL https://github.com/nats-io/natscli/releases/download/v0.1.4/nats-0.1.4-linux-amd64.tar.gz -o /tmp/natscli.tgz

View File

@@ -26,13 +26,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with:
fetch-depth: 0
- name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100-rc.2.25502.107
dotnet-version: 10.0.100
include-prerelease: true
- name: Cache NuGet packages

View File

@@ -27,13 +27,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with:
fetch-depth: 0
- name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100-rc.2.25502.107
dotnet-version: 10.0.100
include-prerelease: true
- name: Install Cosign

View File

@@ -25,6 +25,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Resolve staging credentials
id: staging
run: |

View File

@@ -9,6 +9,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Emit provenance summary
run: |
mkdir -p out/provenance

View File

@@ -0,0 +1,19 @@
name: release-manifest-verify
on:
push:
paths:
- deploy/releases/2025.09-stable.yaml
- deploy/releases/2025.09-airgap.yaml
- deploy/downloads/manifest.json
- ops/devops/release/check_release_manifest.py
workflow_dispatch:
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate release & downloads manifests
run: |
python ops/devops/release/check_release_manifest.py

View File

@@ -0,0 +1,120 @@
name: Release Validation
on:
push:
tags:
- 'v*'
pull_request:
paths:
- 'deploy/**'
- 'scripts/release/**'
workflow_dispatch:
env:
DOTNET_VERSION: '10.0.x'
REGISTRY: ghcr.io
IMAGE_PREFIX: stellaops
jobs:
validate-manifests:
name: Validate Release Manifests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Helm charts
run: |
helm lint deploy/helm/stellaops
helm template stellaops deploy/helm/stellaops --dry-run
- name: Validate Kubernetes manifests
run: |
for f in deploy/k8s/*.yaml; do
kubectl apply --dry-run=client -f "$f" || exit 1
done
- name: Check required images exist
run: |
REQUIRED_IMAGES=(
"concelier"
"scanner"
"authority"
"signer"
"attestor"
"excititor"
"policy"
"scheduler"
"notify"
)
for img in "${REQUIRED_IMAGES[@]}"; do
echo "Checking $img..."
# Validate Dockerfile exists
if [ ! -f "src/${img^}/Dockerfile" ] && [ ! -f "deploy/docker/${img}/Dockerfile" ]; then
echo "Warning: Dockerfile not found for $img"
fi
done
validate-checksums:
name: Validate Artifact Checksums
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify SHA256SUMS files
run: |
find . -name "SHA256SUMS" -type f | while read f; do
dir=$(dirname "$f")
echo "Validating $f..."
cd "$dir"
if ! sha256sum -c SHA256SUMS --quiet 2>/dev/null; then
echo "Warning: Checksum mismatch in $dir"
fi
cd - > /dev/null
done
validate-schemas:
name: Validate Schema Integrity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install ajv-cli
run: npm install -g ajv-cli ajv-formats
- name: Validate JSON schemas
run: |
for schema in docs/schemas/*.schema.json; do
echo "Validating $schema..."
ajv compile -s "$schema" --spec=draft2020 || echo "Warning: $schema validation issue"
done
release-notes:
name: Generate Release Notes
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs: [validate-manifests, validate-checksums, validate-schemas]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
run: |
PREV_TAG=$(git describe --abbrev=0 --tags HEAD^ 2>/dev/null || echo "")
if [ -n "$PREV_TAG" ]; then
echo "## Changes since $PREV_TAG" > RELEASE_NOTES.md
git log --pretty=format:"- %s (%h)" "$PREV_TAG"..HEAD >> RELEASE_NOTES.md
else
echo "## Initial Release" > RELEASE_NOTES.md
fi
- name: Upload release notes
uses: actions/upload-artifact@v4
with:
name: release-notes
path: RELEASE_NOTES.md

View File

@@ -36,7 +36,7 @@ jobs:
build-release:
runs-on: ubuntu-22.04
env:
DOTNET_VERSION: '10.0.100-rc.1.25451.107'
DOTNET_VERSION: '10.0.100'
REGISTRY: registry.stella-ops.org
steps:
- name: Checkout repository
@@ -44,6 +44,9 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Validate NuGet restore source ordering
run: python3 ops/devops/validate_restore_sources.py

View File

@@ -0,0 +1,198 @@
name: Risk Bundle CI
on:
push:
branches: [ main ]
paths:
- 'src/ExportCenter/StellaOps.ExportCenter.RiskBundles/**'
- 'src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/**'
- 'ops/devops/risk-bundle/**'
- '.gitea/workflows/risk-bundle-ci.yml'
- 'docs/modules/export-center/operations/risk-bundle-*.md'
pull_request:
branches: [ main, develop ]
paths:
- 'src/ExportCenter/StellaOps.ExportCenter.RiskBundles/**'
- 'src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/**'
- 'ops/devops/risk-bundle/**'
- '.gitea/workflows/risk-bundle-ci.yml'
- 'docs/modules/export-center/operations/risk-bundle-*.md'
workflow_dispatch:
inputs:
include_osv:
description: 'Include OSV providers (larger bundle)'
type: boolean
default: false
publish_checksums:
description: 'Publish checksums to artifact store'
type: boolean
default: true
jobs:
risk-bundle-build:
runs-on: ubuntu-22.04
env:
DOTNET_VERSION: '10.0.100'
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
BUNDLE_OUTPUT: ${{ github.workspace }}/.artifacts/risk-bundle
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh
- name: Set up .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
include-prerelease: true
- name: Restore
run: dotnet restore src/ExportCenter/StellaOps.ExportCenter.RiskBundles/StellaOps.ExportCenter.RiskBundles.csproj
- name: Build
run: dotnet build src/ExportCenter/StellaOps.ExportCenter.RiskBundles/StellaOps.ExportCenter.RiskBundles.csproj -c Release /p:ContinuousIntegrationBuild=true
- name: Test RiskBundle unit tests
run: |
mkdir -p $ARTIFACT_DIR
dotnet test src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/StellaOps.ExportCenter.Tests.csproj \
-c Release \
--filter "FullyQualifiedName~RiskBundle" \
--logger "trx;LogFileName=risk-bundle-tests.trx" \
--results-directory $ARTIFACT_DIR
- name: Build risk bundle (fixtures)
run: |
mkdir -p $BUNDLE_OUTPUT
ops/devops/risk-bundle/build-bundle.sh --output "$BUNDLE_OUTPUT" --fixtures-only
- name: Verify bundle integrity
run: ops/devops/risk-bundle/verify-bundle.sh "$BUNDLE_OUTPUT/risk-bundle.tar.gz"
- name: Generate checksums
run: |
cd $BUNDLE_OUTPUT
sha256sum risk-bundle.tar.gz > risk-bundle.tar.gz.sha256
sha256sum manifest.json > manifest.json.sha256
cat risk-bundle.tar.gz.sha256 manifest.json.sha256 > checksums.txt
echo "Bundle checksums:"
cat checksums.txt
- name: Upload risk bundle artifacts
uses: actions/upload-artifact@v4
with:
name: risk-bundle-artifacts
path: |
${{ env.BUNDLE_OUTPUT }}/risk-bundle.tar.gz
${{ env.BUNDLE_OUTPUT }}/risk-bundle.tar.gz.sig
${{ env.BUNDLE_OUTPUT }}/manifest.json
${{ env.BUNDLE_OUTPUT }}/checksums.txt
${{ env.ARTIFACT_DIR }}/*.trx
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: risk-bundle-test-results
path: ${{ env.ARTIFACT_DIR }}/*.trx
risk-bundle-offline-kit:
runs-on: ubuntu-22.04
needs: risk-bundle-build
env:
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
OFFLINE_KIT_DIR: ${{ github.workspace }}/.artifacts/offline-kit
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download risk bundle artifacts
uses: actions/download-artifact@v4
with:
name: risk-bundle-artifacts
path: ${{ env.ARTIFACT_DIR }}
- name: Package for offline kit
run: |
mkdir -p $OFFLINE_KIT_DIR/risk-bundles
cp $ARTIFACT_DIR/risk-bundle.tar.gz $OFFLINE_KIT_DIR/risk-bundles/
cp $ARTIFACT_DIR/risk-bundle.tar.gz.sig $OFFLINE_KIT_DIR/risk-bundles/ 2>/dev/null || true
cp $ARTIFACT_DIR/manifest.json $OFFLINE_KIT_DIR/risk-bundles/
cp $ARTIFACT_DIR/checksums.txt $OFFLINE_KIT_DIR/risk-bundles/
# Create offline kit manifest entry
cat > $OFFLINE_KIT_DIR/risk-bundles/kit-manifest.json <<EOF
{
"component": "risk-bundle",
"version": "$(date -u +%Y%m%d-%H%M%S)",
"files": [
{"path": "risk-bundle.tar.gz", "checksum_file": "risk-bundle.tar.gz.sha256"},
{"path": "manifest.json", "checksum_file": "manifest.json.sha256"}
],
"verification": {
"checksums": "checksums.txt",
"signature": "risk-bundle.tar.gz.sig"
}
}
EOF
- name: Verify offline kit structure
run: |
echo "Offline kit structure:"
find $OFFLINE_KIT_DIR -type f
echo ""
echo "Checksum verification:"
cd $OFFLINE_KIT_DIR/risk-bundles
sha256sum -c checksums.txt
- name: Upload offline kit
uses: actions/upload-artifact@v4
with:
name: risk-bundle-offline-kit
path: ${{ env.OFFLINE_KIT_DIR }}
publish-checksums:
runs-on: ubuntu-22.04
needs: risk-bundle-build
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event.inputs.publish_checksums == 'true')
env:
ARTIFACT_DIR: ${{ github.workspace }}/.artifacts
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download risk bundle artifacts
uses: actions/download-artifact@v4
with:
name: risk-bundle-artifacts
path: ${{ env.ARTIFACT_DIR }}
- name: Publish checksums
run: |
echo "Publishing checksums for risk bundle..."
CHECKSUM_DIR=out/checksums/risk-bundle/$(date -u +%Y-%m-%d)
mkdir -p $CHECKSUM_DIR
cp $ARTIFACT_DIR/checksums.txt $CHECKSUM_DIR/
cp $ARTIFACT_DIR/manifest.json $CHECKSUM_DIR/
# Create latest symlink manifest
cat > out/checksums/risk-bundle/latest.json <<EOF
{
"date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"path": "$(date -u +%Y-%m-%d)/checksums.txt",
"manifest": "$(date -u +%Y-%m-%d)/manifest.json"
}
EOF
echo "Checksums published to $CHECKSUM_DIR"
cat $CHECKSUM_DIR/checksums.txt
- name: Upload published checksums
uses: actions/upload-artifact@v4
with:
name: risk-bundle-published-checksums
path: out/checksums/risk-bundle/

View File

@@ -14,10 +14,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.100-rc.2.25502.107"
dotnet-version: "10.0.100"
- name: Install syft (SBOM)
uses: anchore/sbom-action/download-syft@v0

View File

@@ -0,0 +1,133 @@
name: Scanner Analyzers
on:
push:
branches: [main]
paths:
- 'src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.*/**'
- 'src/Scanner/__Tests/StellaOps.Scanner.Analyzers.*/**'
pull_request:
paths:
- 'src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.*/**'
- 'src/Scanner/__Tests/StellaOps.Scanner.Analyzers.*/**'
workflow_dispatch:
env:
DOTNET_VERSION: '10.0.x'
jobs:
discover-analyzers:
name: Discover Analyzers
runs-on: ubuntu-latest
outputs:
analyzers: ${{ steps.find.outputs.analyzers }}
steps:
- uses: actions/checkout@v4
- name: Find analyzer projects
id: find
run: |
ANALYZERS=$(find src/Scanner/__Libraries -name "StellaOps.Scanner.Analyzers.*.csproj" -exec dirname {} \; | xargs -I {} basename {} | sort -u | jq -R -s -c 'split("\n")[:-1]')
echo "analyzers=$ANALYZERS" >> $GITHUB_OUTPUT
build-analyzers:
name: Build Analyzers
runs-on: ubuntu-latest
needs: discover-analyzers
strategy:
fail-fast: false
matrix:
analyzer: ${{ fromJson(needs.discover-analyzers.outputs.analyzers) }}
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Restore
run: dotnet restore src/Scanner/__Libraries/${{ matrix.analyzer }}/
- name: Build
run: dotnet build src/Scanner/__Libraries/${{ matrix.analyzer }}/ --no-restore
test-lang-analyzers:
name: Test Language Analyzers
runs-on: ubuntu-latest
needs: build-analyzers
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Run Bun analyzer tests
run: |
if [ -d "src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Bun.Tests" ]; then
dotnet test src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Bun.Tests/ --verbosity normal
fi
- name: Run Node analyzer tests
run: |
if [ -d "src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Node.Tests" ]; then
dotnet test src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Node.Tests/ --verbosity normal
fi
fixture-validation:
name: Validate Test Fixtures
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate fixture structure
run: |
find src/Scanner/__Tests -name "expected.json" | while read f; do
echo "Validating $f..."
if ! jq empty "$f" 2>/dev/null; then
echo "Error: Invalid JSON in $f"
exit 1
fi
done
- name: Check fixture completeness
run: |
find src/Scanner/__Tests -type d -name "Fixtures" | while read fixtures_dir; do
echo "Checking $fixtures_dir..."
find "$fixtures_dir" -mindepth 1 -maxdepth 1 -type d | while read test_case; do
if [ ! -f "$test_case/expected.json" ]; then
echo "Warning: $test_case missing expected.json"
fi
done
done
determinism-check:
name: Verify Deterministic Output
runs-on: ubuntu-latest
needs: test-lang-analyzers
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Run determinism tests
run: |
# Run scanner on same input twice, compare outputs
if [ -d "tests/fixtures/determinism" ]; then
dotnet test --filter "Category=Determinism" --verbosity normal
fi

View File

@@ -9,10 +9,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.100-rc.2.25502.107"
dotnet-version: "10.0.100"
- name: Run determinism harness
run: |

View File

@@ -17,6 +17,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node.js
uses: actions/setup-node@v4
with:

View File

@@ -33,10 +33,13 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100-rc.2.25502.107
dotnet-version: 10.0.100
include-prerelease: true
- name: Cache NuGet packages

View File

@@ -31,10 +31,13 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100-rc.2.25502.107
dotnet-version: 10.0.100
include-prerelease: true
- name: Cache NuGet packages

View File

@@ -28,17 +28,32 @@ jobs:
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
OUT_DIR: ${{ github.event.inputs.out_dir || 'evidence-locker/signals/2025-12-01' }}
COSIGN_ALLOW_DEV_KEY: ${{ github.event.inputs.allow_dev_key || '0' }}
CI_EVIDENCE_LOCKER_TOKEN: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN || vars.CI_EVIDENCE_LOCKER_TOKEN }}
EVIDENCE_LOCKER_URL: ${{ secrets.EVIDENCE_LOCKER_URL || vars.EVIDENCE_LOCKER_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: 'v2.2.4'
- name: Check signing key configured
run: |
if [[ -z "$COSIGN_PRIVATE_KEY_B64" && "$COSIGN_ALLOW_DEV_KEY" != "1" ]]; then
echo "::error::COSIGN_PRIVATE_KEY_B64 is missing and dev key fallback is disabled. Set COSIGN_PRIVATE_KEY_B64 (and COSIGN_PASSWORD if needed) or rerun with allow_dev_key=1 for smoke only."
exit 1
fi
if [[ "$COSIGN_ALLOW_DEV_KEY" == "1" ]]; then
echo "::notice::Using dev key for signing (allow_dev_key=1) - not suitable for production uploads."
fi
- name: Verify artifacts exist
run: |
cd docs/modules/signals
@@ -87,9 +102,9 @@ jobs:
retention-days: 90
- name: Push to Evidence Locker
if: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN != '' && env.EVIDENCE_LOCKER_URL != '' }}
if: ${{ env.CI_EVIDENCE_LOCKER_TOKEN != '' && env.EVIDENCE_LOCKER_URL != '' }}
env:
TOKEN: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN }}
TOKEN: ${{ env.CI_EVIDENCE_LOCKER_TOKEN }}
URL: ${{ env.EVIDENCE_LOCKER_URL }}
run: |
tar -cf /tmp/signals-dsse.tar -C "$OUT_DIR" .
@@ -99,7 +114,7 @@ jobs:
echo "Pushed to Evidence Locker"
- name: Evidence Locker skip notice
if: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN == '' || env.EVIDENCE_LOCKER_URL == '' }}
if: ${{ env.CI_EVIDENCE_LOCKER_TOKEN == '' || env.EVIDENCE_LOCKER_URL == '' }}
run: |
echo "::notice::Evidence Locker push skipped (CI_EVIDENCE_LOCKER_TOKEN or EVIDENCE_LOCKER_URL not set)"
echo "Artifacts available as workflow artifact for manual ingestion"

View File

@@ -0,0 +1,106 @@
name: signals-evidence-locker
on:
workflow_dispatch:
inputs:
out_dir:
description: "Output directory containing signed artifacts"
required: false
default: "evidence-locker/signals/2025-12-05"
allow_dev_key:
description: "Allow dev key fallback (1=yes, 0=no)"
required: false
default: "0"
retention_target:
description: "Retention days target"
required: false
default: "180"
jobs:
prepare-signals-evidence:
runs-on: ubuntu-latest
env:
MODULE_ROOT: docs/modules/signals
OUT_DIR: ${{ github.event.inputs.out_dir || 'evidence-locker/signals/2025-12-05' }}
COSIGN_ALLOW_DEV_KEY: ${{ github.event.inputs.allow_dev_key || '0' }}
COSIGN_PRIVATE_KEY_B64: ${{ secrets.COSIGN_PRIVATE_KEY_B64 }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
EVIDENCE_LOCKER_URL: ${{ secrets.EVIDENCE_LOCKER_URL || vars.EVIDENCE_LOCKER_URL }}
CI_EVIDENCE_LOCKER_TOKEN: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN || vars.CI_EVIDENCE_LOCKER_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: 'v2.2.4'
- name: Check signing key configured
run: |
if [[ -z "$COSIGN_PRIVATE_KEY_B64" && "$COSIGN_ALLOW_DEV_KEY" != "1" ]]; then
echo "::error::COSIGN_PRIVATE_KEY_B64 is missing and dev key fallback is disabled. Set COSIGN_PRIVATE_KEY_B64 (and COSIGN_PASSWORD if needed) or rerun with allow_dev_key=1 for smoke only."
exit 1
fi
if [[ "$COSIGN_ALLOW_DEV_KEY" == "1" ]]; then
echo "::notice::Using dev key for signing (allow_dev_key=1) - not suitable for production uploads."
fi
- name: Verify artifacts exist
run: |
cd "$MODULE_ROOT"
sha256sum -c SHA256SUMS
- name: Sign signals artifacts
run: |
chmod +x tools/cosign/sign-signals.sh
OUT_DIR="${OUT_DIR}" tools/cosign/sign-signals.sh
- name: Build deterministic signals evidence tar
run: |
set -euo pipefail
test -d "$MODULE_ROOT" || { echo "missing $MODULE_ROOT" >&2; exit 1; }
tmpdir=$(mktemp -d)
rsync -a --relative \
"$OUT_DIR/SHA256SUMS" \
"$OUT_DIR/confidence_decay_config.sigstore.json" \
"$OUT_DIR/unknowns_scoring_manifest.sigstore.json" \
"$OUT_DIR/heuristics_catalog.sigstore.json" \
"$MODULE_ROOT/decay/confidence_decay_config.yaml" \
"$MODULE_ROOT/unknowns/unknowns_scoring_manifest.json" \
"$MODULE_ROOT/heuristics/heuristics.catalog.json" \
"$tmpdir/"
(cd "$tmpdir/$OUT_DIR" && sha256sum --check SHA256SUMS)
tar --sort=name --mtime="UTC 1970-01-01" --owner=0 --group=0 --numeric-owner \
-cf /tmp/signals-evidence.tar -C "$tmpdir" .
sha256sum /tmp/signals-evidence.tar > /tmp/signals-evidence.tar.sha256
- name: Upload artifact (fallback)
uses: actions/upload-artifact@v4
with:
name: signals-evidence-2025-12-05
path: |
/tmp/signals-evidence.tar
/tmp/signals-evidence.tar.sha256
- name: Push to Evidence Locker
if: ${{ env.CI_EVIDENCE_LOCKER_TOKEN != '' && env.EVIDENCE_LOCKER_URL != '' }}
env:
TOKEN: ${{ env.CI_EVIDENCE_LOCKER_TOKEN }}
URL: ${{ env.EVIDENCE_LOCKER_URL }}
run: |
upload_path="${OUT_DIR#evidence-locker/}"
curl -f -X PUT "$URL/${upload_path}/signals-evidence.tar" \
-H "Authorization: Bearer $TOKEN" \
--data-binary @/tmp/signals-evidence.tar
- name: Skip push (missing secret or URL)
if: ${{ env.CI_EVIDENCE_LOCKER_TOKEN == '' || env.EVIDENCE_LOCKER_URL == '' }}
run: |
echo "Locker push skipped: set CI_EVIDENCE_LOCKER_TOKEN and EVIDENCE_LOCKER_URL to enable." >&2

View File

@@ -0,0 +1,127 @@
name: Signals Reachability Scoring & Events
on:
workflow_dispatch:
inputs:
allow_dev_key:
description: "Allow dev signing key fallback (1=yes, 0=no)"
required: false
default: "0"
evidence_out_dir:
description: "Evidence output dir for signing/upload"
required: false
default: "evidence-locker/signals/2025-12-05"
push:
branches: [ main ]
paths:
- 'src/Signals/**'
- 'scripts/signals/reachability-smoke.sh'
- '.gitea/workflows/signals-reachability.yml'
- 'tools/cosign/sign-signals.sh'
jobs:
reachability-smoke:
runs-on: ubuntu-22.04
env:
DOTNET_NOLOGO: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1
TZ: UTC
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.100
include-prerelease: true
- name: Restore
run: dotnet restore src/Signals/StellaOps.Signals.sln --configfile nuget.config
- name: Build
run: dotnet build src/Signals/StellaOps.Signals.sln -c Release --no-restore
- name: Reachability scoring + cache/events smoke
run: |
chmod +x scripts/signals/reachability-smoke.sh
scripts/signals/reachability-smoke.sh
sign-and-upload:
runs-on: ubuntu-22.04
needs: reachability-smoke
env:
COSIGN_PRIVATE_KEY_B64: ${{ secrets.COSIGN_PRIVATE_KEY_B64 }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
COSIGN_ALLOW_DEV_KEY: ${{ github.event.inputs.allow_dev_key || '0' }}
OUT_DIR: ${{ github.event.inputs.evidence_out_dir || 'evidence-locker/signals/2025-12-05' }}
CI_EVIDENCE_LOCKER_TOKEN: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN || vars.CI_EVIDENCE_LOCKER_TOKEN }}
EVIDENCE_LOCKER_URL: ${{ secrets.EVIDENCE_LOCKER_URL || vars.EVIDENCE_LOCKER_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: 'v2.2.4'
- name: Check signing key configured
run: |
if [[ -z "$COSIGN_PRIVATE_KEY_B64" && "$COSIGN_ALLOW_DEV_KEY" != "1" ]]; then
echo "::error::COSIGN_PRIVATE_KEY_B64 is missing and dev key fallback is disabled. Set COSIGN_PRIVATE_KEY_B64 (and COSIGN_PASSWORD if needed) or rerun with allow_dev_key=1 for smoke only."
exit 1
fi
if [[ "$COSIGN_ALLOW_DEV_KEY" == "1" ]]; then
echo "::notice::Using dev key for signing (allow_dev_key=1) - not suitable for production uploads."
fi
- name: Verify artifacts exist
run: |
cd docs/modules/signals
sha256sum -c SHA256SUMS
- name: Sign signals artifacts
run: |
chmod +x tools/cosign/sign-signals.sh
OUT_DIR="${OUT_DIR}" tools/cosign/sign-signals.sh
- name: Upload signed artifacts
uses: actions/upload-artifact@v4
with:
name: signals-evidence-${{ github.run_number }}
path: |
${{ env.OUT_DIR }}/*.sigstore.json
${{ env.OUT_DIR }}/*.dsse
${{ env.OUT_DIR }}/SHA256SUMS
if-no-files-found: error
retention-days: 30
- name: Push to Evidence Locker
if: ${{ env.CI_EVIDENCE_LOCKER_TOKEN != '' && env.EVIDENCE_LOCKER_URL != '' }}
env:
TOKEN: ${{ env.CI_EVIDENCE_LOCKER_TOKEN }}
URL: ${{ env.EVIDENCE_LOCKER_URL }}
run: |
tar -cf /tmp/signals-evidence.tar -C "$OUT_DIR" .
sha256sum /tmp/signals-evidence.tar
curl -f -X PUT "$URL/signals/$(date -u +%Y-%m-%d)/signals-evidence.tar" \
-H "Authorization: Bearer $TOKEN" \
--data-binary @/tmp/signals-evidence.tar
echo "Uploaded to Evidence Locker"
- name: Evidence Locker skip notice
if: ${{ env.CI_EVIDENCE_LOCKER_TOKEN == '' || env.EVIDENCE_LOCKER_URL == '' }}
run: |
echo "::notice::Evidence Locker upload skipped (CI_EVIDENCE_LOCKER_TOKEN or EVIDENCE_LOCKER_URL not set)"

View File

@@ -0,0 +1,33 @@
name: sm-remote-ci
on:
push:
paths:
- "src/SmRemote/**"
- "src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote/**"
- "src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote.Tests/**"
- "ops/sm-remote/**"
- ".gitea/workflows/sm-remote-ci.yml"
pull_request:
paths:
- "src/SmRemote/**"
- "src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote/**"
- "src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote.Tests/**"
- "ops/sm-remote/**"
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: Restore
run: dotnet restore src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote.Tests/StellaOps.Cryptography.Plugin.SmRemote.Tests.csproj
- name: Test
run: dotnet test src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote.Tests/StellaOps.Cryptography.Plugin.SmRemote.Tests.csproj --no-build --verbosity normal
- name: Publish service
run: dotnet publish src/SmRemote/StellaOps.SmRemote.Service/StellaOps.SmRemote.Service.csproj -c Release -o out/sm-remote

View File

@@ -26,6 +26,9 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh

View File

@@ -17,6 +17,9 @@ jobs:
with:
fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh

View File

@@ -21,6 +21,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Python
uses: actions/setup-python@v5

28
.gitignore vendored
View File

@@ -39,3 +39,31 @@ build/
/src/Sdk/StellaOps.Sdk.Release/out/**
/src/Sdk/StellaOps.Sdk.Generator/out/**
/out/scanner-analyzers/**
# Node / frontend
node_modules/
dist/
.build/
.cache/
# .NET
bin/
obj/
# IDEs
.vscode/
.idea/
*.user
*.suo
# Misc
logs/
tmp/
coverage/
.nuget/
local-nugets/
local-nuget/
src/Sdk/StellaOps.Sdk.Generator/tools/jdk-21.0.1+12
.nuget-cache/
.nuget-packages2/
.nuget-temp/

View File

@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.
RequestId:111b5cf5-801e-0033-51f3-4ee25c000000
Time:2025-11-06T08:00:59.9404934Z</Message></Error>

Some files were not shown because too many files have changed in this diff Show More