feat: add InvenTree Cloudron package (Business-Apps) [#658]
Official-image wrapper of inventree/inventree 1.5.2 (digest-pinned). allauth OIDC provider JSON built from the platform env; invoke update on boot; RQ worker behind the web-port gate; admin seeded with a generated password. grind-stack: lowercase image names. 19th package. Verified: health 200, SSO route 302s to issuer, migrations clean. Detail: https://projects.knownelement.com/issues/658#note-5086
This commit is contained in:
+51
@@ -1419,6 +1419,57 @@ no logo file ships).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 19. InvenTree (Business-Apps) ✅
|
||||||
|
**Date**: 2026-09-06
|
||||||
|
**Application**: InvenTree — open-source inventory management (parts,
|
||||||
|
stock, BOMs, suppliers, purchase/build orders, plugins, REST API).
|
||||||
|
Upstream: https://github.com/inventree/InvenTree (MIT), v1.5.2.
|
||||||
|
|
||||||
|
**Ticket**: [#658](https://projects.knownelement.com/issues/658)
|
||||||
|
|
||||||
|
**Pattern**: official-image wrapper of `inventree/inventree:1.5.2`
|
||||||
|
(amd64 digest pinned). Upstream compose splits server (gunicorn :8000)
|
||||||
|
and worker (`invoke worker`); Cloudron is one container — worker
|
||||||
|
backgrounded behind the web-port gate (NetBox pattern, third use).
|
||||||
|
|
||||||
|
**Auth gate verdict**: ✅ OIDC preferred. django-allauth in core;
|
||||||
|
`INVENTREE_SOCIAL_PROVIDERS` (settings.py:1002, JSON) carries the
|
||||||
|
openid_connect provider; `SOCIALACCOUNT_OPENID_CONNECT_URL_PREFIX=''`
|
||||||
|
routes SSO at `/accounts/oidc/<provider_id>/`. start.sh builds the
|
||||||
|
provider JSON from `CLOUDRON_OIDC_*` with `server_url` (discovery) +
|
||||||
|
PKCE. LDAP also in core as an alternative. Local admin seeded with a
|
||||||
|
generated password persisted at `/app/data/.admin_password`.
|
||||||
|
|
||||||
|
**Key decisions**:
|
||||||
|
|
||||||
|
- Everything env-driven (INVENTREE_DB_*, INVENTREE_CACHE_* = redis
|
||||||
|
addon with cache DB 1, INVENTREE_SITE_URL, INVENTREE_ADMIN_*).
|
||||||
|
- `invoke update` driven explicitly on every boot (migrations +
|
||||||
|
collectstatic); the image's init.sh ENTRYPOINT is bypassed so
|
||||||
|
ordering is ours.
|
||||||
|
- Data dir pinned to /app/data — media/static/config.yaml/secret all
|
||||||
|
persist; the image's own SECRET_KEY_FILE convention then lives in
|
||||||
|
localstorage too.
|
||||||
|
- Health endpoint: `/api/system/health/` (upstream's unauthenticated
|
||||||
|
probe path).
|
||||||
|
- grind-stack fix: image names must be lowercase — dir basenames are
|
||||||
|
lowercased for tags/volumes (`grind-InvenTree:test` was invalid).
|
||||||
|
|
||||||
|
**Verification** (grind-stack, ephemeral pg+redis): first boot ~7.5 min
|
||||||
|
(migrations + static collection) → health 200; home 302→login;
|
||||||
|
`/accounts/oidc/cloudron/login/` 302s to the issuer (provider JSON
|
||||||
|
valid); worker gate fired; version-check JSONDecodeError in logs =
|
||||||
|
release-API fetch noise (sandboxed network), benign.
|
||||||
|
|
||||||
|
**Files Created**: Dockerfile, CloudronManifest.json (port 8000,
|
||||||
|
localstorage + postgresql + redis, 2048MB, healthCheckPath
|
||||||
|
/api/system/health/), start.sh, README.md, CHANGELOG.md,
|
||||||
|
.dockerignore, logo.png (from repo docs/docs/assets).
|
||||||
|
|
||||||
|
**Commit**: `feat: add InvenTree Cloudron package (Business-Apps) [#658]`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Packaging Pattern: Download Pre-Compiled Binaries
|
## Packaging Pattern: Download Pre-Compiled Binaries
|
||||||
|
|
||||||
### When to Use
|
### When to Use
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
repo
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Changelog — InvenTree Cloudron Package
|
||||||
|
|
||||||
|
## 1.0.0 — 2026-09-06
|
||||||
|
|
||||||
|
- Initial package: InvenTree 1.5.2 (official-image wrapper, digest
|
||||||
|
pinned sha256:2df695b3…)
|
||||||
|
- postgresql + redis + localstorage addons; gunicorn on :8000
|
||||||
|
- INVENTREE_* env mapped from the platform; data dir pinned to
|
||||||
|
/app/data (media/static/config + persisted secret key)
|
||||||
|
- OIDC provider JSON built from CLOUDRON_OIDC_* (allauth
|
||||||
|
openid_connect, PKCE); local admin seeded with generated password
|
||||||
|
- `invoke update` on boot; RQ worker backgrounded behind web-port gate
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"manifestVersion": 2,
|
||||||
|
"type": "app",
|
||||||
|
"id": "io.cloudron.inventree",
|
||||||
|
"title": "InvenTree",
|
||||||
|
"description": "Open-source inventory management system: parts and stock tracking, bills of materials, suppliers, purchase and build orders, with a plugin ecosystem and REST API. PostgreSQL storage, Redis-backed background workers. SSO via the Cloudron OIDC provider; a local admin account is seeded on first boot (generated password in /app/data/.admin_password).",
|
||||||
|
"author": "InvenTree contributors",
|
||||||
|
"website": "https://inventree.org/",
|
||||||
|
"contactEmail": "cloudron@tsys.dev",
|
||||||
|
"tagline": "Inventory management: parts, stock, BOMs and orders",
|
||||||
|
"version": "1.5.2",
|
||||||
|
"healthCheckPath": "/api/system/health/",
|
||||||
|
"httpPort": 8000,
|
||||||
|
"memoryLimit": 2048,
|
||||||
|
"addons": {
|
||||||
|
"localstorage": {},
|
||||||
|
"postgresql": {},
|
||||||
|
"redis": {}
|
||||||
|
},
|
||||||
|
"mediaLinks": [],
|
||||||
|
"changelog": "Initial Cloudron package for InvenTree 1.5.2 (official-image wrapper of inventree/inventree, digest pinned). start.sh maps the postgresql/redis addons onto INVENTREE_* env, persists secret key + generated admin password under /app/data, builds the django-allauth openid_connect provider JSON from the Cloudron OIDC env, drives `invoke update` (migrations + static) before serving, and backgrounds the RQ worker gated on the web port. Health endpoint /api/system/health/ per upstream convention.",
|
||||||
|
"icon": "file://logo.png"
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# InvenTree Cloudron Package
|
||||||
|
#
|
||||||
|
# InvenTree is an open-source inventory management system (Django):
|
||||||
|
# parts/stock tracking, BOMs, suppliers, purchase orders, build orders,
|
||||||
|
# plugin ecosystem. PostgreSQL storage + Redis for background-task
|
||||||
|
# queues (RQ) and optional caching.
|
||||||
|
#
|
||||||
|
# Upstream: https://github.com/inventree/InvenTree (MIT), v1.5.2.
|
||||||
|
# - Official image inventree/inventree (single image; upstream compose
|
||||||
|
# runs inventree-server [gunicorn :8000] and inventree-worker
|
||||||
|
# [invoke worker] as separate services - Cloudron is one container,
|
||||||
|
# so start.sh backgrounds the worker gated on the web port, the
|
||||||
|
# same pattern as NetBox).
|
||||||
|
# - Everything is env-configurable via INVENTREE_* (config.md): DB,
|
||||||
|
# cache, site URL, secret key, admin seed, SOCIAL_PROVIDERS JSON.
|
||||||
|
# - The image ENTRYPOINT (init.sh) prepares dirs + config template
|
||||||
|
# and execs the CMD; migrations/static collection run via
|
||||||
|
# `invoke update`, which start.sh drives explicitly.
|
||||||
|
#
|
||||||
|
# Authentication: NATIVE OIDC (preferred) via django-allauth
|
||||||
|
# (settings.py:1002 reads INVENTREE_SOCIAL_PROVIDERS;
|
||||||
|
# SOCIALACCOUNT_OPENID_CONNECT_URL_PREFIX='' so SSO routes live at
|
||||||
|
# /accounts/oidc/...). start.sh builds the provider JSON from the
|
||||||
|
# Cloudron platform OIDC env (CLOUDRON_OIDC_*). LDAP also exists in
|
||||||
|
# core (INVENTREE_LDAP_ENABLED) as an alternative. Local login remains;
|
||||||
|
# the first admin is seeded (generated password, see README).
|
||||||
|
#
|
||||||
|
# Pattern: official-image wrapper. Image pinned by tag AND digest
|
||||||
|
# (amd64 manifest digest of 1.5.2, from docker manifest inspect).
|
||||||
|
FROM inventree/inventree:1.5.2@sha256:2df695b338b9fbcb4d86a6a3c27c5f53e690d1b58af8a216e69fec49fc178a14
|
||||||
|
|
||||||
|
# no packages needed: the image ships bash, python, invoke; start.sh
|
||||||
|
# only orchestrates env + processes
|
||||||
|
COPY start.sh /app/start.sh
|
||||||
|
|
||||||
|
# gunicorn web server; API/SSO all on this port (worker has no listener)
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/bash", "/app/start.sh"]
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# InvenTree — Cloudron Package
|
||||||
|
|
||||||
|
[InvenTree](https://github.com/inventree/InvenTree) v1.5.2 — open-source
|
||||||
|
inventory management: parts and stock, BOMs, suppliers, purchase/build
|
||||||
|
orders, plugins, REST API. Django + PostgreSQL + Redis(RQ). Packaged as
|
||||||
|
an **official-image wrapper** around `inventree/inventree:1.5.2`
|
||||||
|
(digest-pinned). Upstream runs server and worker as separate compose
|
||||||
|
services; Cloudron is one container, so start.sh backgrounds
|
||||||
|
`invoke worker` gated on the web port (same pattern as NetBox).
|
||||||
|
|
||||||
|
## Authentication (auth gate: ✅ OIDC preferred)
|
||||||
|
|
||||||
|
django-allauth is built into core; `INVENTREE_SOCIAL_PROVIDERS`
|
||||||
|
(settings.py:1002) carries provider config. start.sh builds the
|
||||||
|
`openid_connect` provider from the Cloudron platform env:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"openid_connect": {"OAUTH_PKCE_ENABLED": true, "APPS": [{
|
||||||
|
"provider_id": "cloudron", "name": "Cloudron SSO",
|
||||||
|
"server_url": "<CLOUDRON_OIDC_ISSUER>", "client_id": "...", "secret": "..."
|
||||||
|
}]}}
|
||||||
|
```
|
||||||
|
|
||||||
|
- SSO login route: `https://<app-domain>/accounts/oidc/cloudron/login/`
|
||||||
|
- LDAP is also available in core (`INVENTREE_LDAP_*`) as an alternative.
|
||||||
|
- Local login remains for the admin.
|
||||||
|
|
||||||
|
**First-boot admin**: a local `admin` account is seeded with a
|
||||||
|
generated password stored at `/app/data/.admin_password` (read it via
|
||||||
|
the Cloudron file manager). Change it after first login, or set
|
||||||
|
`INVENTREE_ADMIN_EMAIL`/`INVENTREE_ADMIN_PASSWORD` app env vars to
|
||||||
|
control the seed yourself.
|
||||||
|
|
||||||
|
## Runtime layout
|
||||||
|
|
||||||
|
| Concern | How |
|
||||||
|
|---------|-----|
|
||||||
|
| Database | Cloudron `postgresql` addon |
|
||||||
|
| Cache/queues | Cloudron `redis` addon (cache DB 1; RQ default DB 0) |
|
||||||
|
| Schema + static | `invoke update` on every boot (migrations + collectstatic) |
|
||||||
|
| Worker | `invoke worker` backgrounded, gated on web port (post-migration) |
|
||||||
|
| Persistence | `/app/data` (localstorage): media/, static/, config.yaml, secret key, admin password |
|
||||||
|
| Health | `/api/system/health/` (upstream's own unauthenticated endpoint) |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Version upgrades: bump tag+digest, rebuild — `invoke update` migrates
|
||||||
|
on first boot.
|
||||||
|
- The image ENTRYPOINT's venv logic is bypassed (deps are baked in the
|
||||||
|
image); start.sh controls ordering instead.
|
||||||
|
- Package pattern + verification: repo `JOURNAL.md`, InvenTree section.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 198 KiB |
+97
@@ -0,0 +1,97 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# InvenTree runtime setup for Cloudron:
|
||||||
|
# 1. map the Cloudron postgresql + redis addons onto INVENTREE_* env
|
||||||
|
# and pin the data dir into localstorage (/app/data)
|
||||||
|
# 2. wait for both addons
|
||||||
|
# 3. drive `invoke update` (migrations + static collection) before
|
||||||
|
# serving; the image ENTRYPOINT is bypassed so we control ordering
|
||||||
|
# 4. background the RQ worker (gated on the web port = migrations
|
||||||
|
# done), then exec gunicorn on :8000
|
||||||
|
#
|
||||||
|
# Authentication: OIDC via the Cloudron platform provider, mapped into
|
||||||
|
# INVENTREE_SOCIAL_PROVIDERS (django-allauth openid_connect). The first
|
||||||
|
# admin is seeded via INVENTREE_ADMIN_* with a generated password,
|
||||||
|
# persisted at /app/data/.admin_password (see README).
|
||||||
|
|
||||||
|
DATA_DIR="/app/data"
|
||||||
|
ADMIN_PASS_FILE="${DATA_DIR}/.admin_password"
|
||||||
|
|
||||||
|
mkdir -p "${DATA_DIR}"
|
||||||
|
|
||||||
|
# --- 1. Cloudron -> INVENTREE_* environment ---------------------------------------
|
||||||
|
export INVENTREE_DATA_DIR="${DATA_DIR}"
|
||||||
|
export INVENTREE_CONFIG_FILE="${DATA_DIR}/config.yaml"
|
||||||
|
|
||||||
|
export INVENTREE_DB_ENGINE=postgresql
|
||||||
|
export INVENTREE_DB_HOST="${CLOUDRON_POSTGRESQL_HOST:-127.0.0.1}"
|
||||||
|
export INVENTREE_DB_PORT="${CLOUDRON_POSTGRESQL_PORT:-5432}"
|
||||||
|
export INVENTREE_DB_NAME="${CLOUDRON_POSTGRESQL_DATABASE:-inventree}"
|
||||||
|
export INVENTREE_DB_USER="${CLOUDRON_POSTGRESQL_USERNAME:-inventree}"
|
||||||
|
export INVENTREE_DB_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD:-}"
|
||||||
|
|
||||||
|
export INVENTREE_CACHE_ENABLED=true
|
||||||
|
export INVENTREE_CACHE_HOST="${CLOUDRON_REDIS_HOST:-127.0.0.1}"
|
||||||
|
export INVENTREE_CACHE_PORT="${CLOUDRON_REDIS_PORT:-6379}"
|
||||||
|
export INVENTREE_CACHE_PASSWORD="${CLOUDRON_REDIS_PASSWORD:-}"
|
||||||
|
export INVENTREE_CACHE_DB=1
|
||||||
|
|
||||||
|
export INVENTREE_SITE_URL="${CLOUDRON_APP_ORIGIN:-http://localhost}"
|
||||||
|
export INVENTREE_SECRET_KEY="$(cat "${DATA_DIR}/.secret_key" 2>/dev/null || true)"
|
||||||
|
if [[ -z "${INVENTREE_SECRET_KEY}" ]]; then
|
||||||
|
( umask 077; head -c 48 /dev/urandom | od -An -tx1 | tr -d ' \n' > "${DATA_DIR}/.secret_key" )
|
||||||
|
export INVENTREE_SECRET_KEY="$(cat "${DATA_DIR}/.secret_key")"
|
||||||
|
echo "Generated new InvenTree secret key"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# first admin: generated password, stored under /app/data
|
||||||
|
if [[ ! -s "${ADMIN_PASS_FILE}" ]]; then
|
||||||
|
( umask 077; head -c 12 /dev/urandom | od -An -tx1 | tr -d ' \n' > "${ADMIN_PASS_FILE}" )
|
||||||
|
echo "Generated admin password (stored at ${ADMIN_PASS_FILE} - see README)"
|
||||||
|
fi
|
||||||
|
export INVENTREE_ADMIN_USER="${INVENTREE_ADMIN_USER:-admin}"
|
||||||
|
export INVENTREE_ADMIN_PASSWORD="${INVENTREE_ADMIN_PASSWORD:-$(cat "${ADMIN_PASS_FILE}")}"
|
||||||
|
export INVENTREE_ADMIN_EMAIL="${INVENTREE_ADMIN_EMAIL:-admin@${CLOUDRON_APP_DOMAIN:-localhost}}"
|
||||||
|
|
||||||
|
# platform OIDC -> django-allauth openid_connect (server_url drives
|
||||||
|
# .well-known discovery; PKCE on)
|
||||||
|
if [[ -n "${CLOUDRON_OIDC_CLIENT_ID:-}" ]]; then
|
||||||
|
export INVENTREE_SOCIAL_PROVIDERS="$(jq -nc \
|
||||||
|
--arg cid "${CLOUDRON_OIDC_CLIENT_ID}" \
|
||||||
|
--arg csec "${CLOUDRON_OIDC_CLIENT_SECRET:-}" \
|
||||||
|
--arg issuer "${CLOUDRON_OIDC_ISSUER:-}" \
|
||||||
|
'{openid_connect: {OAUTH_PKCE_ENABLED: true, APPS: [{provider_id: "cloudron", name: "Cloudron SSO", server_url: $issuer, client_id: $cid, secret: $csec}]}}')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 2. wait for the addons ---------------------------------------------------------
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_tcp "${INVENTREE_DB_HOST}" "${INVENTREE_DB_PORT}" "PostgreSQL"
|
||||||
|
wait_tcp "${INVENTREE_CACHE_HOST}" "${INVENTREE_CACHE_PORT}" "Redis"
|
||||||
|
|
||||||
|
# --- 3. schema + static + plugin setup ----------------------------------------------
|
||||||
|
# image layout: INVENTREE_HOME=/home/inventree (tasks.py + gunicorn.conf.py
|
||||||
|
# + init.sh live here), INVENTREE_BACKEND_DIR=/home/inventree/src/backend
|
||||||
|
cd "${INVENTREE_HOME:-/home/inventree}"
|
||||||
|
echo "Running invoke update (migrations + static files) ..."
|
||||||
|
invoke update
|
||||||
|
|
||||||
|
# --- 4. worker + web server ----------------------------------------------------------
|
||||||
|
(
|
||||||
|
until (exec 3<>/dev/tcp/127.0.0.1/8000) 2>/dev/null; do sleep 2; done
|
||||||
|
echo "web port is up - starting InvenTree worker"
|
||||||
|
exec invoke worker
|
||||||
|
) &
|
||||||
|
|
||||||
|
echo "Starting InvenTree web server on :8000 ..."
|
||||||
|
exec gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 \
|
||||||
|
--chdir "${INVENTREE_BACKEND_DIR:-/home/inventree/src/backend}/InvenTree"
|
||||||
@@ -9,9 +9,9 @@ The Cloudron component focuses on packaging upstream free/libre/open application
|
|||||||
### 📊 Current Progress
|
### 📊 Current Progress
|
||||||
|
|
||||||
- **Total Applications**: 46 (see [GitUrlList.txt](GitUrlList.txt); pruned 2026-09-06 by human rulings: no-Node policy, k8s redirects, out-of-scope)
|
- **Total Applications**: 46 (see [GitUrlList.txt](GitUrlList.txt); pruned 2026-09-06 by human rulings: no-Node policy, k8s redirects, out-of-scope)
|
||||||
- **Completed Packages**: 18/46 (~39% of the post-ruling set)
|
- **Completed Packages**: 19/46 (~41% of the post-ruling set)
|
||||||
- **Packaging Templates**: Created ✅
|
- **Packaging Templates**: Created ✅
|
||||||
- **Packages Committed & Pushed**: 18 ✅
|
- **Packages Committed & Pushed**: 19 ✅
|
||||||
- **Build Tickets**: rulings synced 2026-09-06 (#633-#678 batch, umbrella
|
- **Build Tickets**: rulings synced 2026-09-06 (#633-#678 batch, umbrella
|
||||||
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
|
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
|
||||||
grist-core excluded (packaged upstream)
|
grist-core excluded (packaged upstream)
|
||||||
@@ -40,6 +40,7 @@ The Cloudron component focuses on packaging upstream free/libre/open application
|
|||||||
| 16 | NetBox | Infrastructure | ~1GB | 8080 | localstorage, postgresql, redis | ✅ Committed |
|
| 16 | NetBox | Infrastructure | ~1GB | 8080 | localstorage, postgresql, redis | ✅ Committed |
|
||||||
| 17 | ConsulDemocracy | Collaboration | ~1.6GB | 3000 | localstorage, postgresql | ✅ Committed |
|
| 17 | ConsulDemocracy | Collaboration | ~1.6GB | 3000 | localstorage, postgresql | ✅ Committed |
|
||||||
| 18 | GoAlert | Monitoring | ~40MB | 8081 | localstorage, postgresql | ✅ Committed |
|
| 18 | GoAlert | Monitoring | ~40MB | 8081 | localstorage, postgresql | ✅ Committed |
|
||||||
|
| 19 | InvenTree | Business-Apps | ~1.4GB | 8000 | localstorage, postgresql, redis | ✅ Committed |
|
||||||
|
|
||||||
### 📦 Packages in Development
|
### 📦 Packages in Development
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
|
|
||||||
## Current State: STABLE (packaging phase, ongoing)
|
## Current State: STABLE (packaging phase, ongoing)
|
||||||
|
|
||||||
Cloudron packaging pipeline is operational. 18 of 46 remaining-set applications are
|
Cloudron packaging pipeline is operational. 19 of 46 remaining-set applications are
|
||||||
packaged, committed, and pushed. Packaging templates exist for the core
|
packaged, committed, and pushed. Packaging templates exist for the core
|
||||||
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
|
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
|
||||||
All remaining apps now carry build tickets (#633-#678) under umbrella
|
All remaining apps now carry build tickets (#633-#678) under umbrella
|
||||||
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
|
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
|
||||||
ready for the sequential grind-driver pattern.
|
ready for the sequential grind-driver pattern.
|
||||||
|
|
||||||
## Completed Packages (18)
|
## Completed Packages (19)
|
||||||
|
|
||||||
| # | Application | Category | Pattern | Port(s) | Addons |
|
| # | Application | Category | Pattern | Port(s) | Addons |
|
||||||
|---|-------------|----------|---------|---------|--------|
|
|---|-------------|----------|---------|---------|--------|
|
||||||
@@ -80,7 +80,7 @@ GitUrlList pruned 56 → 46 accordingly.
|
|||||||
| #655 | Slurm | System-Administration | disposition: OUT OF SCOPE — ruling pending |
|
| #655 | Slurm | System-Administration | disposition: OUT OF SCOPE — ruling pending |
|
||||||
| #656 | Gophish | Security | blocked-on-auth |
|
| #656 | Gophish | Security | blocked-on-auth |
|
||||||
| #657 | SniperPhish | Security | upstream gone (404) — ruling pending |
|
| #657 | SniperPhish | Security | upstream gone (404) — ruling pending |
|
||||||
| #658 | InvenTree | Business-Apps | GO: official image, OIDC+LDAP core |
|
| #658 | InvenTree | Business-Apps | DONE 2026-09-06 (19th package, grind-verified) |
|
||||||
| #659 | Mender | System-Administration | build |
|
| #659 | Mender | System-Administration | build |
|
||||||
| #661 | WireViz | Documentation-Tools | disposition: covered by wireviz-web package |
|
| #661 | WireViz | Documentation-Tools | disposition: covered by wireviz-web package |
|
||||||
| #662 | KillBill | Business-Apps | build |
|
| #662 | KillBill | Business-Apps | build |
|
||||||
@@ -116,7 +116,7 @@ Full write-ups of each pattern + challenges are in [`JOURNAL.md`](JOURNAL.md).
|
|||||||
| Low-Code | 2 | 1/2 | corteza done (openblocks removed) |
|
| Low-Code | 2 | 1/2 | corteza done (openblocks removed) |
|
||||||
| Monitoring | 5 | 2/5 | healthchecks, goalert done (langfuse removed) |
|
| Monitoring | 5 | 2/5 | healthchecks, goalert done (langfuse removed) |
|
||||||
| Automation | 3 | 1/3 | windmill done (huginn removed) |
|
| Automation | 3 | 1/3 | windmill done (huginn removed) |
|
||||||
| Business-Apps | 6 | 1/6 | elabftw done (midday removed) |
|
| Business-Apps | 6 | 2/6 | elabftw, inventree done (midday removed) |
|
||||||
| Collaboration | 2 | 1/2 | consuldemocracy done |
|
| Collaboration | 2 | 1/2 | consuldemocracy done |
|
||||||
| Infrastructure | 6 | 5/6 | easy-gate, rathole, database-gateway, chirpstack, netbox done |
|
| Infrastructure | 6 | 5/6 | easy-gate, rathole, database-gateway, chirpstack, netbox done |
|
||||||
| Data-Management | 2 | 0/2 | datahub, seatunnel |
|
| Data-Management | 2 | 0/2 | datahub, seatunnel |
|
||||||
@@ -135,7 +135,7 @@ Auth capability is a hard gate before packaging (see
|
|||||||
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
||||||
(unacceptable / blocked-on-auth).
|
(unacceptable / blocked-on-auth).
|
||||||
|
|
||||||
### Completed packages (18)
|
### Completed packages (19)
|
||||||
|
|
||||||
| App | OIDC | LDAP | Verdict | Note |
|
| App | OIDC | LDAP | Verdict | Note |
|
||||||
|-----|------|------|---------|------|
|
|-----|------|------|---------|------|
|
||||||
@@ -157,6 +157,7 @@ LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
|||||||
| 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) |
|
| 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 |
|
| 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 |
|
||||||
| GoAlert | yes | no | ✅ preferred | **Packaged**; native generic OIDC (go-oidc, any issuer) wired via GOALERT_OIDC_* from the platform provider; new-user creation on; optional first-admin basic auth via GOALERT_ADMIN_USER/PASS; callback /api/v2/identity/providers/oidc/callback |
|
| GoAlert | yes | no | ✅ preferred | **Packaged**; native generic OIDC (go-oidc, any issuer) wired via GOALERT_OIDC_* from the platform provider; new-user creation on; optional first-admin basic auth via GOALERT_ADMIN_USER/PASS; callback /api/v2/identity/providers/oidc/callback |
|
||||||
|
| InvenTree | yes | yes | ✅ preferred | **Packaged**; django-allauth openid_connect provider JSON built from CLOUDRON_OIDC_* (server_url discovery, PKCE); SSO at /accounts/oidc/cloudron/; LDAP also available; local admin seeded (generated password in /app/data/.admin_password) |
|
||||||
|
|
||||||
### Candidates researched
|
### Candidates researched
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ manifest_field() { jq -r "$1" "$PKG/CloudronManifest.json"; }
|
|||||||
cmd_up() {
|
cmd_up() {
|
||||||
PKG="${1:?usage: grind-stack.sh up <pkg-dir>}"
|
PKG="${1:?usage: grind-stack.sh up <pkg-dir>}"
|
||||||
[ -f "$PKG/CloudronManifest.json" ] || die "no CloudronManifest.json in $PKG"
|
[ -f "$PKG/CloudronManifest.json" ] || die "no CloudronManifest.json in $PKG"
|
||||||
APPNAME="$(basename "$PKG")"
|
APPNAME="$(basename "$PKG" | tr '[:upper:]' '[:lower:]')"
|
||||||
PORT="$(manifest_field .httpPort)"
|
PORT="$(manifest_field .httpPort)"
|
||||||
MEM="$(manifest_field .memoryLimit)"
|
MEM="$(manifest_field .memoryLimit)"
|
||||||
ADDONS="$(jq -r '.addons | keys[]' "$PKG/CloudronManifest.json" | sort | tr '\n' ' ')"
|
ADDONS="$(jq -r '.addons | keys[]' "$PKG/CloudronManifest.json" | sort | tr '\n' ' ')"
|
||||||
@@ -121,7 +121,7 @@ cmd_down() {
|
|||||||
|
|
||||||
cmd_sweep() {
|
cmd_sweep() {
|
||||||
PKG="${1:?usage: grind-stack.sh sweep <pkg-dir>}"
|
PKG="${1:?usage: grind-stack.sh sweep <pkg-dir>}"
|
||||||
APPNAME="$(basename "$PKG")"
|
APPNAME="$(basename "$PKG" | tr '[:upper:]' '[:lower:]')"
|
||||||
echo "== grind sweep: $APPNAME"
|
echo "== grind sweep: $APPNAME"
|
||||||
stack_running && die "stack still up - run 'down' before sweep"
|
stack_running && die "stack still up - run 'down' before sweep"
|
||||||
docker image rm "grind-$APPNAME:test" >/dev/null 2>&1 || echo " (test image already gone)"
|
docker image rm "grind-$APPNAME:test" >/dev/null 2>&1 || echo " (test image already gone)"
|
||||||
|
|||||||
Reference in New Issue
Block a user