From 1bf98100716d277c11f441ca6a13f75296f5581e Mon Sep 17 00:00:00 2001 From: reachableceo Date: Sun, 6 Sep 2026 18:23:54 -0500 Subject: [PATCH] fix(consuldemocracy): verify end-to-end + harden seed/OIDC [#653] Seed verification over marker trust (observed exit-0 no-op seed), first-boot-only OIDC auto-enable, logo added, docs synced (JOURNAL s17, counts 17/~57). grind-stack verified: homepage 200, OIDC SSO button live. Detail: https://projects.knownelement.com/issues/653#note-5044 --- JOURNAL.md | 63 ++++++++++++++++++ .../consuldemocracy/CHANGELOG.md | 16 ++++- .../Collaboration/consuldemocracy/README.md | 3 + .../Collaboration/consuldemocracy/logo.png | Bin 0 -> 12470 bytes .../Collaboration/consuldemocracy/start.sh | 23 ++++++- README.md | 5 +- STATUS.md | 17 ++--- 7 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 Package-Workspace/Collaboration/consuldemocracy/logo.png diff --git a/JOURNAL.md b/JOURNAL.md index 15d875e..03ea6a2 100644 --- a/JOURNAL.md +++ b/JOURNAL.md @@ -1304,6 +1304,69 @@ terminal); SSO users register WITHOUT privileges. --- +### 17. ConsulDemocracy (Collaboration) ✅ +**Date**: 2026-09-06 +**Application**: ConsulDemocracy — citizen participation platform behind +Madrid's Consul (proposals, participatory budgeting, debates, polls, +collaborative legislation). Upstream: +https://github.com/consuldemocracy/consuldemocracy (MIT). Rails 8 + +PostgreSQL + delayed_job + memcached. First package verified through the +grind lifecycle (`scripts/grind-stack.sh`) end to end. + +**Ticket**: [#653](https://projects.knownelement.com/issues/653) + +**Pattern**: build-from-source on ruby:3.4.10-trixie, trimmed from the +upstream dev Dockerfile (Chromium/E2E and sudo dropped, fixed non-root +uid 1000). No published upstream image exists. + +**Auth gate verdict**: ✅ OIDC preferred. Generic OpenID Connect via +`omniauth_openid_connect` (devise.rb:289-296, discovery: true), secrets +contract `oidc_client_id/secret/issuer` in config/secrets.yml — wired +from `CLOUDRON_OIDC_*` by start.sh. SAML also available. + +**Key decisions / lessons (four build-breaking gotchas, all fixed)**: + +1. **`ruby file: ".ruby-version"`**: the Gemfile resolves its ruby + version from `.ruby-version` BY NAME — copying it under a different + name kills `bundle install` with a bare backtrace. +2. **`eval_gemfile "./Gemfile_custom"`**: the Gemfile expects a + developer-local `Gemfile_custom` that isn't in git — `touch` an empty + one before `bundle install`. +3. **assets:precompile cannot run at build time**: this app's Rails + environment touches the DB (apartment), so precompile moved to + start.sh after the postgres wait (idempotent; slow only first boot). + Related: Rails 8's `regexp_timeout` default killed the graphiql + minified-JS regexes under CPU contention — disabled via a baked + initializer (`Regexp.timeout = nil`). +4. **Named-volume ownership**: a fresh docker volume is root-owned while + the container runs as uid 1000 — declare `VOLUME /app/data` AFTER + `chown` in the Dockerfile so volume initialization inherits the + right owner (Cloudron chowns its own mounts, but the grind stack and + any plain docker run need this). +5. **Seed verification over marker trust**: one boot observed + `db:create db:migrate db:seed` exit 0 while persisting nothing; a + standalone re-seed landed fine. start.sh now checks `Setting.count` + and re-seeds an empty database regardless of the marker file. +6. **`feature.oidc_login` defaults to false** upstream — start.sh + enables it ONCE on first boot when platform OIDC vars are present; + operators can toggle it afterwards in Admin → Settings → Features. + +**Verification** (grind-stack, ephemeral postgres): build green; first +boot ~5 min — migrate → seed (123 settings + admin@consul.dev) → OIDC +enable → precompile → gated delayed_job worker → Rails on :3000; +homepage 200; login page renders the `/users/auth/oidc` SSO button. + +**Files Created**: Dockerfile, CloudronManifest.json (port 3000, +localstorage + postgresql, 2048MB), start.sh (config generation, seed +verify, memcached, worker gate), README.md, CHANGELOG.md, +.dockerignore (repo/.git only — the source IS the build context), +logo.png (upstream public/consul_logo.png). + +**Commit**: `feat(consuldemocracy): add initial Cloudron package` (7c65dc1, +landed mid-flight) + verification hardening follow-up + +--- + ## Packaging Pattern: Download Pre-Compiled Binaries ### When to Use diff --git a/Package-Workspace/Collaboration/consuldemocracy/CHANGELOG.md b/Package-Workspace/Collaboration/consuldemocracy/CHANGELOG.md index 3d306d6..9f38d7d 100644 --- a/Package-Workspace/Collaboration/consuldemocracy/CHANGELOG.md +++ b/Package-Workspace/Collaboration/consuldemocracy/CHANGELOG.md @@ -7,7 +7,17 @@ - postgresql + localstorage addons; Rails server on :3000 - Generated configs (database.yml / secrets.yml) under /app/data, regenerated each boot; persisted secret_key_base -- First-boot db:create/migrate/seed with marker; gated delayed_job - worker; in-container memcached -- Platform OIDC wired into secrets.yml; local admin seeded +- First-boot db:create/migrate/seed with marker + empty-DB verification + (a stale marker against a fresh database re-seeds); gated delayed_job + worker; in-container memcached; assets:precompile at start (the app's + environment needs the DB, so precompile cannot run at build time) +- Platform OIDC wired into secrets.yml; `feature.oidc_login` auto-enabled + on first boot when the provider is present; local admin seeded (admin@consul.dev — password change required on first login) + +## Verification (2026-09-06) + +Full-stack grind-stack test against ephemeral postgres: build green, +first boot ~5 min (migrate → seed [123 settings, admin] → OIDC enable → +precompile → delayed_job → Rails), homepage 200, login page renders the +`/users/auth/oidc` SSO button. diff --git a/Package-Workspace/Collaboration/consuldemocracy/README.md b/Package-Workspace/Collaboration/consuldemocracy/README.md index 5cdfb87..862f11f 100644 --- a/Package-Workspace/Collaboration/consuldemocracy/README.md +++ b/Package-Workspace/Collaboration/consuldemocracy/README.md @@ -18,6 +18,9 @@ regenerates secrets.yml on every boot with the Cloudron platform provider values (`CLOUDRON_OIDC_*`). - SSO redirect: `https:///users/auth/oidc/callback` +- The SSO button (`feature.oidc_login`, default off upstream) is + auto-enabled on FIRST boot when the platform provider is present — + after that it's yours to toggle in Admin → Settings → Features. - Local login stays available alongside SSO. - SAML is also supported (saml_* keys in secrets.yml) if an external IdP is preferred. diff --git a/Package-Workspace/Collaboration/consuldemocracy/logo.png b/Package-Workspace/Collaboration/consuldemocracy/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0261d8c9924af420dbc10956423f81e3550ac374 GIT binary patch literal 12470 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 literal 0 HcmV?d00001 diff --git a/Package-Workspace/Collaboration/consuldemocracy/start.sh b/Package-Workspace/Collaboration/consuldemocracy/start.sh index 9c38c55..d27021a 100755 --- a/Package-Workspace/Collaboration/consuldemocracy/start.sh +++ b/Package-Workspace/Collaboration/consuldemocracy/start.sh @@ -97,11 +97,30 @@ memcached -d -p 11211 -u consul -m 64 # --- 3. database lifecycle ------------------------------------------------------- wait_tcp "${DB_HOST}" "${DB_PORT}" "PostgreSQL" -if [[ ! -f "${MARKER}" ]]; then - echo "First boot: creating + migrating + seeding the database ..." +# seed decision: the marker alone is not trusted - a marker left by a +# previous database (restore, migration, fresh test DB) must not skip +# seeding an empty one (observed: seed chain exits 0 yet persists +# nothing when re-run in the same first-boot process; a standalone +# re-seed lands fine, so verify + retry instead of debugging ghosts) +SEED_COUNT="$(bundle exec rails runner 'print Setting.count' 2>/dev/null || echo 0)" +if [[ ! -f "${MARKER}" || "${SEED_COUNT}" = "0" ]]; then + echo "First boot (or empty database): creating + migrating + seeding ..." bundle exec rails db:create db:migrate db:seed + SEED_COUNT="$(bundle exec rails runner 'print Setting.count' 2>/dev/null || echo 0)" + if [[ "${SEED_COUNT}" = "0" ]]; then + echo "seed pass 1 did not persist - retrying standalone seed" + bundle exec rails db:seed + fi touch "${MARKER}" echo "Database seeded (local admin: admin@consul.dev - change the password!)" + + # first-boot only: expose the SSO button when the platform provider is + # wired (feature.oidc_login defaults to false; operators can toggle it + # later in Admin > Settings > Features without us re-enabling it) + if [[ -n "${CLOUDRON_OIDC_CLIENT_ID:-}" ]]; then + bundle exec rails runner 'Setting["feature.oidc_login"] = true' || true + echo "OIDC login enabled (admin panel can toggle it)" + fi else bundle exec rails db:migrate fi diff --git a/README.md b/README.md index 8dde7e4..92e76cd 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ The Cloudron component focuses on packaging upstream free/libre/open application ### 📊 Current Progress - **Total Applications**: ~57 (see [GitUrlList.txt](GitUrlList.txt)) -- **Completed Packages**: 16/~57 (~28%) +- **Completed Packages**: 17/~57 (~30%) - **Packaging Templates**: Created ✅ -- **Packages Committed & Pushed**: 16 ✅ +- **Packages Committed & Pushed**: 17 ✅ - **Build Tickets**: 46 filed (#633-#678, umbrella [#632](https://projects.knownelement.com/issues/632), Redmine project 55); grist-core excluded (packaged upstream) @@ -38,6 +38,7 @@ The Cloudron component focuses on packaging upstream free/libre/open application | 14 | ChirpStack | Infrastructure | 83.4MB | 8080 | localstorage, postgresql, redis | ✅ Committed | | 15 | eLabFTW | Business-Apps | ~209MB (compressed) | 443 | localstorage, mysql, ldap | ✅ Committed | | 16 | NetBox | Infrastructure | ~1GB | 8080 | localstorage, postgresql, redis | ✅ Committed | +| 17 | ConsulDemocracy | Collaboration | ~1.6GB | 3000 | localstorage, postgresql | ✅ Committed | ### 📦 Packages in Development diff --git a/STATUS.md b/STATUS.md index 72aae0d..a60b229 100644 --- a/STATUS.md +++ b/STATUS.md @@ -3,7 +3,7 @@ > **Human read-only. Agents maintain this file automatically after each work > session.** Do not edit by hand — the next agent run will overwrite it. > -> **Last updated:** 2026-09-06 by ZCode (GLM-5.3) — NetBox packaged +> **Last updated:** 2026-09-06 by ZCode (GLM-5.3) — ConsulDemocracy packaged (17th; verified via grind lifecycle) > (#648, Infrastructure, 16th package); auth gate verdict: native OIDC via > python-social-auth (OpenIdConnectAuth + SOCIAL_AUTH_OIDC_*) wired to the > platform provider; official-image wrapper of netboxcommunity/netbox @@ -13,14 +13,14 @@ ## Current State: STABLE (packaging phase, ongoing) -Cloudron packaging pipeline is operational. 16 of ~57 upstream applications are +Cloudron packaging pipeline is operational. 17 of ~57 upstream applications are packaged, committed, and pushed. Packaging templates exist for the core patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync. All remaining apps now carry build tickets (#633-#678) under umbrella [#632](https://projects.knownelement.com/issues/632) in Redmine project 55 — ready for the sequential grind-driver pattern. -## Completed Packages (16) +## Completed Packages (17) | # | Application | Category | Pattern | Port(s) | Addons | |---|-------------|----------|---------|---------|--------| @@ -45,7 +45,7 @@ Each package lives in `Package-Workspace///` and contains a `Dockerfile`, `CloudronManifest.json`, `README.md`, `CHANGELOG.md`, `logo.png`, and (where relevant) `start.sh` + `.env.example`. -## Build Ticket Map (46 filed 2026-09-01; 39 open — 7 landed: #639, #640, #648, #650, #651, #668, #669) +## Build Ticket Map (46 filed 2026-09-01; 38 open — 8 landed: #639, #640, #648, #650, #651, #653, #668, #669) All under umbrella [#632](https://projects.knownelement.com/issues/632) (Redmine project 55, tracker Feature). Excluded: **grist-core** (a Cloudron @@ -68,12 +68,12 @@ package already exists upstream — do not package). | #645 | OpenBoxes | Business-Apps | needs LDAP runtime verification (note 2026-09-06) | | #646 | Nautilus Trader | Financial-Trading | disposition (headless lib) | | #647 | Fleet | Monitoring | build (research queue) | -| #648 | NetBox | Infrastructure | build (redis addon; strong candidate) | +| #648 | NetBox | Infrastructure | DONE 2026-09-06 (16th package) | | #649 | SeaTunnel | Data-Management | disposition (service vs tool) | | #650 | Rathole | Infrastructure | build (proxy) | | #651 | Easy-Gate | Infrastructure | build (proxy) | | #652 | Huginn | Automation | blocked-on-auth (local-only Devise; note 2026-09-06) | -| #653 | ConsulDemocracy | Collaboration | build | +| #653 | ConsulDemocracy | Collaboration | DONE 2026-09-06 (17th, grind-verified) | | #654 | BOINC | Scientific-Computing | disposition (server packaging heavy) | | #655 | Slurm | System-Administration | disposition (likely out of scope) | | #656 | Gophish | Security | blocked-on-auth | @@ -122,7 +122,7 @@ Full write-ups of each pattern + challenges are in [`JOURNAL.md`](JOURNAL.md). | Monitoring | 6 | 1/6 | healthchecks done | | Automation | 4 | 1/4 | windmill done | | Business-Apps | 8 | 1/8 | elabftw done | -| Collaboration | 2 | 0/2 | | +| Collaboration | 2 | 1/2 | consuldemocracy done | | Communication | 1 | 0/1 | | | Data-Management | 2 | 0/2 | | | DevOps-Tools | 1 | 1/1 (100%) ✅ | fx done | @@ -142,7 +142,7 @@ Auth capability is a hard gate before packaging (see LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only (unacceptable / blocked-on-auth). -### Completed packages (16) +### Completed packages (17) | App | OIDC | LDAP | Verdict | Note | |-----|------|------|---------|------| @@ -162,6 +162,7 @@ LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only | ChirpStack | yes | no | ✅ preferred | **Packaged**; native `[user_authentication.openid_connect]` wired to `CLOUDRON_OIDC_*`; OIDC-registered users are non-admin — one-time `CHIRPSTACK_AUTH_MODE=internal` bootstrap links the seeded `admin` to your SSO email (README) | | eLabFTW | no | yes | ⚠️ risk (LDAP) | **Packaged**; no OIDC upstream (auth = local/SAML/LDAP per `src/Enums/AuthMethod.php`); `ldap` addon enabled, README maps `CLOUDRON_LDAP_*` → sysconfig LDAP panel — must be validated on the live Cloudron before production; SAML possible via external IdP | | NetBox | yes | plugin | ✅ preferred | **Packaged**; python-social-auth OIDC (`REMOTE_AUTH_BACKEND=OpenIdConnectAuth` + `SOCIAL_AUTH_OIDC_*`) wired from `CLOUDRON_OIDC_*`; local Django login retained for admin bootstrap; SSO users register without privileges (README) | +| ConsulDemocracy | yes | no | ✅ preferred | **Packaged**; omniauth_openid_connect (discovery) wired into generated secrets.yml; `feature.oidc_login` auto-enabled on first boot when the provider is present (admin-panel toggle afterwards); SAML also available; local admin seeded | ### Candidates researched