Reusable CI workflows - the pipeline security boundary (task 04)
Find a file
forge-admin 7db09be7fd
Some checks failed
build-push-image.yml / README: safer caller triggers (avoid push+PR double-run cache race) (push) Failing after 0s
publish-nuget.yml / README: safer caller triggers (avoid push+PR double-run cache race) (push) Failing after 0s
publish-pypi.yml / README: safer caller triggers (avoid push+PR double-run cache race) (push) Failing after 0s
report-red.yml / README: safer caller triggers (avoid push+PR double-run cache race) (push) Failing after 0s
README: safer caller triggers (avoid push+PR double-run cache race)
2026-08-18 13:10:57 +02:00
.forgejo/workflows Task 04: reusable workflows - build/test, publish nuget+pypi, image build, test-shrink guard, report-red 2026-08-18 12:45:06 +02:00
README.md README: safer caller triggers (avoid push+PR double-run cache race) 2026-08-18 13:10:57 +02:00

Platform/workflows — reusable CI workflows (task 04)

THE security boundary of the assembly line: publish/deploy logic lives HERE, unit repos only contain thin callers. Branch protection (see Platform/org-policy) locks .forgejo/workflows/** in unit repos, and secrets exist only as org-level Actions secrets — so coding agents can never alter or exfiltrate the pipeline. See Platform/platform SECURITY.md.

Workflows

File What Secrets
build-test-csharp.yml restore, build Debug+Release, test
build-test-python.yml venv, install, pytest
publish-nuget.yml Version.txt-driven pack+push to the forge NuGet feed; skips if version already published; asserts package id == repo name REGISTRY_PUBLISH_TOKEN
publish-pypi.yml same for PyPI REGISTRY_PUBLISH_TOKEN
build-push-image.yml kaniko (no docker socket in jobs) build+push to the forge OCI registry, outputs image digest REGISTRY_PUBLISH_TOKEN
test-shrink-check.yml fails PRs that reduce test files/markers unless labeled tests-reduction-approved
report-red.yml files/updates an incident+ready issue when a main run goes red DISPATCH_TOKEN

Caller snippets (what unit repos get from the templates, task 05)

# .forgejo/workflows/build.yml
name: build
on:
  push:
    branches: [main]
  pull_request:
jobs:
  build:
    uses: Platform/workflows/.forgejo/workflows/build-test-csharp.yml@main
  report-red:
    needs: [build]
    if: ${{ failure() && github.ref == 'refs/heads/main' }}
    uses: Platform/workflows/.forgejo/workflows/report-red.yml@main
    secrets:
      DISPATCH_TOKEN: ${{ secrets.DISPATCH_TOKEN }}
# .forgejo/workflows/publish.yml
name: publish
on:
  push:
    branches: [main]
jobs:
  publish:
    uses: Platform/workflows/.forgejo/workflows/publish-nuget.yml@main
    secrets:
      REGISTRY_PUBLISH_TOKEN: ${{ secrets.REGISTRY_PUBLISH_TOKEN }}
# .forgejo/workflows/test-shrink.yml
name: test-shrink
on:
  pull_request:
    types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
  test-shrink:
    uses: Platform/workflows/.forgejo/workflows/test-shrink-check.yml@main

Notes

  • Runners: interactive (PR feedback) / batch (long jobs). Job containers have NO docker socket — that is why image builds use kaniko (git context, pushed with the registry token).
  • build-push-image.yml is verified end-to-end with the service template (task 05).
  • Actions (actions/checkout etc.) resolve from the local actions org mirrors, never github.com.
  • Callers should trigger push on main only (plus pull_request): running push+PR for the same branch commit doubles load and can race concurrent NuGet restores of the same new package in the shared /ci-cache volume (observed: Could not find file .../xunit.abstractions/...).
  • Publish auth: REGISTRY_PUBLISH_TOKEN org secret = deploy-bot PAT (package write only).