api_directory_admin nests permission.SUPER_ADMIN_GROUP into every new resource's
_admin group. Changing it to the not-yet-existing 'god_admin' made that nesting
no-op, leaving the creator as the sole member (so the access_request test's
beforeAll could not remove the last member of a groupOfNames). Revert it to
'app_super_admin' and recognize 'god_admin' separately in isSuperAdmin + isAdmin.
Co-Authored-By: Claude <noreply@anthropic.com>
- Add utils/groups.js: the group schema + inheritance resolver (god_admin,
{site}_super_admin, {site}_hosts_*/{site}_apps_* aggregates, per-resource
admin/access/<capability>, meta everyone/{site}_everyone). admin implies
access; capabilities explicit; hosts/apps orthogonal; cross-site isolated.
- permission.js: recognize god_admin (legacy app_super_admin aliased) and add
onResource/requireResource for resource-level checks + everyone meta grants.
- user.js isAdmin: recognize god_admin + site-scoped super/app-admin groups.
- Remove the standalone Groups page (nav + route + view); groups are managed on
adopted Directory resources. Add a /docs/groups help link in the Directory
toolbar (GROUPS.md copied into the SSO docs).
- tests/groups.test.js: full resolver coverage (15 tests).
Co-Authored-By: Claude <noreply@anthropic.com>
- Merge theta-agent into Directory: remove the Agents page; add green/yellow/red
status dots to host rows and a Metrics tab (telemetry + discovery) to the
resource modal, joined to hosts by hostname, live via socket.io + 30s refresh.
- Discovery Plugins New-plugin modal: slug derived from name (field removed),
cron dropdown (hourly/daily/weekly/custom), configSchema-driven settings
(Proxmox url/tokenId/tokenSecret) sent as a populated config.
- Directory resource slug now read-only + derived from name.
- Vault page restyled to match the site.
- Navbar: username no longer underlined; only the active link is bold+underlined.
- docs/agents.md: document the Directory status/metrics + NAT troubleshooting.
Co-Authored-By: Claude <noreply@anthropic.com>
- /api/vault proxy now injects X-Vault-Token: the proxy declared its request
hook with http-proxy-middleware v3 syntax (on: { proxyReq }), which the
installed HPM v2 silently ignores — so every vault call reached OpenBao
unauthenticated (the recurring 403). Rewritten as v2 onProxyReq.
- Header injection ordered before fixRequestBody (the body write flushes
headers; setting X-Vault-Token after it failed on every POST/PUT).
- initORM add-only schema heal: sequelize.sync() never ALTERs, so newer columns
(PluginInstance.lastLog) are now added via describeTable + addColumn.
- Long-lived external-app tokens via sso-app role (768h periodic); VaultAppToken
stores each app token's accessor and renews it at boot + every 6h; re-minting
revokes the previous token via its accessor.
- Wire-level tests for the vault proxy + app-token accessor lifecycle.
- package.json + lockfile bumped to 1.23.0.
Co-Authored-By: Claude <noreply@anthropic.com>
- New admin Agents page (nav + /agents route + views/agents.ejs): live list of
connected theta-agent hosts with CPU/RAM/disk/ZFS/GPU telemetry and online
status, updated live over socket.io ('agent.telemetry'/'agent.discovery').
- Auth + admin-gate the /api/agent REST router (it was mounted without
middleware.auth — anyone could list nodes / send commands). The agent
WebSocket (/api/agent/ws) is unaffected (handled by the raw wss upgrade with
its own token auth).
- package.json + lockfile bumped to 1.22.0 to match the tag.
Co-Authored-By: Claude <noreply@anthropic.com>
The no_native_dialogs regression test forbids native alert/confirm/prompt in
views (they block browser events). Replace the native confirm() in deleteShared
with app.messages.confirm().
- vault_broker: always reconcile policy content before serving a cached
token (compare-and-skip), so stale stored policies can't cause a recurring
403 'permission denied'; policy content is parsed live by OpenBao, so edits
apply to existing tokens immediately.
- Shared secrets: publish to secret/shared/<owner>/<slug>; grant read to users
and apps by editing the grantee's policy content (live-applied). New
SharedSecret/SharedSecretGrant ORM models, /api/shared-secrets router, and a
Shared tab in the vault UI.
- package.json + lockfile bumped to 1.21.0 to match the tag.
Co-Authored-By: Claude <noreply@anthropic.com>
The v1.20.2 release tag was created but nodejs/package.json (and the
lockfile) were left at 1.20.1, so the deployed app's buildVersion lagged
its own release tag and the update-check banner falsely reported a newer
version. Bump the version fields to match the tag.
### Fixed
- **Navbar shows Catalog/Vault for unauthenticated users** — Changed nav
gating from `groups: []` (always visible) to `groups: ['login']` and
added synthetic 'login' group handling in app-base.js.
- **500 ENOENT: no such file or directory, open '/docs/directory.md'** —
Created the missing documentation file.
### Changed
- **SMTP configuration UI-only** — Removed SMTP from static config files
(conf/base.js, sso-secrets.js, setup.env.example). SMTP is now only
configurable via the runtime UI at /conf.
### Added
- **Test email/SMS capability** — Added POST /api/conf/test-email and
POST /api/conf/test-sms endpoints with UI buttons in the Configuration
page. Saves config first, then sends test message to verify settings.
### theta-env setup.sh
- **Non-interactive theta-agent configuration** — Added CFG_THETA_AGENT_ENABLE,
CFG_THETA_AGENT_LDAP_AUTH, and CFG_THETA_AGENT_FULL_CONTROL variables to
setup.env (all default to 1/enabled).
Co-Authored-By: Claude <noreply@anthropic.com>