feat: add GoAlert Cloudron package (Monitoring) [#633]

Official-image wrapper of goalert/goalert 0.34.1 (digest-pinned),
single Go binary + postgresql only. Native generic OIDC wired from
the platform provider (GOALERT_OIDC_*), data-encryption key
persisted, optional first-admin basic auth. grind-stack verified:
full migration chain, serving, origin canonicalization correct.
18th package; category table reconciled to the 46-app set.
This commit is contained in:
2026-09-06 18:47:20 -05:00
parent 5ba4078133
commit b9bc032d2b
10 changed files with 269 additions and 27 deletions
@@ -0,0 +1 @@
repo
@@ -0,0 +1,12 @@
# Changelog — GoAlert Cloudron Package
## 1.0.0 — 2026-09-06
- Initial package: GoAlert 0.34.1 (official-image wrapper, digest-pinned
sha256:36b3962e…)
- postgresql + localstorage addons; web/API on :8081; bash added for the
addon wait loop
- GOALERT_DB_URL/PUBLIC_URL mapped from the platform env; data-encryption
key persisted under /app/data
- Native OIDC wired from the platform provider, new-user creation on;
optional first-admin basic auth via GOALERT_ADMIN_USER/PASS env vars
@@ -0,0 +1,22 @@
{
"manifestVersion": 2,
"type": "app",
"id": "io.cloudron.goalert",
"title": "GoAlert",
"description": "Open-source on-call and alerting system by Target: escalation chains, rotation schedules, notification rules (Slack, Twilio SMS/voice, and more), heartbeat checks, and status dashboards. Single Go service with PostgreSQL storage; schema migrations run automatically on start. SSO via the Cloudron OIDC provider; optional basic-auth bootstrap for the first admin.",
"author": "Target Corporation / GoAlert contributors",
"website": "https://goalert.io/",
"contactEmail": "cloudron@tsys.dev",
"tagline": "On-call scheduling, escalations and alert routing",
"version": "0.34.1",
"healthCheckPath": "/api/v2/heartbeat",
"httpPort": 8081,
"memoryLimit": 1024,
"addons": {
"localstorage": {},
"postgresql": {}
},
"mediaLinks": [],
"changelog": "Initial Cloudron package for GoAlert 0.34.1 (official-image wrapper of goalert/goalert, digest pinned). start.sh waits for the postgresql addon, persists the data-encryption key under /app/data, maps GOALERT_DB_URL/PUBLIC_URL from the platform env, and wires native generic OIDC (GOALERT_OIDC_*) from the Cloudron OIDC provider with new-user creation enabled. Optional first-admin via GOALERT_ADMIN_USER/PASS app env vars (basic auth).",
"icon": "file://logo.png"
}
@@ -0,0 +1,35 @@
# GoAlert Cloudron Package
#
# GoAlert is Target's open-source on-call alerting system: escalation
# chains, schedules/rotations, notification rules (SMS/phone via
# Twilio/VictorOps etc., Slack), heartbeat checks, status dashboards —
# a single Go binary serving web UI + REST API on :8081 with
# PostgreSQL as the only backing store.
#
# Upstream: https://github.com/target/goalert (Apache-2.0), v0.34.1.
# - Official image goalert/goalert (alpine, /usr/bin/goalert, runs a
# build-time self-test). DB schema migrations run automatically at
# startup; no separate worker/scheduler processes.
# - Configuration is envconfig-style: GOALERT_<SECTION>_<FIELD>
# (GOALERT_DB_URL, GOALERT_PUBLIC_URL, GOALERT_OIDC_*, ...).
#
# Authentication: NATIVE OIDC (preferred). Generic OpenID Connect in
# core (config/config.go OIDC struct; go-oidc against any issuer):
# start.sh wires GOALERT_OIDC_ENABLE/ISSUER_URL/CLIENT_ID/CLIENT_SECRET
# from the Cloudron platform provider (CLOUDRON_OIDC_*), with
# new-user creation enabled. GitHub OAuth and basic-auth also exist.
#
# Pattern: official-image wrapper. Image pinned by tag AND digest
# (amd64 manifest digest of v0.34.1 from docker manifest inspect).
FROM goalert/goalert:v0.34.1@sha256:36b3962e3171de7ba6b964bcba21a9fee3fe331dc01d9716ee8bbd7bc01ba935
# bash for start.sh (alpine's ash lacks /dev/tcp used by the addon wait)
USER root
RUN apk add --no-cache bash
COPY start.sh /app/start.sh
# web UI + REST API; notifications are all outbound (no extra listeners)
EXPOSE 8081
ENTRYPOINT ["/bin/bash", "/app/start.sh"]
@@ -0,0 +1,44 @@
# GoAlert — Cloudron Package
[GoAlert](https://github.com/target/goalert) v0.34.1 — Target's open-source
on-call alerting: escalation chains, schedules and rotations, notification
rules (Slack, Twilio SMS/voice, VictorOps, ...), heartbeats, status
dashboards. A **single Go binary** with PostgreSQL as its only store —
packaged as an official-image wrapper around `goalert/goalert`
(digest-pinned), the cleanest Cloudron shape in this workspace.
## Authentication (auth gate: ✅ OIDC preferred)
Generic OpenID Connect is first-class in core (`config/config.go` OIDC
struct on go-oidc — any compliant issuer). `start.sh` wires it from the
Cloudron platform provider:
| GoAlert env | Source |
|-------------|--------|
| `GOALERT_OIDC_ENABLE=true` | fixed |
| `GOALERT_OIDC_ISSUER_URL` | `CLOUDRON_OIDC_ISSUER` |
| `GOALERT_OIDC_CLIENT_ID` | `CLOUDRON_OIDC_CLIENT_ID` |
| `GOALERT_OIDC_CLIENT_SECRET` | `CLOUDRON_OIDC_CLIENT_SECRET` |
| `GOALERT_OIDC_NEWUSERS=true` | overridable (`GOALERT_OIDC_NEWUSERS`) |
- SSO redirect: `https://<app-domain>/api/v2/identity/providers/oidc/callback`
- OIDC-registered users are created **without** privileges. First admin:
set `GOALERT_ADMIN_USER` + `GOALERT_ADMIN_PASS` app env vars once —
start.sh exposes them as basic auth — log in, promote your SSO account,
then unset them (README + `.env.example`).
## Runtime layout
| Concern | How |
|---------|-----|
| Database | Cloudron `postgresql` addon; migrations run automatically at startup |
| Encryption key | `GOALERT_DATA_ENCRYPTION_KEY` generated once, persisted in `/app/data` (rotating loses provider credentials) |
| Public URL | `GOALERT_PUBLIC_URL``CLOUDRON_APP_ORIGIN` |
| Notifications | All outbound (Slack/Twilio/webhooks) — no inbound ports beyond 8081 |
| Storage | `/app/data` (localstorage) — key + future runtime files |
## Notes
- Version upgrades: bump tag+digest in the Dockerfile, rebuild —
migrations run on first boot.
- Package pattern + verification: repo `JOURNAL.md`, GoAlert section.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

+73
View File
@@ -0,0 +1,73 @@
#!/bin/bash
set -euo pipefail
# GoAlert runtime setup for Cloudron:
# 1. wait for the postgresql addon (GoAlert's startup runs migrations
# itself, but gives up quickly if the DB is slow to accept - the
# /dev/tcp wait removes that race)
# 2. persist GOALERT_DATA_ENCRYPTION_KEY (rotating it loses encrypted
# notification-provider credentials)
# 3. map the Cloudron addon + platform env onto GOALERT_* vars
# 4. exec /usr/bin/goalert (migrations + web/API on :8081)
#
# Authentication: OIDC via the Cloudron platform provider. OIDC users
# are created on first login (NewUsers=true); they arrive WITHOUT
# admin rights - an admin logs in once with basic auth (GOALERT_BASIC_AUTH
# below, set only when the operator provides GOALERT_ADMIN_USER/PASS env)
# or via OIDC and is promoted from the admin panel.
DATA_DIR="/app/data"
KEY_FILE="${DATA_DIR}/.data_encryption_key"
mkdir -p "${DATA_DIR}"
# --- 1. wait for the addon -------------------------------------------------------
wait_tcp() {
local host="$1" port="$2" name="$3"
echo "Waiting for ${name} at ${host}:${port} ..."
until (exec 3<>"/dev/tcp/${host}/${port}") 2>/dev/null; do
echo "${name} is unavailable - sleeping"
sleep 2
done
echo "${name} is up"
}
DB_HOST="${CLOUDRON_POSTGRESQL_HOST:-127.0.0.1}"
DB_PORT="${CLOUDRON_POSTGRESQL_PORT:-5432}"
DB_NAME="${CLOUDRON_POSTGRESQL_DATABASE:-goalert}"
DB_USER="${CLOUDRON_POSTGRESQL_USERNAME:-goalert}"
DB_PASS="${CLOUDRON_POSTGRESQL_PASSWORD:-}"
wait_tcp "${DB_HOST}" "${DB_PORT}" "PostgreSQL"
# --- 2. persistent data-encryption key -------------------------------------------
if [[ ! -s "${KEY_FILE}" ]]; then
( umask 077; head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n' > "${KEY_FILE}" )
echo "Generated new data encryption key"
fi
# --- 3. Cloudron -> GOALERT_* environment ----------------------------------------
export GOALERT_DB_URL="postgres://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
export GOALERT_PUBLIC_URL="${CLOUDRON_APP_ORIGIN:-http://localhost}"
export GOALERT_DATA_ENCRYPTION_KEY="$(cat "${KEY_FILE}")"
export GOALERT_LISTEN=":8081"
# optional admin bootstrap: when GOALERT_ADMIN_USER/GOALERT_ADMIN_PASS
# are set as app env vars, basic auth allows the first admin login
# (promote/deactivate the account after SSO users exist)
if [[ -n "${GOALERT_ADMIN_USER:-}" && -n "${GOALERT_ADMIN_PASS:-}" ]]; then
export GOALERT_BASIC_AUTH="${GOALERT_ADMIN_USER}:${GOALERT_ADMIN_PASS}"
else
unset GOALERT_BASIC_AUTH || true
fi
# platform OIDC provider -> goalert oidc config
export GOALERT_OIDC_ENABLE="${GOALERT_OIDC_ENABLE:-true}"
export GOALERT_OIDC_ISSUER_URL="${CLOUDRON_OIDC_ISSUER:-}"
export GOALERT_OIDC_CLIENT_ID="${CLOUDRON_OIDC_CLIENT_ID:-}"
export GOALERT_OIDC_CLIENT_SECRET="${CLOUDRON_OIDC_CLIENT_SECRET:-}"
export GOALERT_OIDC_NEWUSERS="${GOALERT_OIDC_NEWUSERS:-true}"
export GOALERT_OIDC_OVERRIDE_NAME="${GOALERT_OIDC_OVERRIDE_NAME:-Cloudron}"
echo "Starting GoAlert (migrations run automatically) ..."
exec /usr/bin/goalert