Files
git.stella-ops.org/docs/ci/20_CI_RECIPES.md
master 4e3e575db5 feat: Implement console session management with tenant and profile handling
- Add ConsoleSessionStore for managing console session state including tenants, profile, and token information.
- Create OperatorContextService to manage operator context for orchestrator actions.
- Implement OperatorMetadataInterceptor to enrich HTTP requests with operator context metadata.
- Develop ConsoleProfileComponent to display user profile and session details, including tenant information and access tokens.
- Add corresponding HTML and SCSS for ConsoleProfileComponent to enhance UI presentation.
- Write unit tests for ConsoleProfileComponent to ensure correct rendering and functionality.
2025-10-28 09:59:09 +02:00

15 KiB
Executable File
Raw Blame History

StellaOps CI Recipes — (20250804)

0·Key variables (export these once)

Variable Meaning Typical value
STELLA_URL Host that: ① stores the CLI & SBOMbuilder images under /registry and ② receives API calls at https://$STELLA_URL stella-ops.ci.acme.example
DOCKER_HOST How containers reach your Docker daemon (because we no longer mount /var/run/docker.sock) tcp://docker:2375
WORKSPACE Directory where the pipeline stores artefacts (SBOM file) $(pwd)
IMAGE The image you are building & scanning acme/backend:sha-${COMMIT_SHA}
SBOM_FILE Immutable SBOM name <image-ref>YYYYMMDDThhmmssZ.sbom.json acme_backend_shaabc12320250804T153050Z.sbom.json

Authority graph scopes note (2025-10-27): CI stages that spin up the Authority compose profile now rely on the checked-in etc/authority.yaml. Before running integration smoke jobs, inject real secrets for every etc/secrets/*.secret file (Cartographer, Graph API, Policy Engine, Concelier, Excititor). The repository defaults contain *-change-me placeholders and Authority will reject tokens if those secrets are not overridden. Reissue CI tokens that previously used policy:write/policy:submit/policy:edit scopes—new bundles must request policy:read, policy:author, policy:review, policy:simulate, and (policy:approve/policy:operate/policy:activate when pipelines promote policies).

export STELLA_URL="stella-ops.ci.acme.example"
export DOCKER_HOST="tcp://docker:2375"               # Jenkins/Circle often expose it like this
export WORKSPACE="$(pwd)"
export IMAGE="acme/backend:sha-${COMMIT_SHA}"
export SBOM_FILE="$(echo "${IMAGE}" | tr '/:+' '__')-$(date -u +%Y%m%dT%H%M%SZ).sbom.json"

1·SBOM creation strategies

Option A Buildx attested SBOM (preferred if you can use BuildKit)

You pass two build args so the Dockerfile can run the builder and copy the result out of the build context.

docker buildx build \
  --build-arg STELLA_SBOM_BUILDER="$STELLA_URL/registry/stella-sbom-builder:latest" \
  --provenance=true --sbom=true \
  --build-arg SBOM_FILE="$SBOM_FILE" \
  -t "$IMAGE" .

If you cannot use Buildx, use Option B below. The older “run a builder stage inside the Dockerfile” pattern is unreliable for producing an SBOM of the final image.


ARG STELLA_SBOM_BUILDER
ARG SBOM_FILE

FROM $STELLA_SBOM_BUILDER as sbom
ARG IMAGE
ARG SBOM_FILE
RUN $STELLA_SBOM_BUILDER build --image $IMAGE --output /out/$SBOM_FILE

# ---- actual build stages … ----
FROM alpine:3.20
COPY --from=sbom /out/$SBOM_FILE /     # (optional) keep or discard

# (rest of your Dockerfile)

(keep this block if your pipeline already has an imagebuild step that you cant modify)

docker run --rm \
  -e DOCKER_HOST="$DOCKER_HOST" \                       # let builder reach the daemon remotely
  -v "$WORKSPACE:/workspace" \                          # place SBOM beside the source code
  "$STELLA_URL/registry/stella-sbom-builder:latest" \
    build --image "$IMAGE" --output "/workspace/${SBOM_FILE}"

2·Scan the image & upload results

docker run --rm \
  -e DOCKER_HOST="$DOCKER_HOST" \                       # remotedaemon pointer
  -v "$WORKSPACE/${SBOM_FILE}:/${SBOM_FILE}:ro" \       # mount SBOM under same name at container root
  -e STELLA_OPS_URL="https://${STELLA_URL}" \           # where the CLI posts findings
  "$STELLA_URL/registry/stella-cli:latest" \
    scan --sbom "/${SBOM_FILE}" "$IMAGE"

The CLI returns exit 0 if policies pass, >0 if blocked — perfect for failing the job.


3·CI templates

Below are minimal, cutandpaste snippets. Feel free to deleteOption B if you adopt Option A.

3.1 Jenkins (Declarative Pipeline)

pipeline {
  agent { docker { image 'docker:25' args '--privileged' } }  // gives us /usr/bin/docker
  environment {
    STELLA_URL = 'stella-ops.ci.acme.example'
    DOCKER_HOST = 'tcp://docker:2375'
    IMAGE = "acme/backend:${env.BUILD_NUMBER}"
    SBOM_FILE = "acme_backend_${env.BUILD_NUMBER}-${new Date().format('yyyyMMdd\'T\'HHmmss\'Z\'', TimeZone.getTimeZone('UTC'))}.sbom.json"
  }
  stages {
    stage('Build image + SBOM (Option A)') {
      steps {
        sh '''
          docker build \
            --build-arg STELLA_SBOM_BUILDER="$STELLA_URL/registry/stella-sbom-builder:latest" \
            --build-arg SBOM_FILE="$SBOM_FILE" \
            -t "$IMAGE" .
        '''
      }
    }
    /* ---------- Option B fallback (when you must keep the existing build step asis) ----------
    stage('SBOM builder (Option B)') {
      steps {
        sh '''
          docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
            -v "$WORKSPACE:/workspace" \
            "$STELLA_URL/registry/stella-sbom-builder:latest" \
              build --image "$IMAGE" --output "/workspace/${SBOM_FILE}"
        '''
      }
    }
    ------------------------------------------------------------------------------------------ */
    stage('Scan & upload') {
      steps {
        sh '''
          docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
            -v "$WORKSPACE/${SBOM_FILE}:/${SBOM_FILE}:ro" \
            -e STELLA_OPS_URL="https://$STELLA_URL" \
            "$STELLA_URL/registry/stella-cli:latest" \
              scan --sbom "/${SBOM_FILE}" "$IMAGE"
        '''
      }
    }
  }
}

3.2 CircleCI .circleci/config.yml

version: 2.1
jobs:
  stella_scan:
    docker:
      - image: cimg/base:stable           # baremetal image with Docker CLI
    environment:
      STELLA_URL: stella-ops.ci.acme.example
      DOCKER_HOST: tcp://docker:2375      # Circles “remote Docker” socket
    steps:
      - checkout

      - run:
          name: Compute vars
          command: |
            echo 'export IMAGE="acme/backend:${CIRCLE_SHA1}"' >> $BASH_ENV
            echo 'export SBOM_FILE="$(echo acme/backend:${CIRCLE_SHA1} | tr "/:+" "__")-$(date -u +%Y%m%dT%H%M%SZ).sbom.json"' >> $BASH_ENV
      - run:
          name: Build image + SBOM (Option A)
          command: |
            docker build \
              --build-arg STELLA_SBOM_BUILDER="$STELLA_URL/registry/stella-sbom-builder:latest" \
              --build-arg SBOM_FILE="$SBOM_FILE" \
              -t "$IMAGE" .
      # --- Option B fallback (when you must keep the existing build step asis) ---
      #- run:
      #    name: SBOM builder (Option B)
      #    command: |
      #      docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
      #        -v "$PWD:/workspace" \
      #        "$STELLA_URL/registry/stella-sbom-builder:latest" \
      #          build --image "$IMAGE" --output "/workspace/${SBOM_FILE}"
      - run:
          name: Scan
          command: |
            docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
              -v "$PWD/${SBOM_FILE}:/${SBOM_FILE}:ro" \
              -e STELLA_OPS_URL="https://$STELLA_URL" \
              "$STELLA_URL/registry/stella-cli:latest" \
                scan --sbom "/${SBOM_FILE}" "$IMAGE"
workflows:
  stella:
    jobs: [stella_scan]

3.3 Gitea Actions .gitea/workflows/stella.yml

(Gitea 1.22+ ships native Actions compatible with GitHub syntax)

name: Stella Scan
on: [push]

jobs:
  stella:
    runs-on: ubuntu-latest
    env:
      STELLA_URL: ${{ secrets.STELLA_URL }}
      DOCKER_HOST: tcp://docker:2375       # provided by the docker:dind service
    services:
      docker:
        image: docker:dind
        options: >-
          --privileged
    steps:
      - uses: actions/checkout@v4

      - name: Compute vars
        id: vars
        run: |
          echo "IMAGE=ghcr.io/${{ gitea.repository }}:${{ gitea.sha }}" >> $GITEA_OUTPUT
          echo "SBOM_FILE=$(echo ghcr.io/${{ gitea.repository }}:${{ gitea.sha }} | tr '/:+' '__')-$(date -u +%Y%m%dT%H%M%SZ).sbom.json" >> $GITEA_OUTPUT

      - name: Build image + SBOM (Option A)
        run: |
          docker build \
            --build-arg STELLA_SBOM_BUILDER="${STELLA_URL}/registry/stella-sbom-builder:latest" \
            --build-arg SBOM_FILE="${{ steps.vars.outputs.SBOM_FILE }}" \
            -t "${{ steps.vars.outputs.IMAGE }}" .

      # --- Option B fallback (when you must keep the existing build step asis) ---
      #- name: SBOM builder (Option B)
      #  run: |
      #    docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
      #      -v "$(pwd):/workspace" \
      #      "${STELLA_URL}/registry/stella-sbom-builder:latest" \
      #        build --image "${{ steps.vars.outputs.IMAGE }}" --output "/workspace/${{ steps.vars.outputs.SBOM_FILE }}"

      - name: Scan
        run: |
          docker run --rm -e DOCKER_HOST="$DOCKER_HOST" \
            -v "$(pwd)/${{ steps.vars.outputs.SBOM_FILE }}:/${{ steps.vars.outputs.SBOM_FILE }}:ro" \
            -e STELLA_OPS_URL="https://${STELLA_URL}" \
            "${STELLA_URL}/registry/stella-cli:latest" \
              scan --sbom "/${{ steps.vars.outputs.SBOM_FILE }}" "${{ steps.vars.outputs.IMAGE }}"

4·Docs CI (Gitea Actions & Offline Mirror)

StellaOps ships a dedicated Docs workflow at .gitea/workflows/docs.yml. When mirroring the pipeline offline or running it locally, install the same toolchain so markdown linting, schema validation, and HTML preview stay deterministic.

4.1 Toolchain bootstrap

# Node.js 20.x is required; install once per runner
npm install --no-save \
  markdown-link-check \
  remark-cli \
  remark-preset-lint-recommended \
  ajv \
  ajv-cli \
  ajv-formats

# Python 3.11+ powers the preview renderer
python -m pip install --upgrade pip
python -m pip install markdown pygments

No pip available? Some hardened Python builds (including the repos tmp/docenv interpreter) ship without pip/ensurepip. In that case download the purePython sdists (e.g. Markdown-3.x.tar.gz, pygments-2.x.tar.gz) and extract their packages directly into the virtualenvs lib/python*/site-packages/ folder. This keeps the renderer working even when package managers are disabled.

Offline tip. Add the packages above to your artifact mirror (for example ops/devops/offline-kit.json) so runners can install them via npm --offline / pip --no-index.

4.2 Schema validation step

Ajv compiles every event schema to guard against syntax or format regressions. The workflow uses ajv-formats for UUID/date-time support.

for schema in docs/events/*.json; do
  npx ajv compile -c ajv-formats -s "$schema"
done

Run this loop before committing schema changes. For new references, append -r additional-file.json so CI and local runs stay aligned.

4.3 Preview build

python scripts/render_docs.py --source docs --output artifacts/docs-preview --clean

Host the resulting bundle via any static file server for review (for example python -m http.server).

4.4 Publishing checklist

  • Toolchain installs succeed without hitting the public internet (mirror or cached tarballs).
  • Ajv validation passes for scanner.report.ready@1, scheduler.rescan.delta@1, attestor.logged@1.
  • Markdown link check (npx markdown-link-check) reports no broken references.
  • Preview bundle archived (or attached) for stakeholders.

4.5 Policy DSL lint stage

Policy Engine v2 pipelines now fail fast if policy documents are malformed. After checkout and dotnet restore, run:

dotnet run \
  --project tools/PolicyDslValidator/PolicyDslValidator.csproj \
  -- \
  --strict docs/examples/policies/*.yaml
  • --strict treats warnings as errors so missing metadata doesnt slip through.
  • The validator accepts globs, so you can point it at tenant policy directories later (policies/**/*.yaml).
  • Exit codes follow UNIX conventions: 0 success, 1 parse/errors, 2 warnings when --strict is set, 64 usage mistakes.

Capture the validator output as part of your build logs; Support uses it when triaging policy rollout issues.

4.6 Policy simulation smoke

Catch unexpected policy regressions by exercising a small set of golden SBOM findings via the simulation smoke tool:

dotnet run \
  --project tools/PolicySimulationSmoke/PolicySimulationSmoke.csproj \
  -- \
  --scenario-root samples/policy/simulations \
  --output artifacts/policy-simulations
  • The tool loads each scenario.json under samples/policy/simulations, evaluates the referenced policy, and fails the build if projected verdicts change.
  • In CI the command runs twice (to run1/ and run2/) and diff -u compares the summaries—any mismatch signals a determinism regression.
  • Artifacts land in artifacts/policy-simulations/policy-simulation-summary.json; upload them for later inspection (see CI workflow).
  • Expand scenarios by copying real-world findings into the samples directory—ensure expected statuses are recorded so regressions trip the pipeline.

5·Troubleshooting cheatsheet

Symptom Root cause First things to try
no such host $STELLA_URL DNS typo or VPN outage ping $STELLA_URL from runner
connection refused when CLI uploads Port 443 blocked open firewall / check ingress
failed to stat /<sbom>.json SBOM wasnt produced Did Option A actually run builder? If not, enable Option B
registry unauthorized Runner lacks registry creds docker login $STELLA_URL/registry (store creds in CI secrets)
Nonzero scan exit Blocking vuln/licence Open project in Ops UI → triage or waive

Change log

  • 20251018 Documented Docs CI toolchain (Ajv validation, static preview) and offline checklist.
  • 20250804 Variable cleanup, removed Dockersocket & cache mounts, added Jenkins / CircleCI / Gitea examples, clarified Option B comment.