Author SHA1 Message Date
jared e988465906 Add MIT license
Lint / Shell (shellcheck) (push) Successful in 14s
Lint / JS (eslint) (push) Successful in 14s
Lint / No secrets in webhook configs (push) Successful in 11s
Lint / Landing page is rendered (matrix (push) Successful in 6s
Lint / Python (ruff) (push) Successful in 5s
Lint / Python deps (pip-audit) (push) Successful in 30s
Lint / Secret scan (gitleaks) (push) Successful in 4s
2026-10-03 00:16:58 -04:00
jared effa27da3d Merge pull request 'cinny config: status banner from the Kuma page (cinny #124)' (#17) from config-status-pages into main
Lint / Shell (shellcheck) (push) Successful in 11s
Lint / JS (eslint) (push) Successful in 7s
Lint / No secrets in webhook configs (push) Successful in 4s
Lint / Landing page is rendered (matrix (push) Successful in 3s
Lint / Python (ruff) (push) Successful in 4s
Lint / Python deps (pip-audit) (push) Successful in 33s
Lint / Secret scan (gitleaks) (push) Successful in 7s
Merge pull request #17: cinny config status banner (cinny #124)
2026-09-29 13:24:51 -04:00
Lotus CIandClaude Opus 5.5 8d80ebf4c2 cinny config: status banner from the Kuma page (cinny #124)
Lint / Shell (shellcheck) (push) Successful in 15s
Lint / JS (eslint) (push) Successful in 11s
Lint / No secrets in webhook configs (push) Successful in 5s
Lint / Landing page is rendered (matrix (push) Successful in 6s
Lint / Python (ruff) (push) Successful in 9s
Lint / Python deps (pip-audit) (push) Successful in 1m1s
Lint / Secret scan (gitleaks) (push) Successful in 8s
Lint / Shell (shellcheck) (pull_request) Successful in 14s
Lint / JS (eslint) (pull_request) Successful in 11s
Lint / No secrets in webhook configs (pull_request) Successful in 6s
Lint / Landing page is rendered (matrix (pull_request) Successful in 6s
Lint / Python (ruff) (pull_request) Successful in 6s
Lint / Python deps (pip-audit) (pull_request) Successful in 44s
Lint / Secret scan (gitleaks) (pull_request) Successful in 7s
Adds `statusPages` for matrix.lotusguild.org → the Kuma status page
https://isitup.lotusguild.org/status/matrix (groups Homeserver, Voice
calls, Login). The banner code (cinny #255) and the CSP (#16) are already
live; production's config.json comes from this file, so without this entry
the client never asks Kuma. The LXC 106 deploy merges it into the live file
and keeps server-only values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-29 12:35:55 -04:00
jared 0914339180 Merge pull request 'cinny CSP: allow the Kuma status page (cinny #124)' (#16) from csp-kuma-status into main
Lint / Shell (shellcheck) (push) Successful in 17s
Lint / JS (eslint) (push) Successful in 14s
Lint / No secrets in webhook configs (push) Successful in 8s
Lint / Landing page is rendered (matrix (push) Successful in 6s
Lint / Python (ruff) (push) Successful in 7s
Lint / Python deps (pip-audit) (push) Successful in 43s
Lint / Secret scan (gitleaks) (push) Successful in 8s
Merge pull request #16: cinny CSP allows the Kuma status page (cinny #124)
2026-09-29 12:28:30 -04:00
Lotus CIandClaude Opus 5.5 9fcbd410f2 cinny CSP: allow the app to read the Kuma status page (cinny #124)
Lint / Shell (shellcheck) (push) Successful in 17s
Lint / JS (eslint) (push) Successful in 12s
Lint / No secrets in webhook configs (push) Successful in 7s
Lint / Landing page is rendered (matrix (push) Successful in 7s
Lint / Python (ruff) (push) Successful in 7s
Lint / Python deps (pip-audit) (push) Successful in 45s
Lint / Secret scan (gitleaks) (push) Successful in 7s
Lint / Shell (shellcheck) (pull_request) Successful in 12s
Lint / JS (eslint) (pull_request) Successful in 11s
Lint / No secrets in webhook configs (pull_request) Successful in 7s
Lint / Landing page is rendered (matrix (pull_request) Successful in 10s
Lint / Python (ruff) (pull_request) Successful in 8s
Lint / Python deps (pip-audit) (pull_request) Successful in 57s
Lint / Secret scan (gitleaks) (pull_request) Successful in 8s
Add https://isitup.lotusguild.org to connect-src so the client can fetch
the public status JSON (GET /api/status-page/matrix and
/api/status-page/heartbeat/matrix) for the homeserver status banner.
Read-only public JSON, no credentials; nothing else changes.

The live snippet (/etc/nginx/snippets/cinny-security-headers.conf on
LXC 106) was identical to this file before the change; install it by hand
with a backup and `nginx -t` (the deploy script only handles
cinny/nginx.conf).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-29 12:08:45 -04:00
jared d76d276da4 Merge pull request #15: LXC 106 deploy: merge config.json, self-update (#13)
Lint / Shell (shellcheck) (push) Successful in 7s
Lint / JS (eslint) (push) Successful in 5s
Lint / No secrets in webhook configs (push) Successful in 3s
Lint / Landing page is rendered (matrix (push) Successful in 4s
Lint / Python (ruff) (push) Successful in 4s
Lint / Python deps (pip-audit) (push) Successful in 36s
Lint / Secret scan (gitleaks) (push) Successful in 4s
2026-09-28 18:52:30 -04:00
Lotus CIandClaude Opus 5.5 8d47df711d fix(lxc106): deploy script merges config.json and updates itself (#13)
Lint / Shell (shellcheck) (push) Successful in 31s
Lint / JS (eslint) (push) Successful in 5s
Lint / No secrets in webhook configs (push) Successful in 4s
Lint / Landing page is rendered (matrix (push) Successful in 6s
Lint / Python (ruff) (push) Successful in 8s
Lint / Python deps (pip-audit) (push) Successful in 1m2s
Lint / Secret scan (gitleaks) (push) Successful in 10s
Lint / Shell (shellcheck) (pull_request) Successful in 12s
Lint / JS (eslint) (pull_request) Successful in 12s
Lint / No secrets in webhook configs (pull_request) Successful in 8s
Lint / Landing page is rendered (matrix (pull_request) Successful in 8s
Lint / Python (ruff) (pull_request) Successful in 8s
Lint / Python deps (pip-audit) (pull_request) Successful in 1m15s
Lint / Secret scan (gitleaks) (pull_request) Successful in 12s
LXC 106's matrix-deploy hook has not fired since May: Gitea posts to
10.10.10.6:9000, which webhook.service binds to 127.0.0.1. The same hooks
(same secret) are served by webhook-lotus on :9001; the Gitea hook is being
re-pointed there. Before it starts firing again:

- cinny/config.json is merged into the live file instead of copied over it.
  The live file carries gifApiKey (injected by lotus_deploy.sh), empty in
  git, which a copy would blank. Repo keys win except where the repo value is
  empty and the live one isn't. Backup goes to /root/config-backups; the live
  file is left untouched on error.
- The script installs its own updates (deploy/lxc106-cinny.sh →
  /usr/local/bin/matrix-deploy.sh, after bash -n). Until now repo edits to
  it never reached the server.
- A hooks.json change restarts webhook-lotus 15 s after the script exits,
  since that listener is the one running this script.
- README: port 9001, the file list, and the history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-28 18:47:49 -04:00
Lotus CIandClaude Opus 5.5 9baafd4928 cinny: load Element Call from call.chat.lotusguild.org (cinny #43)
Lint / Shell (shellcheck) (push) Successful in 50s
Lint / JS (eslint) (push) Successful in 10s
Lint / No secrets in webhook configs (push) Successful in 8s
Lint / Landing page is rendered (matrix (push) Successful in 11s
Lint / Python (ruff) (push) Successful in 10s
Lint / Python deps (pip-audit) (push) Successful in 48s
Lint / Secret scan (gitleaks) (push) Successful in 8s
Sets elementCallUrl so the web app frames the call page on its own origin
(desktop keeps its bundled copy). Applied on LXC 106 in place (the live file
also carries the injected gifApiKey; backup in /root/config-backups/), since
the matrix-deploy webhook there has not fired since May.

Rollback: remove this key (live: restore the backup) and new calls use the
bundled same-origin page again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-27 11:52:52 -04:00
jared 97d9416b01 Merge pull request #12: nginx for Element Call on call.chat.lotusguild.org (cinny #43)
Lint / Shell (shellcheck) (push) Successful in 22s
Lint / JS (eslint) (push) Successful in 15s
Lint / No secrets in webhook configs (push) Successful in 20s
Lint / Landing page is rendered (matrix (push) Successful in 13s
Lint / Python (ruff) (push) Successful in 11s
Lint / Python deps (pip-audit) (push) Successful in 1m13s
Lint / Secret scan (gitleaks) (push) Successful in 9s
2026-09-27 02:32:07 -04:00
5 changed files with 91 additions and 10 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Jared Vititoe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+2 -2
View File
@@ -111,7 +111,7 @@ matrix/
- Build log: `/var/log/cinny-build.log`
- Nginx site config: `/etc/nginx/sites-available/cinny` (copy in this repo: `cinny/nginx.conf`, synced with live on 2026-09-23)
- Nginx security headers: `/etc/nginx/snippets/cinny-security-headers.conf` (`cinny/nginx-security-headers.conf`). Included at server level **and** in every `location` that sets its own `add_header`; nginx drops inherited `add_header`s in such blocks, which left static assets without `nosniff` and `/sw.js` without its CSP (cinny #210). Edit the CSP here, not in the site config. **Exception:** `/public/element-call/` (the bundled Element Call, which the app itself frames) uses `cinny-security-headers-framed.conf` (`cinny/nginx-security-headers-framed.conf`), the same headers **without** the CSP. The app CSP's `frame-ancestors 'none'` would block every web call.
- ⚠️ The `matrix-deploy` hook on 106 has been unreachable since May (webhook bound to `127.0.0.1:9000`), so edits to these files in the repo are **not** auto-deployed there. Apply them by hand (`nginx -t` then `nginx -s reload`) and keep the repo copy in sync.
- The `matrix-deploy` hook on 106 is served by `webhook-lotus` on `10.10.10.6:9001` (Gitea hook → `http://10.10.10.6:9001/hooks/matrix-deploy`). It was pointed at `:9000` until 2026-09-28, which is bound to `127.0.0.1`, so nothing deployed from May to then (matrix #13). `cinny/config.json` is **merged** into the live file (server-injected values such as `gifApiKey` are kept), and the script installs its own updates (`deploy/lxc106-cinny.sh` → `/usr/local/bin/matrix-deploy.sh`).
---
@@ -132,7 +132,7 @@ Pushes to `main` on `LotusGuild/matrix` automatically deploy to the relevant LXC
| LXC | Service | IP | Port | Deploys When Changed |
|-----|---------|----|----|----------------------|
| 151 | matrix/hookshot | 10.10.10.29 | **9500** | `hookshot/*.js`, `systemd/livekit-server.service`, `livekit/voice-limit-guard.py`, `systemd/voice-limit-guard.service`, `matrixbot/*` |
| 106 | cinny | 10.10.10.6 | 9000 | `cinny/config.json`, `cinny/upstream-check.sh`, `cinny/lotus-build.sh`, `deploy/hooks-lxc106.json`, `systemd/cinny-upstream-check.cron` |
| 106 | cinny | 10.10.10.6 | 9001 | `cinny/config.json` (merged), `cinny/nginx.conf`, `cinny/upstream-check.sh`, `cinny/lotus-build.sh`, `cinny/lotus_deploy.sh`, `deploy/hooks-lxc106.json`, `deploy/lxc106-cinny.sh` (self), `systemd/cinny-upstream-check.cron` |
| 139 | landing/NPM | 10.10.10.27 | 9000 | `landing/index.html` |
| 110 | draupnir | 10.10.10.24 | 9000 | `draupnir/production.yaml` |
+14 -2
View File
@@ -16,5 +16,17 @@
"enabled": false,
"basename": "/"
},
"gifApiKey": ""
}
"gifApiKey": "",
"elementCallUrl": "https://call.chat.lotusguild.org/public/element-call/index.html",
"statusPages": {
"matrix.lotusguild.org": {
"url": "https://isitup.lotusguild.org",
"slug": "matrix",
"groups": {
"homeserver": "Homeserver",
"calls": "Voice calls",
"login": "Login"
}
}
}
}
+1 -1
View File
@@ -12,4 +12,4 @@ add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Permissions-Policy 'accelerometer=(), autoplay=(self "https://call.chat.lotusguild.org"), camera=(self "https://call.chat.lotusguild.org"), display-capture=(self "https://call.chat.lotusguild.org"), encrypted-media=(self), fullscreen=(self), geolocation=(self), gyroscope=(), magnetometer=(), microphone=(self "https://call.chat.lotusguild.org"), midi=(), payment=(), usb=()' always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://matrix.lotusguild.org https://matrix.org https://*.matrix.org https://mozilla.org https://mozilla.modular.im https://drive.lotusguild.org https://media.giphy.com https://media0.giphy.com https://media1.giphy.com https://media2.giphy.com https://media3.giphy.com https://media4.giphy.com https://www.openstreetmap.org https://tile.openstreetmap.org; font-src 'self' data:; connect-src 'self' https://matrix.lotusguild.org wss://matrix.lotusguild.org https://matrix.org https://*.matrix.org https://mozilla.org https://mozilla.modular.im https://chat.mozilla.org https://vector.im https://api.giphy.com https://*.giphy.com wss:; media-src 'self' https: blob:; frame-src 'self' https:; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://matrix.lotusguild.org https://matrix.org https://*.matrix.org https://mozilla.org https://mozilla.modular.im https://drive.lotusguild.org https://media.giphy.com https://media0.giphy.com https://media1.giphy.com https://media2.giphy.com https://media3.giphy.com https://media4.giphy.com https://www.openstreetmap.org https://tile.openstreetmap.org; font-src 'self' data:; connect-src 'self' https://matrix.lotusguild.org wss://matrix.lotusguild.org https://isitup.lotusguild.org https://matrix.org https://*.matrix.org https://mozilla.org https://mozilla.modular.im https://chat.mozilla.org https://vector.im https://api.giphy.com https://*.giphy.com wss:; media-src 'self' https: blob:; frame-src 'self' https:; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
+53 -5
View File
@@ -3,7 +3,8 @@
# Handles: cinny/config.json, cinny/nginx.conf, cinny/upstream-check.sh,
# cinny/lotus-build.sh, cinny/lotus_deploy.sh,
# deploy/hooks-lxc106.json, systemd/cinny-upstream-check.cron
# Triggered by: Gitea webhook on push to main
# Triggered by: Gitea webhook on push to main → http://10.10.10.6:9001/hooks/matrix-deploy
# (webhook-lotus; the :9000 listener is bound to 127.0.0.1 and unreachable).
set -euo pipefail
REPO_DIR="/opt/matrix-config"
@@ -27,9 +28,39 @@ else
fi
if echo "$CHANGED" | grep -q '^cinny/config.json'; then
echo "Deploying cinny config.json..."
cp "$REPO_DIR/cinny/config.json" /var/www/html/config.json
echo "✓ config.json deployed"
echo "Deploying cinny config.json (merged: keeps server-only values)..."
# The live file carries values injected on the server that are empty in git
# (gifApiKey, set by lotus_deploy.sh from GIPHY_API_KEY). A plain copy would
# blank them, so repo keys win except where the repo value is empty and the
# live one isn't. Backup outside the web root; on any error the live file
# is left untouched.
mkdir -p /root/config-backups
cp -p /var/www/html/config.json "/root/config-backups/config.json.$(date +%Y%m%d%H%M%S)" 2>/dev/null || true
if python3 - "$REPO_DIR/cinny/config.json" /var/www/html/config.json <<'PY'
import json, os, sys, tempfile
repo_path, live_path = sys.argv[1], sys.argv[2]
repo = json.load(open(repo_path))
live = json.load(open(live_path)) if os.path.exists(live_path) else {}
merged = dict(repo)
kept = []
for key, value in live.items():
if key in repo and repo[key] in ("", None) and value not in ("", None):
merged[key] = value
kept.append(key)
fd, tmp = tempfile.mkstemp(dir=os.path.dirname(live_path))
with os.fdopen(fd, "w") as f:
json.dump(merged, f, indent=2)
f.write("\n")
json.load(open(tmp))
os.chmod(tmp, 0o644)
os.replace(tmp, live_path)
print("kept server values for: " + (", ".join(kept) or "none"))
PY
then
echo "✓ config.json deployed"
else
echo "✗ config.json merge FAILED — live file left unchanged"
fi
fi
if echo "$CHANGED" | grep -q '^cinny/nginx.conf'; then
@@ -80,7 +111,11 @@ if echo "$CHANGED" | grep -q '^deploy/hooks-lxc106.json'; then
echo "Deploying hooks-lxc106.json..."
cp "$REPO_DIR/deploy/hooks-lxc106.json" /etc/webhook/hooks.json
systemctl restart webhook
echo "✓ hooks.json deployed, webhook restarted"
# webhook-lotus (:9001) serves the same hooks and is the one running THIS
# script (Gitea posts matrix-deploy there), so restarting it now would kill
# this deploy mid-run: restart it shortly after we exit instead.
systemd-run --on-active=15s --unit="webhook-lotus-reload-$(date +%s)" systemctl restart webhook-lotus
echo "✓ hooks.json deployed, webhook restarted (webhook-lotus in 15s)"
fi
if echo "$CHANGED" | grep -q '^systemd/cinny-upstream-check.cron'; then
@@ -90,4 +125,17 @@ if echo "$CHANGED" | grep -q '^systemd/cinny-upstream-check.cron'; then
echo "✓ cron deployed"
fi
# Keep the installed copy of this script in step with the repo (the webhook
# runs /usr/local/bin/matrix-deploy.sh, not the repo file). Checked with bash -n
# first; takes effect from the next deploy.
if echo "$CHANGED" | grep -q '^deploy/lxc106-cinny.sh'; then
if bash -n "$REPO_DIR/deploy/lxc106-cinny.sh"; then
cp "$REPO_DIR/deploy/lxc106-cinny.sh" /usr/local/bin/matrix-deploy.sh
chmod +x /usr/local/bin/matrix-deploy.sh
echo "✓ matrix-deploy.sh updated"
else
echo "✗ bash -n FAILED on lxc106-cinny.sh — keeping the installed copy"
fi
fi
echo "=== $(date) === LXC106 deploy complete ==="