postern
postern routes events from cloud storage and message systems to GitLab pipeline triggers. An event arrives, pushed over HTTP or pulled from a queue or topic; postern matches it against YAML routes, pulls the fields a route asks for out of the payload, and calls a GitLab project’s trigger API with them as CI variables. The pipeline stays in that project’s .gitlab-ci.yml. It is the receiving hop of a one-way transfer, the pattern the diode exhibit in exhibits carries end to end.
- Push adapters (Event Grid, Pub/Sub, CloudEvents) mount an HTTP handler and check the caller by shared secret, Google-signed OIDC token or bearer token; pull adapters (SQS, Kafka) loop on their own protocol.
- Every adapter implements one
Run(ctx, emit)method and emits CloudEvents 1.0, so nothing past it knows a vendor’s shape. - A ring buffer keyed on event id drops duplicates, sized in config and empty after a restart.
- Matched jobs enter a bounded queue in front of a worker pool that POSTs to the trigger API with retries.
- A full queue answers 503 to a push and leaves a pulled message in place, so backpressure reaches the producer instead of dropping an event.
A route is the whole of the logic between event and trigger.
- Match is on event type, exact or prefix wildcard, optionally a substring of the source.
- Variables are envelope shortcuts (
id,subject,time) or gjson dot-paths into the payload,@modifiers refused. - The trigger token is named by environment variable and never reaches the config, the logs or the status endpoint.
- Every config opens with
version: 1, required rather than defaulted, so an unknown format fails at startup instead of half-parsing.
postern ships as a container:
- a static Go binary on a UBI micro base pinned by digest, non-root, signed keyless with cosign through GitLab’s OIDC;
/livez,/readyz,/status,/metricsfor in-cluster probes and Prometheus;SIGHUPreloads routes and dedup capacity; a source change needs a restart;- a Helm chart in
chart/.
postern covers the hop between an event and a pipeline trigger and nothing further: no database, no logic on the cloud side, and no state that outlives a restart.