CI/CD Publishing

The self-hosted GitLab is the everyday forge and the source of truth - normal development only ever pushes there. GitHub is not a mirror: only a hand-picked few showpiece repos are ever published outward, and only by a deliberate manual step. The job here is to publish those selected repos to public GitHub without leaking the internal domain, secrets, or git history, and without giving untrusted CI jobs a path to the internet. This is the most deliberate piece of engineering in the lab, so it gets the most detail.

Why this exists

I make mistakes, and I lean on AI heavily - so the design assumption is that something will slip through. The goal was never a perfect gate; it is a small blast radius for when one does. Everything here verifies locally, fails closed, and keeps the damage contained and auditable.

It lives on my own GitLab rather than straight on GitHub for two reasons:

At a glance

DevSecOps · DNS-gapped CI, gate before publish
cat .gitlab-ci.yml
# tags: [internal] -> gitlab-runner (DNS-gapped, no internet) # tags: [external] -> gitlab-runner-external (has DNS) - publish only stages: [check, publish] sanitisation-gate: stage: check tags: [internal] script: sh scripts/sanitisation-gate.sh .sanitisation-patterns publish-to-github: stage: publish tags: [external] when: manual
# nothing can leave the network until the sanitisation gate passes on the isolated runner

Full mechanics - the two runners up close, the pipeline, the sanitisation gate and the gotcha that waved a bad repo through, squash-publish, and how to recreate it →