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
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
This commit is contained in:
@@ -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
23
.dockerignore
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
128
.gitea/workflows/artifact-signing.yml
Normal file
128
.gitea/workflows/artifact-signing.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' }}
|
||||
|
||||
@@ -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
|
||||
|
||||
32
.gitea/workflows/concelier-store-aoc-19-005.yml
Normal file
32
.gitea/workflows/concelier-store-aoc-19-005.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
32
.gitea/workflows/console-runner-image.yml
Normal file
32
.gitea/workflows/console-runner-image.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
55
.gitea/workflows/cryptopro-linux-csp.yml
Normal file
55
.gitea/workflows/cryptopro-linux-csp.yml
Normal 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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
325
.gitea/workflows/findings-ledger-ci.yml
Normal file
325
.gitea/workflows/findings-ledger-ci.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
68
.gitea/workflows/icscisa-kisa-refresh.yml
Normal file
68
.gitea/workflows/icscisa-kisa-refresh.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
125
.gitea/workflows/manifest-integrity.yml
Normal file
125
.gitea/workflows/manifest-integrity.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
44
.gitea/workflows/mock-dev-release.yml
Normal file
44
.gitea/workflows/mock-dev-release.yml
Normal 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
|
||||
102
.gitea/workflows/notify-smoke-test.yml
Normal file
102
.gitea/workflows/notify-smoke-test.yml
Normal 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"
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,206 +1,209 @@
|
||||
# .gitea/workflows/promote.yml
|
||||
# Manual promotion workflow to copy staged artefacts to production
|
||||
|
||||
name: Promote Feedser (Manual)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
include_docs:
|
||||
description: 'Also promote the generated documentation bundle'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
tag:
|
||||
description: 'Optional build identifier to record in the summary'
|
||||
required: false
|
||||
default: 'latest'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
promote:
|
||||
runs-on: ubuntu-22.04
|
||||
environment: production
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Resolve staging credentials
|
||||
id: staging
|
||||
run: |
|
||||
missing=()
|
||||
|
||||
host="${{ secrets.STAGING_DEPLOYMENT_HOST }}"
|
||||
if [ -z "$host" ]; then host="${{ vars.STAGING_DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then missing+=("STAGING_DEPLOYMENT_HOST"); fi
|
||||
|
||||
user="${{ secrets.STAGING_DEPLOYMENT_USERNAME }}"
|
||||
if [ -z "$user" ]; then user="${{ vars.STAGING_DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then missing+=("STAGING_DEPLOYMENT_USERNAME"); fi
|
||||
|
||||
path="${{ secrets.STAGING_DEPLOYMENT_PATH }}"
|
||||
if [ -z "$path" ]; then path="${{ vars.STAGING_DEPLOYMENT_PATH }}"; fi
|
||||
if [ -z "$path" ]; then missing+=("STAGING_DEPLOYMENT_PATH")
|
||||
fi
|
||||
|
||||
docs_path="${{ secrets.STAGING_DOCS_PATH }}"
|
||||
if [ -z "$docs_path" ]; then docs_path="${{ vars.STAGING_DOCS_PATH }}"; fi
|
||||
|
||||
key="${{ secrets.STAGING_DEPLOYMENT_KEY }}"
|
||||
if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.STAGING_DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then missing+=("STAGING_DEPLOYMENT_KEY"); fi
|
||||
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
echo "❌ Missing staging configuration: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
key_file="$RUNNER_TEMP/staging_key"
|
||||
printf '%s\n' "$key" > "$key_file"
|
||||
chmod 600 "$key_file"
|
||||
|
||||
echo "host=$host" >> $GITHUB_OUTPUT
|
||||
echo "user=$user" >> $GITHUB_OUTPUT
|
||||
echo "path=$path" >> $GITHUB_OUTPUT
|
||||
echo "docs-path=$docs_path" >> $GITHUB_OUTPUT
|
||||
echo "key-file=$key_file" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Resolve production credentials
|
||||
id: production
|
||||
run: |
|
||||
missing=()
|
||||
|
||||
host="${{ secrets.PRODUCTION_DEPLOYMENT_HOST }}"
|
||||
if [ -z "$host" ]; then host="${{ vars.PRODUCTION_DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then missing+=("PRODUCTION_DEPLOYMENT_HOST"); fi
|
||||
|
||||
user="${{ secrets.PRODUCTION_DEPLOYMENT_USERNAME }}"
|
||||
if [ -z "$user" ]; then user="${{ vars.PRODUCTION_DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then missing+=("PRODUCTION_DEPLOYMENT_USERNAME"); fi
|
||||
|
||||
path="${{ secrets.PRODUCTION_DEPLOYMENT_PATH }}"
|
||||
if [ -z "$path" ]; then path="${{ vars.PRODUCTION_DEPLOYMENT_PATH }}"; fi
|
||||
if [ -z "$path" ]; then missing+=("PRODUCTION_DEPLOYMENT_PATH")
|
||||
fi
|
||||
|
||||
docs_path="${{ secrets.PRODUCTION_DOCS_PATH }}"
|
||||
if [ -z "$docs_path" ]; then docs_path="${{ vars.PRODUCTION_DOCS_PATH }}"; fi
|
||||
|
||||
key="${{ secrets.PRODUCTION_DEPLOYMENT_KEY }}"
|
||||
if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.PRODUCTION_DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then missing+=("PRODUCTION_DEPLOYMENT_KEY"); fi
|
||||
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
echo "❌ Missing production configuration: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
key_file="$RUNNER_TEMP/production_key"
|
||||
printf '%s\n' "$key" > "$key_file"
|
||||
chmod 600 "$key_file"
|
||||
|
||||
echo "host=$host" >> $GITHUB_OUTPUT
|
||||
echo "user=$user" >> $GITHUB_OUTPUT
|
||||
echo "path=$path" >> $GITHUB_OUTPUT
|
||||
echo "docs-path=$docs_path" >> $GITHUB_OUTPUT
|
||||
echo "key-file=$key_file" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install rsync
|
||||
run: |
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
CACHE_DIR="${CI_CACHE_ROOT:-/tmp}/apt"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
KEY="rsync-$(lsb_release -rs 2>/dev/null || echo unknown)"
|
||||
DEB_DIR="$CACHE_DIR/$KEY"
|
||||
mkdir -p "$DEB_DIR"
|
||||
if ls "$DEB_DIR"/rsync*.deb >/dev/null 2>&1; then
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb
|
||||
else
|
||||
apt-get update
|
||||
apt-get download rsync libpopt0
|
||||
mv rsync*.deb libpopt0*.deb "$DEB_DIR"/
|
||||
dpkg -i "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb || apt-get install -f -y
|
||||
fi
|
||||
|
||||
- name: Fetch staging artefacts
|
||||
id: fetch
|
||||
run: |
|
||||
staging_root="${{ runner.temp }}/staging"
|
||||
mkdir -p "$staging_root/service" "$staging_root/docs"
|
||||
|
||||
echo "📥 Copying service bundle from staging"
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs.path }}/" \
|
||||
"$staging_root/service/"
|
||||
|
||||
if [ "${{ github.event.inputs.include_docs }}" = "true" ] && [ -n "${{ steps.staging.outputs['docs-path'] }}" ]; then
|
||||
echo "📥 Copying documentation bundle from staging"
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs['docs-path'] }}/" \
|
||||
"$staging_root/docs/"
|
||||
else
|
||||
echo "ℹ️ Documentation promotion skipped"
|
||||
fi
|
||||
|
||||
echo "service-dir=$staging_root/service" >> $GITHUB_OUTPUT
|
||||
echo "docs-dir=$staging_root/docs" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Backup production service content
|
||||
run: |
|
||||
ssh -o StrictHostKeyChecking=no -i "${{ steps.production.outputs['key-file'] }}" \
|
||||
"${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}" \
|
||||
"set -e; TARGET='${{ steps.production.outputs.path }}'; \
|
||||
if [ -d \"$TARGET\" ]; then \
|
||||
parent=\$(dirname \"$TARGET\"); \
|
||||
base=\$(basename \"$TARGET\"); \
|
||||
backup=\"\$parent/\${base}.backup.\$(date +%Y%m%d_%H%M%S)\"; \
|
||||
mkdir -p \"\$backup\"; \
|
||||
rsync -a --delete \"$TARGET/\" \"\$backup/\"; \
|
||||
ls -dt \"\$parent/\${base}.backup.*\" 2>/dev/null | tail -n +6 | xargs rm -rf || true; \
|
||||
echo 'Backup created at ' \"\$backup\"; \
|
||||
else \
|
||||
echo 'Production service path missing; skipping backup'; \
|
||||
fi"
|
||||
|
||||
- name: Publish service to production
|
||||
run: |
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.fetch.outputs['service-dir'] }}/" \
|
||||
"${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs.path }}/"
|
||||
|
||||
- name: Promote documentation bundle
|
||||
if: github.event.inputs.include_docs == 'true' && steps.production.outputs['docs-path'] != ''
|
||||
run: |
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.fetch.outputs['docs-dir'] }}/" \
|
||||
"${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs['docs-path'] }}/"
|
||||
|
||||
- name: Promotion summary
|
||||
run: |
|
||||
echo "✅ Promotion completed"
|
||||
echo " Tag: ${{ github.event.inputs.tag }}"
|
||||
echo " Service: ${{ steps.staging.outputs.host }} → ${{ steps.production.outputs.host }}"
|
||||
if [ "${{ github.event.inputs.include_docs }}" = "true" ]; then
|
||||
echo " Docs: included"
|
||||
else
|
||||
echo " Docs: skipped"
|
||||
fi
|
||||
# .gitea/workflows/promote.yml
|
||||
# Manual promotion workflow to copy staged artefacts to production
|
||||
|
||||
name: Promote Feedser (Manual)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
include_docs:
|
||||
description: 'Also promote the generated documentation bundle'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
tag:
|
||||
description: 'Optional build identifier to record in the summary'
|
||||
required: false
|
||||
default: 'latest'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
promote:
|
||||
runs-on: ubuntu-22.04
|
||||
environment: production
|
||||
steps:
|
||||
- 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: |
|
||||
missing=()
|
||||
|
||||
host="${{ secrets.STAGING_DEPLOYMENT_HOST }}"
|
||||
if [ -z "$host" ]; then host="${{ vars.STAGING_DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then missing+=("STAGING_DEPLOYMENT_HOST"); fi
|
||||
|
||||
user="${{ secrets.STAGING_DEPLOYMENT_USERNAME }}"
|
||||
if [ -z "$user" ]; then user="${{ vars.STAGING_DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then missing+=("STAGING_DEPLOYMENT_USERNAME"); fi
|
||||
|
||||
path="${{ secrets.STAGING_DEPLOYMENT_PATH }}"
|
||||
if [ -z "$path" ]; then path="${{ vars.STAGING_DEPLOYMENT_PATH }}"; fi
|
||||
if [ -z "$path" ]; then missing+=("STAGING_DEPLOYMENT_PATH")
|
||||
fi
|
||||
|
||||
docs_path="${{ secrets.STAGING_DOCS_PATH }}"
|
||||
if [ -z "$docs_path" ]; then docs_path="${{ vars.STAGING_DOCS_PATH }}"; fi
|
||||
|
||||
key="${{ secrets.STAGING_DEPLOYMENT_KEY }}"
|
||||
if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.STAGING_DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then missing+=("STAGING_DEPLOYMENT_KEY"); fi
|
||||
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
echo "❌ Missing staging configuration: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
key_file="$RUNNER_TEMP/staging_key"
|
||||
printf '%s\n' "$key" > "$key_file"
|
||||
chmod 600 "$key_file"
|
||||
|
||||
echo "host=$host" >> $GITHUB_OUTPUT
|
||||
echo "user=$user" >> $GITHUB_OUTPUT
|
||||
echo "path=$path" >> $GITHUB_OUTPUT
|
||||
echo "docs-path=$docs_path" >> $GITHUB_OUTPUT
|
||||
echo "key-file=$key_file" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Resolve production credentials
|
||||
id: production
|
||||
run: |
|
||||
missing=()
|
||||
|
||||
host="${{ secrets.PRODUCTION_DEPLOYMENT_HOST }}"
|
||||
if [ -z "$host" ]; then host="${{ vars.PRODUCTION_DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi
|
||||
if [ -z "$host" ]; then missing+=("PRODUCTION_DEPLOYMENT_HOST"); fi
|
||||
|
||||
user="${{ secrets.PRODUCTION_DEPLOYMENT_USERNAME }}"
|
||||
if [ -z "$user" ]; then user="${{ vars.PRODUCTION_DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi
|
||||
if [ -z "$user" ]; then missing+=("PRODUCTION_DEPLOYMENT_USERNAME"); fi
|
||||
|
||||
path="${{ secrets.PRODUCTION_DEPLOYMENT_PATH }}"
|
||||
if [ -z "$path" ]; then path="${{ vars.PRODUCTION_DEPLOYMENT_PATH }}"; fi
|
||||
if [ -z "$path" ]; then missing+=("PRODUCTION_DEPLOYMENT_PATH")
|
||||
fi
|
||||
|
||||
docs_path="${{ secrets.PRODUCTION_DOCS_PATH }}"
|
||||
if [ -z "$docs_path" ]; then docs_path="${{ vars.PRODUCTION_DOCS_PATH }}"; fi
|
||||
|
||||
key="${{ secrets.PRODUCTION_DEPLOYMENT_KEY }}"
|
||||
if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.PRODUCTION_DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi
|
||||
if [ -z "$key" ]; then missing+=("PRODUCTION_DEPLOYMENT_KEY"); fi
|
||||
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
echo "❌ Missing production configuration: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
key_file="$RUNNER_TEMP/production_key"
|
||||
printf '%s\n' "$key" > "$key_file"
|
||||
chmod 600 "$key_file"
|
||||
|
||||
echo "host=$host" >> $GITHUB_OUTPUT
|
||||
echo "user=$user" >> $GITHUB_OUTPUT
|
||||
echo "path=$path" >> $GITHUB_OUTPUT
|
||||
echo "docs-path=$docs_path" >> $GITHUB_OUTPUT
|
||||
echo "key-file=$key_file" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install rsync
|
||||
run: |
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
CACHE_DIR="${CI_CACHE_ROOT:-/tmp}/apt"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
KEY="rsync-$(lsb_release -rs 2>/dev/null || echo unknown)"
|
||||
DEB_DIR="$CACHE_DIR/$KEY"
|
||||
mkdir -p "$DEB_DIR"
|
||||
if ls "$DEB_DIR"/rsync*.deb >/dev/null 2>&1; then
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb
|
||||
else
|
||||
apt-get update
|
||||
apt-get download rsync libpopt0
|
||||
mv rsync*.deb libpopt0*.deb "$DEB_DIR"/
|
||||
dpkg -i "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb || apt-get install -f -y
|
||||
fi
|
||||
|
||||
- name: Fetch staging artefacts
|
||||
id: fetch
|
||||
run: |
|
||||
staging_root="${{ runner.temp }}/staging"
|
||||
mkdir -p "$staging_root/service" "$staging_root/docs"
|
||||
|
||||
echo "📥 Copying service bundle from staging"
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs.path }}/" \
|
||||
"$staging_root/service/"
|
||||
|
||||
if [ "${{ github.event.inputs.include_docs }}" = "true" ] && [ -n "${{ steps.staging.outputs['docs-path'] }}" ]; then
|
||||
echo "📥 Copying documentation bundle from staging"
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs['docs-path'] }}/" \
|
||||
"$staging_root/docs/"
|
||||
else
|
||||
echo "ℹ️ Documentation promotion skipped"
|
||||
fi
|
||||
|
||||
echo "service-dir=$staging_root/service" >> $GITHUB_OUTPUT
|
||||
echo "docs-dir=$staging_root/docs" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Backup production service content
|
||||
run: |
|
||||
ssh -o StrictHostKeyChecking=no -i "${{ steps.production.outputs['key-file'] }}" \
|
||||
"${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}" \
|
||||
"set -e; TARGET='${{ steps.production.outputs.path }}'; \
|
||||
if [ -d \"$TARGET\" ]; then \
|
||||
parent=\$(dirname \"$TARGET\"); \
|
||||
base=\$(basename \"$TARGET\"); \
|
||||
backup=\"\$parent/\${base}.backup.\$(date +%Y%m%d_%H%M%S)\"; \
|
||||
mkdir -p \"\$backup\"; \
|
||||
rsync -a --delete \"$TARGET/\" \"\$backup/\"; \
|
||||
ls -dt \"\$parent/\${base}.backup.*\" 2>/dev/null | tail -n +6 | xargs rm -rf || true; \
|
||||
echo 'Backup created at ' \"\$backup\"; \
|
||||
else \
|
||||
echo 'Production service path missing; skipping backup'; \
|
||||
fi"
|
||||
|
||||
- name: Publish service to production
|
||||
run: |
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.fetch.outputs['service-dir'] }}/" \
|
||||
"${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs.path }}/"
|
||||
|
||||
- name: Promote documentation bundle
|
||||
if: github.event.inputs.include_docs == 'true' && steps.production.outputs['docs-path'] != ''
|
||||
run: |
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \
|
||||
"${{ steps.fetch.outputs['docs-dir'] }}/" \
|
||||
"${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs['docs-path'] }}/"
|
||||
|
||||
- name: Promotion summary
|
||||
run: |
|
||||
echo "✅ Promotion completed"
|
||||
echo " Tag: ${{ github.event.inputs.tag }}"
|
||||
echo " Service: ${{ steps.staging.outputs.host }} → ${{ steps.production.outputs.host }}"
|
||||
if [ "${{ github.event.inputs.include_docs }}" = "true" ]; then
|
||||
echo " Docs: included"
|
||||
else
|
||||
echo " Docs: skipped"
|
||||
fi
|
||||
|
||||
@@ -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
|
||||
|
||||
19
.gitea/workflows/release-manifest-verify.yml
Normal file
19
.gitea/workflows/release-manifest-verify.yml
Normal 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
|
||||
120
.gitea/workflows/release-validation.yml
Normal file
120
.gitea/workflows/release-validation.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
198
.gitea/workflows/risk-bundle-ci.yml
Normal file
198
.gitea/workflows/risk-bundle-ci.yml
Normal 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/
|
||||
@@ -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
|
||||
|
||||
133
.gitea/workflows/scanner-analyzers.yml
Normal file
133
.gitea/workflows/scanner-analyzers.yml
Normal 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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
106
.gitea/workflows/signals-evidence-locker.yml
Normal file
106
.gitea/workflows/signals-evidence-locker.yml
Normal 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
|
||||
127
.gitea/workflows/signals-reachability.yml
Normal file
127
.gitea/workflows/signals-reachability.yml
Normal 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)"
|
||||
33
.gitea/workflows/sm-remote-ci.yml
Normal file
33
.gitea/workflows/sm-remote-ci.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
54
.gitignore
vendored
54
.gitignore
vendored
@@ -14,11 +14,11 @@ obj/
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# Packages and logs
|
||||
*.log
|
||||
TestResults/
|
||||
local-nuget/
|
||||
local-nugets/packages/
|
||||
# Packages and logs
|
||||
*.log
|
||||
TestResults/
|
||||
local-nuget/
|
||||
local-nugets/packages/
|
||||
|
||||
.dotnet
|
||||
.DS_Store
|
||||
@@ -31,11 +31,39 @@ seed-data/cert-bund/**/*.sha256
|
||||
out/offline-kit/web/**/*
|
||||
**/node_modules/**/*
|
||||
**/.angular/**/*
|
||||
**/.cache/**/*
|
||||
**/dist/**/*
|
||||
tmp/**/*
|
||||
build/
|
||||
/out/cli/**
|
||||
/src/Sdk/StellaOps.Sdk.Release/out/**
|
||||
/src/Sdk/StellaOps.Sdk.Generator/out/**
|
||||
/out/scanner-analyzers/**
|
||||
**/.cache/**/*
|
||||
**/dist/**/*
|
||||
tmp/**/*
|
||||
build/
|
||||
/out/cli/**
|
||||
/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/
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user