Reusable GitHub Actions workflows and composite actions for Flanksource projects. This repository also hosts the central Renovate control plane for the Flanksource GitHub organization.
Renovate discovers repositories through a GitHub App and creates version-update pull requests only for dependencies owned by Flanksource.
Consumer repositories do not need a renovate.json file. The global configuration disables onboarding and ignores repository-level Renovate configuration.
Dependabot remains responsible for security updates. Renovate's GitHub and OSV vulnerability-alert features are explicitly disabled here.
The hourly workflow:
- Exchanges the GitHub App ID and private key for a one-hour installation token covering every repository in the Flanksource organization installation.
- Runs Renovate with
renovate-config.js. - Discovers
flanksource/*repositories accessible to the App. - Disables every dependency by default, then enables packages whose package name or source repository belongs to Flanksource.
The package-name rules currently cover GitHub Actions, Go modules, npm packages, Docker Hub images, GHCR images, and Quay images. The source-URL rule also covers other Renovate datasources when they resolve to a repository under github.com/flanksource.
Create a GitHub App owned by the Flanksource organization. Webhooks and user authorization are not required. Configure these repository permissions, following Renovate's GitHub App guidance:
| Permission | Access |
|---|---|
| Administration | Read |
| Checks | Read and write |
| Commit statuses | Read and write |
| Contents | Read and write |
| Dependabot alerts | Read |
| Issues | Read and write |
| Metadata | Read |
| Pull requests | Read and write |
| Workflows | Read and write |
Configure Members: read under organization permissions. Install the App once on the Flanksource organization and grant it access to all repositories that Renovate should monitor.
The workflow reuses these organization secrets, which must be available to this repository:
FLANKSOURCE_APP_ID: the App's numeric App ID.FLANKSOURCE_APP_SECRET: the complete PEM private key.
The App and its credentials are managed at organization level. The workflow's owner input deliberately omits a repository list, which creates a token covering all repositories granted to that installation.
The workflow runs hourly at minute 17 and can also be started manually from the Actions tab. GitHub App installation tokens expire after one hour, so the job has a 55-minute timeout. If execution approaches that limit as the organization grows, split repository discovery across multiple jobs or narrower filters so each job gets its own token.
To add another Flanksource-owned registry or package namespace, add its pattern to the enabling rules in renovate-config.js. Changes take effect on the next run; no consumer-repository configuration or sync pull request is needed.
Workflows and actions are published as semantic versions. Use the major-version tag (for example, @v1) to receive compatible updates, or pin a full release tag (for example, @v1.0.0) for a fixed version. Do not pin to the default branch.
Free Disk Space
A composite action that reclaims the preinstalled toolchains a hosted Ubuntu runner ships with. A hosted runner leaves only ~14–21 GB free on / — which is where /var/lib/docker lives — so a multi-stage image build that also exports a mode=max layer cache can run out of space.
Derived from jlumbroso/free-disk-space (MIT), with inputs passed through env: instead of being templated into the script body, concurrent removals, free space measured on / alone, and no blanket || true.
Usage:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: flanksource/action-workflows/actions/free-disk-space@v1
- uses: actions/checkout@v4
# ... docker build ...Opt in to the slower or more destructive categories when a build needs them:
- uses: flanksource/action-workflows/actions/free-disk-space@v1
with:
docker-images: true
tool-cache: trueInputs:
| Input | Default | Removes |
|---|---|---|
android |
true |
/usr/local/lib/android (~9–12 GB) |
dotnet |
true |
/usr/share/dotnet (~1.6–2.9 GB) |
haskell |
true |
/opt/ghc, /usr/local/.ghcup (~5 GB) |
boost |
true |
/usr/local/share/boost (~1 GB) |
codeql |
true |
/opt/hostedtoolcache/CodeQL (~5 GB) |
large-packages |
false |
Large apt packages — costs 2–3 min |
docker-images |
false |
All preloaded Docker images |
tool-cache |
false |
The whole $AGENT_TOOLSDIRECTORY (~8 GB) |
swap-storage |
false |
Swap and /mnt/swapfile |
With the defaults this reclaims roughly 20–25 GB on ubuntu-latest in ~30–45 s.
What it does:
- Records available space on
/ - Removes each enabled category concurrently, failing the step if a removal genuinely errors
- Applies the opt-in apt / Docker / swap categories
- Reports space reclaimed to the log and the job summary
Notes:
- On
ubuntu-*-armrunners most of these paths do not exist.rm -rfno-ops on an absent path, so the action is safe there and simply reports a smaller delta — no architecture conditional is needed. codeqlis ignored whentool-cacheis enabled, since the tool cache already contains it.tool-cacheremoves the directorysetup-go,setup-node, and friends install into. Only enable it in a job that runs nosetup-*action.
Push Helm Chart to flanksource/charts
A reusable workflow that pushes Helm charts to the flanksource/charts repository after a Helm build.
Usage:
The calling workflow must upload the packaged .tgz chart as an artifact (default name: helm-chart) before calling this workflow.
jobs:
helm-package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ... version updates, helm package, etc.
- uses: actions/upload-artifact@v4
with:
name: helm-chart
path: "*.tgz"
push-helm-chart:
needs: helm-package
uses: flanksource/action-workflows/.github/workflows/push-helm-chart.yml@v1
with:
filename_regex: "flanksource-ui-*.tgz"
version: "1.4.180"
pr_title: "Release 1.4.180 of flanksource/flanksource-ui"
secrets:
token: ${{ secrets.FLANKBOT }}Inputs:
filename_regex(required): Pattern to match the helm chart file (e.g.,flanksource-ui-*.tgz)version(required): Chart version (e.g.,1.4.180)pr_title(required): Title for the pull request (e.g.,Release 1.4.180 of flanksource/flanksource-ui)artifact_name(optional, default:helm-chart): Name of the uploaded artifact containing the.tgzfile(s)
Secrets:
token(required): GitHub token with permissions to push to flanksource/charts repository
What it does:
- Downloads the helm chart artifact from the calling workflow
- Clones the flanksource/charts repository (gh-pages branch)
- Creates a new branch for the chart update
- Copies the helm chart file(s) matching the filename regex
- Updates the helm repository index
- Commits and pushes the changes
- Creates a pull request
- Auto-merges the pull request and deletes the branch
Create Semantic Release
Computes the next semantic version from commits using semantic-release, which respects the repo's .releaserc / release.config.*, and creates a GitHub release. Outputs the version and tag for downstream jobs. Callers can install extra plugins when their release config needs them.
Usage:
jobs:
create-release:
permissions:
contents: write
issues: write
pull-requests: write
uses: flanksource/action-workflows/.github/workflows/create-release.yml@v1
with:
extra_plugins: |
@semantic-release/git
build:
needs: create-release
if: needs.create-release.outputs.published == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ... build using needs.create-release.outputs.version ...Inputs:
extra_plugins(optional): newline-separated semantic-release plugins to install, such as@semantic-release/git.
Secrets:
token(optional): token used for checkout, git push, and GitHub release operations. Defaults to the caller'sGITHUB_TOKEN; grant the calling jobcontents: writeand any required issue or pull-request permissions. Pass a PAT or GitHub App token when the automatic token is unsuitable.
Outputs:
published:'true'whensemantic-releasedetermined a new version is due and a release was created. Always check this in dependent jobs.version: Computed semantic version without prefix (e.g.,1.2.3). Empty whenpublishedis'false'.tag: Computed git tag including any prefix (e.g.,v1.2.3). Empty whenpublishedis'false'.
What it does:
- Checks out the calling repository with full history
- Runs
semantic-releasenormally so it creates the git tag, semantic-release notes, and GitHub release
Publish Docker Image
Builds and pushes Docker images with docker/build-push-action on one builder. Optionally signs the pushed image digest using cosign keyless signing through GitHub Actions OIDC. Cosign signing is enabled by default. Use Publish Multi-Platform Docker Image below when each platform should build on a separate native runner.
Usage:
jobs:
docker:
uses: flanksource/action-workflows/.github/workflows/publish-docker-image.yml@v1
permissions:
contents: read
id-token: write
packages: write
with:
dockerfile: build/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
image_tags: |
docker.io/flanksource/config-db:v1.2.3
docker.io/flanksource/config-db:latest
ghcr.io/flanksource/config-db:v1.2.3
public.ecr.aws/k4y9r6y5/config-db:v1.2.3
login_to_ecr: true
ecr_registry_type: public
cosign: true
secrets:
docker_username: ${{ secrets.DOCKER_USERNAME }}
docker_password: ${{ secrets.DOCKER_PASSWORD }}
aws_access_key_id: ${{ secrets.ECR_AWS_ACCESS_KEY }}
aws_secret_access_key: ${{ secrets.ECR_AWS_SECRET_ACCESS_KEY }}Inputs:
image_tags(required): Newline-separated full image tags to publish.dockerfile(optional, default:Dockerfile): Path to the Dockerfile.context(optional, default:.): Docker build context.platforms(optional, default:linux/amd64): Comma-separated target platforms.build_args(optional): Newline-separated Docker build args.cosign(optional, default:true): Sign pushed image digests using cosign keyless.login_to_dockerhub(optional, default:true): Log in to Docker Hub.login_to_ecr(optional, default:false): Log in to Amazon ECR.ecr_registry_type(optional, default:public): Amazon ECR registry type:publicorprivate.aws_region(optional, default:us-east-1): AWS region used for ECR login.
Secrets:
docker_username/docker_password: Required whenlogin_to_dockerhubistrue.ghcr_username/ghcr_token: Optional forghcr.iotags. Defaults togithub.actor/GITHUB_TOKEN.aws_access_key_id/aws_secret_access_key: Required whenlogin_to_ecristrue.
Outputs:
digest: Published image digest fromdocker/build-push-action.
What it does:
- Hardens the runner with
step-security/harden-runnerin audit mode - Frees disk space on the hosted runner
- Checks out the calling repository
- Logs in to Docker Hub and/or Amazon ECR as requested, and logs in to GHCR when
ghcr.iotags are present - Builds and pushes the configured image tags
- Installs cosign when
cosignis enabled - Signs each unique image repository by digest, e.g.
repo/image@sha256:...
Publish Multi-Platform Docker Image
Builds each target platform independently on a matching native GitHub-hosted runner. Platform images are pushed by digest, then a final job creates and signs the tagged multi-platform image indexes. Tags are not published until every platform build succeeds.
Use this workflow for native linux/amd64 and linux/arm64 builds. Use Publish Docker Image when a single multi-platform builder such as Docker Build Cloud should own the complete build.
Usage:
jobs:
docker:
uses: flanksource/action-workflows/.github/workflows/publish-multi-platform-docker-image.yml@v1
permissions:
contents: read
id-token: write
packages: write
with:
dockerfile: build/Dockerfile
image_tags: |
docker.io/flanksource/config-db:v1.2.3
docker.io/flanksource/config-db:latest
public.ecr.aws/k4y9r6y5/config-db:v1.2.3
login_to_ecr: true
ecr_registry_type: public
secrets:
docker_username: ${{ secrets.DOCKER_USERNAME }}
docker_password: ${{ secrets.DOCKER_PASSWORD }}
aws_access_key_id: ${{ secrets.ECR_AWS_ACCESS_KEY }}
aws_secret_access_key: ${{ secrets.ECR_AWS_SECRET_ACCESS_KEY }}Inputs:
image_tags(required): Newline-separated full image tags to publish. Every value must include an explicit tag.dockerfile(optional, default:Dockerfile): Path to the Dockerfile.context(optional, default:.): Docker build context.platforms(optional, default:linux/amd64,linux/arm64): Comma-separated platforms. Supported values arelinux/amd64andlinux/arm64.amd64_runner(optional, default:ubuntu-latest): Runner used forlinux/amd64.arm64_runner(optional, default:ubuntu-24.04-arm): Runner used forlinux/arm64.build_args(optional): Newline-separated Docker build args.cache(optional, default:true): Enable architecture-scoped GitHub Actions caches.cache_mode(optional, default:min): BuildKit cache export mode, eitherminormax.cache_scope(optional): Base cache scope. By default it is derived from the first image repository; the architecture is always appended.cosign(optional, default:true): Sign each published image index using cosign keyless.login_to_dockerhub(optional, default:true): Log in to Docker Hub.login_to_ecr(optional, default:false): Log in to Amazon ECR.ecr_registry_type(optional, default:public): Amazon ECR registry type:publicorprivate.aws_region(optional, default:us-east-1): AWS region used for ECR login.
Secrets:
docker_username/docker_password: Required whenlogin_to_dockerhubistrue.ghcr_username/ghcr_token: Optional forghcr.iotags. Defaults togithub.actor/GITHUB_TOKEN.aws_access_key_id/aws_secret_access_key: Required whenlogin_to_ecristrue.token: Optional GitHub token exposed to the Docker build as theGITHUB_TOKENBuildKit secret.
Outputs:
digest: Published multi-platform digest for the first image repository.
What it does:
- Validates the requested platforms and image tags
- Maps
linux/amd64toubuntu-latestandlinux/arm64toubuntu-24.04-armby default - Builds each platform in parallel without QEMU and pushes it by digest to every requested registry
- Stores BuildKit caches in separate architecture-specific scopes
- Downloads the platform digests only after every build succeeds
- Creates each repository's tagged multi-platform image index
- Signs each repository-specific image index digest using cosign keyless
Publish Draft Release
Flips an existing draft release to published at the end of a build pipeline once all artifacts have been uploaded.
Usage:
jobs:
publish:
needs: [create-release, build]
uses: flanksource/action-workflows/.github/workflows/publish-release.yml@v1
with:
tag: ${{ needs.create-release.outputs.tag }}
secrets:
token: ${{ secrets.FLANKBOT }}Inputs:
tag(required): Git tag of the draft release to publish (e.g.,v1.2.3).
Secrets:
token(required): token used to publish the draft GitHub release.
What it does:
- Runs
gh release edit <tag> --draft=falseagainst the calling repository, which publishes the release and creates the underlying git tag.