Projects

Client project · Normies & ChainGPT

Reusable GitHub Actions Deploy Platform

One pipeline for every service — security gated, health-checked, auto-rollback, and notified.

workflow_call

one suite: build, scan, GitOps, gate, notify

Config only

onboarding for a new app

OIDC

no static AWS keys

Auto-rollback

on a failed health gate

Overview

I built a central deploy platform as reusable GitHub Actions (workflow_call). Application repos do not own pipeline logic. They call versioned templates and pass a small config blob.

Stages are on by default and individually toggleable. Secrets can live in GitHub or in one AWS Secrets Manager JSON loaded over OIDC — no long-lived cloud keys in repos. Pushing a tag is not “deployed.” The gate treats the cluster as the source of truth. A successful rollback still fails the workflow. CI stays red until a healthy gate run — by design.

The problem

Each repo invented its own Actions. A new service meant another 200-line deploy.yml and another way to fail in production.

  • Different build, tag, and push conventions
  • Security scans missing or copy-pasted badly
  • Green CI meant the image pushed, not that the cluster was healthy
  • Bad releases stayed live until someone noticed
  • Alerts were ad hoc or silent
  • Tokens and AWS keys scattered across repo secrets

The solution

One template branch, many callers. An app repo keeps a thin deploy.yml. The only thing you edit per service is pipeline config — environment, registry, GitOps path, Argo app, workload, which stages to run. Downstream jobs read that context and can matrix over multiple images in one repo.

Config

One dict → context plus a service matrix

Tag

Short SHA image tag

Build

Registry login via OIDC, BuildKit cache, optional build secrets

Trivy

Image CVE scan; artifacts and counts; optional fail-on-critical

Semgrep

SAST on the repo as a separate reusable workflow

GitOps

Bump image in the infra repo — Kustomize or plain image:

Health

Argo sync/wait, kubectl audit, crash and log checks, then stabilize

Rollback

kubectl rollout undo and pause auto-sync when the gate fails

Notify

GitHub job summary plus a pass/fail chat message with the failing stage

Architecture

pipeline.txt

App repo (config only)
        │
        ▼
Reusable templates
  1. Generate tag
  2. Build + push (OIDC)
  3. Trivy / Semgrep
  4. Update GitOps
  5. Health gate (Argo + kubectl)
        ├── healthy   → summary + notify
        └── unhealthy → rollout undo → notify

What I implemented

  • Versioned reusable workflows on a dedicated templates ref
  • Config-driven caller pattern and an example deploy file teams copy
  • Composite action to load CI secrets from AWS Secrets Manager over OIDC — flatten JSON to env at the boundary; jq will not dump KEY=value if a field is not a string
  • Trivy and Semgrep reusable scans with artifacts
  • GitOps updater — Kustomize newName/newTag or a raw image field
  • Production-default health gate: sync, wait, Degraded detection, log regex, kubectl audit
  • Fail fast if children go Degraded while the Deployment is still Progressing; post-deploy wait then re-check so “Healthy, then crash 3 seconds later” still fails
  • Auto-rollback via rollout undo plus Argo sync-policy pause so git does not immediately re-apply the bad image; the next good deploy re-enables automated sync
  • Deployment summary and chat notify with retries; missing chat secrets do not fail CI
  • Self-hosted runner path so the gate can reach the mesh and Argo API without leaking credentials to random hosted VMs

Before / after

Before

  • Copy-paste deploy.yml per repo
  • CI green = image exists
  • No standard rollback
  • Keys in every repo
  • Silent or inconsistent alerts

After

  • Call versioned templates + a config dict
  • CI green = cluster healthy (and stable)
  • Auto rollout undo + pause sync
  • OIDC + one Secrets Manager secret
  • Summary + chat with the failing stage

Results

  • New service = config, not a new pipeline
  • Same security bar on every deploy: OIDC, scan, scoped tokens
  • Failed rollouts revert themselves; git does not keep applying a bad tag
  • On-call sees pass/fail in chat with the failing stage, not a silent red check
  • One place to improve CI — fix the template, every caller inherits it

Stack

GitHub ActionsOIDCECRTrivySemgrepArgo CDkubectlAWS Secrets ManagerKustomize

Have a project in mind? Let's build something together.