CI workflows¶
GitHub Actions in .github/workflows/ build images, gate
pull requests and publish the README cards and the docs site. None of them touch the
cluster or run terraform plan: images reach the cluster through Kargo
(kargo.md) and manifests through Argo CD (argocd.md).
Workflows¶
| Workflow | Trigger | Does | Writes |
|---|---|---|---|
build-portfolio.yaml |
push to main under portfolio/, manual |
lint and typecheck, then Docker build of portfolio/ with the live deployment.yaml copied in |
ghcr.io/mortennordbye/homelab/portfolio:<short-sha> and :0.0.<run> |
build-blog.yaml |
push to main under blog/, manual |
markdownlint, then Docker build of blog/ with the theme submodule |
ghcr.io/mortennordbye/homelab/blog:<short-sha> and :0.0.<run> |
ci-portfolio.yaml |
PR under portfolio/ |
lint, typecheck, npm run build |
nothing |
ci-blog.yaml |
PR under blog/ |
markdownlint, Docker build as a render check | nothing |
ci-terraform.yaml |
PR and push under terraform/ |
terraform fmt -check, then init -backend=false and validate in every root it finds |
nothing |
container-vulnerability-scan.yaml |
PR and push changing either Dockerfile, Sundays 00:00 UTC, manual | builds both images and scans them with Trivy (CRITICAL and HIGH, fixed only) | SARIF to the Security tab |
dependency-review.yml |
every PR | fails on a new dependency with a high severity advisory | nothing |
scorecard.yml |
push to main, Mondays 03:00 UTC, manual |
OpenSSF Scorecard | SARIF to the Security tab, published Scorecard result |
docs.yaml |
PR and push under docs/, properdocs.yml, overrides/, scripts/docs_site_hooks.py, manual |
properdocs build --strict |
GitHub Pages (docs.nordbye.it), not on PRs |
render-diagram.yaml |
push to main changing docs/assets/diagrams/*.d2, manual |
renders each D2 file to SVG, then PNG | commit to main |
render-logo.yaml |
push to main changing docs/assets/logo/source.jpg, manual |
crops the photo to a 512 px round PNG | commit to main |
kargo-automerge.yaml |
PR opened, labelled or reopened on a kargo/promotion/* branch |
squash-merges the PR if its app/<name> label is in KARGO_AUTOMERGE_APPS |
merge into main |
indexnow.yaml |
push to main changing the portfolio or blog prod kustomization.yaml, manual |
waits for the key file to be live, then submits the sitemap URLs to IndexNow | nothing in the repo |
lighthouse.yaml |
Mondays 06:00 UTC, manual | Lighthouse CI, 3 runs each on nordbye.it and blog.nordbye.it |
lighthouse.json to the lighthouse-data branch, reports to Lighthouse temporary public storage |
star-history.yaml |
every 6 hours at :40, manual | reads stargazer timestamps over GraphQL and renders the chart with scripts/render-star-history.mjs |
stars-data branch |
status-card.yaml |
every 15 minutes, manual | reads https://nordbye.it/api/v1/infra and renders the cluster card with scripts/render-status-card.mjs |
status-data branch |
reminders.yml |
16:00 UTC on the 1st, 8th and 15th, manual | posts the Kubernetes, backup or server upkeep reminder to Discord | nothing in the repo |
What writes to the repo¶
Three workflows change main. render-diagram and render-logo commit as
GitHub Actions straight to main and only when the output changed.
kargo-automerge merges Kargo's promotion PRs. lighthouse, star-history and
status-card force-push a single commit to their own data branch
(keep_history: false). This repo's README embeds the star history and status cards
from stars-data and status-data over raw.githubusercontent.com; lighthouse.json
feeds the Lighthouse card on the GitHub profile README.
The build workflows only push images. The tag in the manifests is written by Kargo,
and the 0.0.<run> tag is what its Warehouses select.
Conventions¶
Every action is pinned to a commit SHA with the version in a comment. Workflows default
to permissions: contents: read (kargo-automerge and reminders to none) and widen per
job. Most jobs that push, publish or call external services check
github.repository_owner == 'mortennordbye' so forks skip them; lighthouse,
star-history and the docs deploy do not, and kargo-automerge instead requires the PR
branch to come from this repo.
Builds, renders, docs, IndexNow and automerge queue and never cancel a run in progress, so nothing is killed between building and pushing. PR checks, scans and the data-branch jobs cancel the superseded run.
ci-terraform holds no credentials: init runs with -backend=false, so it never
reads state. Plans and applies stay local.
Secrets¶
| Secret or variable | Used by |
|---|---|
GITHUB_TOKEN |
GHCR push, data branches, Pages, automerge, star history |
DOCKERHUB_USERNAME, DOCKERHUB_TOKEN |
build workflows, Docker Hub login before the build |
BW_ACCESS_TOKEN |
reminders.yml, reads the Discord webhook from Bitwarden |
KARGO_AUTOMERGE_APPS (variable) |
kargo-automerge.yaml, comma separated app names |
The IndexNow keys in indexnow.yaml are public by design: the endpoint verifies a
submission by fetching the same key from the site.