Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 65 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,109 @@

Shared reusable GitHub Actions workflows and composite actions for the Defguard repositories.

## Caller pattern
## Ref policy: pinned semver + Renovate

### Reusable workflows
**Product repos pin a specific semver tag.** No floating `@v1` in committed caller workflow files.

Product repos reference workflows from this repo by major tag:
```yaml
# Correct: pinned to a specific release
uses: defguard/ci-workflows/.github/workflows/rehearsal.yml@v1.0.0
```

```yaml
# Incorrect: floating major tag -- do not commit this
uses: defguard/ci-workflows/.github/workflows/rehearsal.yml@v1
```

Passing inputs and secrets explicitly per the workflow's contract:
**Renovate keeps the pin current.** A regex manager in the shared Renovate preset (`renovate/default.json`) scans product-repo workflow files for `DefGuard/ci-workflows/.+@vX.Y.Z` and opens a single grouped PR when a new tag is published. The fix-still-lands-once property is preserved - just behind a merge button.

**`@v1` exists as a convenience pointer** for local/dispatch use, but product repos **must not reference it** in committed workflow files.

### How to cut a release

After a reviewed PR merges to `main`:

```sh
git checkout main
git pull
git tag -a v1.0.1 -m "v1.0.1: description of change"
git tag -f v1
git push origin v1.0.1
git push origin v1 --force
```

Renovate will then open a PR in each product repo to bump the pinned ref from `@v1.0.0` to `@v1.0.1`.

Breaking changes require a new major tag (`v2`) and a migration guide before the old major line is retired.

## Thin-caller pattern

**A product repo's caller workflow is a pure pass-through.** It contains only the `uses:` call plus triggers and concurrency controls - no pre/post jobs, no additional steps.

```yaml
# Example: defguard/.github/workflows/rehearsal.yml
name: Weekly Release Rehearsal
on:
schedule:
- cron: '0 8 * * 1' # Monday 08:00 UTC
workflow_dispatch:

concurrency:
group: rehearsal-${{ github.ref }}
cancel-in-progress: true

jobs:
rehearsal:
uses: defguard/ci-workflows/.github/workflows/rehearsal.yml@v1
uses: defguard/ci-workflows/.github/workflows/rehearsal.yml@v1.0.0
with:
publish: false
branch: dev
secrets:
MATRIX_WEBHOOK: ${{ secrets.MATRIX_WEBHOOK }}
MATRIX_WEBHOOK_URL: ${{ secrets.MATRIX_WEBHOOK_URL }}
GHCR_READ_TOKEN: ${{ secrets.GHCR_READ_TOKEN }}
```

**Rationale:** this guarantees rehearsal and release call the exact same underlying jobs with no hidden divergence. If a repo needs a repo-specific step, extract it into ci-workflows behind a parameter - do not add it to the caller.

### Composite actions

Composite actions are called from steps within any workflow (reusable or caller):

```yaml
steps:
- uses: defguard/ci-workflows/actions/alert@v1
- uses: defguard/ci-workflows/actions/alert@v1.0.0
with:
alert-key: rehearsal-dev
title: "Rehearsal failed on dev"
labels: release-blocker
github-token: ${{ secrets.GITHUB_TOKEN }}
matrix-webhook: ${{ secrets.MATRIX_WEBHOOK }}
```

## Versioning
## Parity rule

This repo uses a **moving major tag** convention:
**Any change to a release build path must land in this repo first.**

- `v1` always points to the latest stable release on the v1 line
- `v1.x.x` tags pin a specific release
- Product repos pin `@v1`; the tag is moved deliberately after review
A PR touching a product repo's release caller workflow (beyond a ref bump) is a red flag - the shared workflow here must be updated instead. The weekly release rehearsal exercises the shared workflow automatically. Rehearsal and release must call the same underlying jobs, so divergence between what is rehearsed and what actually ships is impossible.

To advance `v1` to a new commit after a reviewed change:
## Repo layout

```sh
git tag -a v1.x.x -m "v1.x.x"
git tag -f v1
git push origin v1.x.x
git push origin v1 --force
```

Breaking changes require a new major tag (`v2`) and a migration guide before the old major tag is retired.

## Parity rule

**Any change to a release build path must land in this repo first.**

A PR touching a product repo's release caller workflow is a red flag - update the shared workflow here instead, so the weekly release rehearsal exercises the change automatically. Rehearsal and release must call the same underlying jobs.
ci-workflows/
.github/
workflows/ # Reusable workflow_call workflows
actions/ # Composite actions
renovate/ # Shared Renovate preset (default.json)
README.md
```

## Contents

| Path | Type | Purpose |
|------|------|---------|
| `.github/workflows/lint.yml` | CI workflow | actionlint + shellcheck on every PR to this repo |
| `.github/workflows/hello-world.yml` | Reusable workflow | Caller-pattern probe (temporary; replaced by real workflows as they are added) |

More workflows and composite actions will be added here as the release-process smoothing initiative progresses.
| `.github/workflows/hello-world.yml` | Reusable workflow | Minimal `workflow_call` probe for cross-repo caller validation |
| `actions/` | Composite actions | Shared actions for alerting, readiness checks, etc. (populated by subsequent tickets) |
| `renovate/default.json` | Renovate preset | Shared config extended by all product repos |

## Developing

Expand Down
Empty file added actions/.gitkeep
Empty file.