diff --git a/.gitignore b/.gitignore index 4dfa580..bbbdd91 100755 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,12 @@ secrets.js # they must never be committed. The empty *.example templates ARE tracked. config/*-secrets.js +# Default sqlite ORM storage (nodejs/models/index.js falls back to this path +# when no external DB is configured via conf.orm) -- live runtime data, not a +# fixture. Was committed by mistake across many prior releases. NB: this is +# nodejs/config/, distinct from the root ./config/ secrets dir above. +nodejs/config/*.sqlite + # Jekyll build artifact (GitHub Pages builds remotely; ignore locally) docs/_site diff --git a/CHANGELOG.md b/CHANGELOG.md index aca8768..8ce9c94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# v2.0.3 - 2026-08-09 + +### Fixed +- **Directory tab showed unpromoted discoveries.** `GET /api/directory-admin/resources` unconditionally admitted every `kind: 'host'` resource, and every discovery plugin (UniFi, Proxmox, nmap) creates its finds as `kind: 'host'` — so unchecking "Auto-promote to Directory" on a plugin never actually kept undiscovered/unpromoted devices out of the Directory tab, only out of the LDAP-group auto-provisioning. Now only `site` resources are unconditionally shown; anything else that discovery ever touched requires `metadata.managed === true` (set by promotion, an agent, or merging into an already-managed resource). +- **`GET /api/directory-admin/site-status` 500'd.** Queried `Resource.list({ where: { subType: 'wireguard' } })`, but `subType` only ever lives in `metadata.subType` (every driver/discovery plugin reads it that way) — never a top-level DB column, so SQLite raised `no such column: Resource.subType`. Filters in JS over `metadata.subType` now. +- **Discovered Inventory had no way to review ignored devices.** Added a "Show ignored" toggle (off by default) to the tab, so `metadata.ignored === true` rows stay hidden from routine triage but remain reachable. + +### Chore +- **Untracked `nodejs/config/inventory.sqlite`.** It's the app's default runtime DB (`nodejs/models/index.js` falls back to this path when no external DB is configured), not a fixture — it had been committed by mistake across 13 prior releases, churning on every local run. Removed from tracking and gitignored. + # v2.0.2 - 2026-08-09 ### Fixed diff --git a/nodejs/config/inventory.sqlite b/nodejs/config/inventory.sqlite deleted file mode 100644 index 53b93fe..0000000 Binary files a/nodejs/config/inventory.sqlite and /dev/null differ diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 64efa8e..ecbd3cf 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "t42-theta-directory", - "version": "2.0.2", + "version": "2.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "t42-theta-directory", - "version": "2.0.2", + "version": "2.0.3", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-free": "^7.3.0", diff --git a/nodejs/package.json b/nodejs/package.json index c4a2811..71ea39e 100755 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "t42-theta-directory", - "version": "2.0.2", + "version": "2.0.3", "description": "A very simple LDAP management and SSO system", "author": [ { diff --git a/nodejs/routes/api_directory_admin.js b/nodejs/routes/api_directory_admin.js index 7ccd092..ea680c5 100644 --- a/nodejs/routes/api_directory_admin.js +++ b/nodejs/routes/api_directory_admin.js @@ -199,10 +199,17 @@ router.get('/resources', async (req, res, next) => { try { let resources = await Resource.list(); resources = resources.filter(r => { - if (r.kind === 'host' || r.kind === 'site') return true; - const isAuto = r.metadata?.discovery_sources?.length > 0 && !r.metadata.discovery_sources.includes('manual'); + // Sites are structural containers, not discovery output -- always shown. + if (r.kind === 'site') return true; + // A resource discovery ever touched only belongs in the Directory once + // it's explicitly managed (created by an agent, promoted by a user, or + // merged into an already-managed resource). Until then it's pending + // review in the Discovered Inventory tab. Anything discovery never + // touched (created directly through this admin UI) has no + // discovery_sources and is always shown. + const isDiscovered = r.metadata?.discovery_sources?.length > 0; const isManaged = r.metadata?.managed === true; - return !isAuto || isManaged; + return !isDiscovered || isManaged; }); // Even admins never receive secret metadata (e.g. client_secret_hash) over // the wire; projectResources strips it unconditionally. @@ -885,7 +892,8 @@ let localSiteConfig = { router.get('/site-status', async (req, res, next) => { try { const sites = await Resource.list({ where: { kind: 'site' } }); - const gateResources = await Resource.list({ where: { subType: 'wireguard' } }); + const allResources = await Resource.list(); + const gateResources = allResources.filter(r => r.metadata && r.metadata.subType === 'wireguard'); res.json({ status: 'ok', diff --git a/nodejs/views/directory.ejs b/nodejs/views/directory.ejs index 578a503..168baa8 100644 --- a/nodejs/views/directory.ejs +++ b/nodejs/views/directory.ejs @@ -136,6 +136,10 @@ Network Discovery Dashboard
+
+ + +
@@ -2258,11 +2262,14 @@ function renderDiscoveryTable() { const search = $('#discovery-search-filter').val().toLowerCase(); + const showIgnored = $('#discovery-show-ignored').is(':checked'); const filtered = allDiscoveryResources.filter(r => { if (search && !r.name.toLowerCase().includes(search) && !r.slug.toLowerCase().includes(search)) return false; // Directory contains managed items; Discovered Inventory only shows unmanaged/pending items awaiting promotion const isExplicitManaged = r.metadata && (r.metadata.managed === true || r.metadata.managed === 'true'); if (isExplicitManaged || r.kind === 'site' || r.kind === 'service') return false; + const isIgnored = r.metadata && (r.metadata.ignored === true || r.metadata.ignored === 'true'); + if (isIgnored && !showIgnored) return false; return true; });