iobroker.eos-admin 7.10.6 → 7.10.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/INSTALL_TEST_V7.10.7.md +9 -0
  2. package/MERGE_UPDATE_README_V7.10.7.md +7 -0
  3. package/NEXOWATT_EOS_BUILD_INFO.json +19 -19
  4. package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +26 -24
  5. package/PUBLISH_STABLE_V7.10.7.md +9 -0
  6. package/README_STABILITY_V7.10.7.md +7 -0
  7. package/RELEASE_ACCEPTANCE_V7.10.7.md +12 -0
  8. package/RELEASE_NOTES_V7.10.7.md +19 -0
  9. package/{SECURITY_ROLE_MATRIX_V7.10.6.md → SECURITY_ROLE_MATRIX_V7.10.7.md} +4 -2
  10. package/adminWww/css/nexowatt-native-shell.css +332 -0
  11. package/adminWww/index.html +14 -14
  12. package/adminWww/js/eos-role-bootstrap.js +4 -3
  13. package/adminWww/js/eos-role-ui.js +34 -18
  14. package/adminWww/js/nexowatt-native-shell.js +104 -2
  15. package/adminWww/static/js/{nexowatt-stable-v7106.js → nexowatt-stable-v7108.js} +2 -2
  16. package/build/lib/web.js +3 -0
  17. package/io-package.json +10 -5
  18. package/package.json +16 -12
  19. package/tools/nexowatt-installer-ems-selftest.cjs +44 -0
  20. package/tools/nexowatt-merge-update-selftest.cjs +1 -1
  21. package/tools/nexowatt-role-security-selftest.cjs +19 -6
  22. package/tools/nexowatt-stable-v7103-selftest.cjs +2 -2
  23. package/tools/nexowatt-user-area-selftest.cjs +1 -1
  24. package/tools/nexowatt-v7108-ui-foundation-selftest.cjs +64 -0
  25. package/tools/nexowatt-validate-package.cjs +9 -7
  26. package/INSTALL_TEST_V7.10.6.md +0 -8
  27. package/MERGE_UPDATE_README_V7.10.6.md +0 -7
  28. package/PUBLISH_STABLE_V7.10.6.md +0 -8
  29. package/README_STABILITY_V7.10.6.md +0 -5
  30. package/RELEASE_ACCEPTANCE_V7.10.6.md +0 -11
  31. package/RELEASE_NOTES_V7.10.6.md +0 -14
@@ -32,9 +32,9 @@ const cleanupSource = read('tools/nexowatt-clean-legacy-runtime.cjs');
32
32
  // visible header happened to contain "user". Only authenticated backend policy may define the role.
33
33
  for (const html of [index, sourceIndex]) {
34
34
  assert.doesNotMatch(html, /nexowatt-role-security\.js/i, 'legacy heuristic role guard is still loaded');
35
- assert.match(html, /eos-role-bootstrap\.js\?v=7106/, 'authoritative role bootstrap cache tag is missing');
36
- assert.match(html, /eos-policy-client\.js\?v=7106/, 'authoritative policy client cache tag is missing');
37
- assert.match(html, /eos-role-ui\.js\?v=7106/, 'authoritative role UI cache tag is missing');
35
+ assert.match(html, /eos-role-bootstrap\.js\?v=7108/, 'authoritative role bootstrap cache tag is missing');
36
+ assert.match(html, /eos-policy-client\.js\?v=7108/, 'authoritative policy client cache tag is missing');
37
+ assert.match(html, /eos-role-ui\.js\?v=7108/, 'authoritative role UI cache tag is missing');
38
38
  }
39
39
  assert.equal(fs.existsSync(path.join(root, 'adminWww/nexowatt-role-security.js')), false, 'legacy runtime still exists');
40
40
  assert.equal(fs.existsSync(path.join(root, 'build/lib/eosRoleSecurity.js')), false, 'legacy backend heuristic still exists');
@@ -100,10 +100,23 @@ assert.match(introBundle, /_forceAdmin=_eosAdmin/);
100
100
  assert.doesNotMatch(introSource, /NEXOWATT_EOS_ACCESS_ROLE \|\| 'admin'/, 'Intro source must fail closed while role is unresolved');
101
101
  assert.doesNotMatch(introBundle, /NEXOWATT_EOS_ACCESS_ROLE\|\|"admin"/, 'Intro runtime must fail closed while role is unresolved');
102
102
 
103
- // App Center, License, Simulation and normal account administration are not available to Installer/End User.
103
+ // Installer receives EMS App-Center access only. Simulation and License remain Admin-only;
104
+ // End User remains blocked from all three actions and from inherited port-8188 sessions.
104
105
  for (const token of ['app center', 'app-center', 'appcenter', 'simulation', 'simulator', 'lizenz', 'license']) {
105
106
  assert.ok(roleUi.toLowerCase().includes(token), `role UI is missing protected action ${token}`);
106
107
  }
108
+ for (const code of [roleUi, sourceRoleUi]) {
109
+ assert.match(code, /const privilegedActionKind = element =>/, 'privileged actions are not separated by capability');
110
+ assert.match(code, /if \(action === 'ems'\)/, 'EMS action branch is missing');
111
+ assert.match(code, /state\.role === 'installer' && state\.policy\?\.capabilities\?\.emsAppCenter !== false/, 'Installer EMS App-Center allowance is missing');
112
+ assert.match(code, /return state\.role === 'admin';/, 'Simulation and License must remain Admin-only');
113
+ assert.match(code, /if \(state\.role !== 'enduser'\) return;/, 'port 8188 session scrubbing must be End User-only');
114
+ }
115
+ for (const code of [webSource, webBuilt]) {
116
+ assert.match(code, /emsAppCenter: technical/, 'backend role capabilities do not grant Installer EMS access');
117
+ assert.match(code, /simulation: role === 'admin'/, 'Simulation capability must remain Admin-only');
118
+ assert.match(code, /licenseAdministration: role === 'admin'/, 'License capability must remain Admin-only');
119
+ }
107
120
  assert.match(roleUi, /applyPrivilegedIframePolicy/);
108
121
  assert.match(roleUi, /:8188\/logout\?/);
109
122
  assert.match(roleUi, /route !== 'tab-users'/);
@@ -130,7 +143,7 @@ assert.ok((io.instanceObjects || []).some(object => object?._id === 'info.uiTabs
130
143
  assert.match(drawerSource, /backupAdapters\.has\(adapterName\) && instance\.enabled !== true/);
131
144
  assert.match(builtDrawer, /o\.has\(A\)&&d\.enabled!==!0/);
132
145
 
133
- // 7.10.6 End User cleanup: system information is read-only and object actions disappear only for End User.
146
+ // 7.10.8 End User cleanup: system information is read-only and object actions disappear only for End User.
134
147
  for (const code of [webSource, webBuilt]) {
135
148
  assert.match(code, /nexowatt\/readonly\/system-info/, 'authenticated read-only system-info route is missing');
136
149
  assert.match(code, /authenticationRequired/, 'read-only system-info route must require an authenticated session');
@@ -146,4 +159,4 @@ for (const code of [roleUi, sourceRoleUi]) {
146
159
  }
147
160
  assert.match(sourceMain, /role === 'enduser' && \['readLogs', 'sendToHost'\]\.includes\(command\)/, 'End User technical diagnostics must remain denied');
148
161
 
149
- console.log('[NexoWatt EOS role security] OK (authoritative Admin rights, End User read-only datapoints, protected tools, restart-safe menu storage)');
162
+ console.log('[NexoWatt EOS role security] OK (Admin full rights, Installer EMS App-Center access, End User read-only datapoints, protected Admin tools)');
@@ -31,7 +31,7 @@ const autoUi = read('adminWww/js/eos-auto-update.js');
31
31
  const autoCss = read('adminWww/css/eos-auto-update.css');
32
32
  const autoTag = String(info.autoUpdateCacheTag || info.autoUpdateCacheVersion || info.shellCacheTag || info.shellCacheVersion);
33
33
 
34
- must(pkg.version === '7.10.6' && io.version === '7.10.6' && io.common.version === '7.10.6' && info.version === '7.10.6', 'version drift');
34
+ must(pkg.version === '7.10.8' && io.version === '7.10.8' && io.common.version === '7.10.8' && info.version === '7.10.8', 'version drift');
35
35
  must(io.native.eosRequireFirstLoginPassword === false && io.native.eosRequireFirstLoginPasswordChange === false, 'forced first password still enabled');
36
36
  must(!index.includes('eos-account-management.js'), 'custom reset UI still loaded');
37
37
  must(!boot.includes('installIntegratedFirstLogin(base);') && !boot.includes('showFirstLoginPassword(resolved, base);'), 'forced first-login UI still active');
@@ -49,7 +49,7 @@ must(!autoBackend.includes('extendForeignObjectAsync(this.instanceId'), 'runtime
49
49
  must(web.includes('this.nexowattStableUpdateManager?.stop();'), 'auto-update manager is not stopped with the web server');
50
50
  must(fs.existsSync(path.join(root, 'build/lib/eosRequestSecurity.js')), 'eosRequestSecurity runtime module missing');
51
51
 
52
- // 7.10.4 placement acceptance remains mandatory in 7.10.6: System Settings only.
52
+ // 7.10.4 placement acceptance remains mandatory in 7.10.8: System Settings only.
53
53
  must(index.includes(`eos-auto-update.js?v=${autoTag}`), 'auto-update JavaScript cache key missing');
54
54
  must(index.includes(`eos-auto-update.css?v=${autoTag}`), 'auto-update CSS cache key missing');
55
55
  must(autoUi.includes('[role="dialog"][aria-labelledby="system-settings-dialog-title"]'), 'System Settings selector missing');
@@ -13,7 +13,7 @@ const runtimeRole = read('adminWww/js/eos-role-ui.js');
13
13
  const sourceMain = read('src/main.ts');
14
14
  const builtMain = read('build/main.js');
15
15
 
16
- assert.equal(pkg.version, '7.10.6', 'release must use a new npm version');
16
+ assert.equal(pkg.version, '7.10.8', 'release must use a new npm version');
17
17
  for (const web of [sourceWeb, builtWeb]) {
18
18
  assert.match(web, /nexowatt\/readonly\/system-info/, 'read-only system information endpoint missing');
19
19
  assert.match(web, /sendEosReadonlySystemInfo/, 'read-only system information handler missing');
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const assert = require('node:assert/strict');
5
+ const fs = require('node:fs');
6
+ const path = require('node:path');
7
+
8
+ const root = path.resolve(__dirname, '..');
9
+ const read = relative => fs.readFileSync(path.join(root, relative), 'utf8');
10
+ const json = relative => JSON.parse(read(relative));
11
+
12
+ const pkg = json('package.json');
13
+ const sourceRole = read('src-admin/public/js/eos-role-ui.js');
14
+ const runtimeRole = read('adminWww/js/eos-role-ui.js');
15
+ const sourceBoot = read('src-admin/public/js/eos-role-bootstrap.js');
16
+ const runtimeBoot = read('adminWww/js/eos-role-bootstrap.js');
17
+ const sourceShell = read('src-admin/public/js/nexowatt-native-shell.js');
18
+ const runtimeShell = read('adminWww/js/nexowatt-native-shell.js');
19
+ const sourceCss = read('src-admin/public/css/nexowatt-native-shell.css');
20
+ const runtimeCss = read('adminWww/css/nexowatt-native-shell.css');
21
+ const drawer = read('src-admin/src/components/Drawer.tsx');
22
+ const index = read('adminWww/index.html');
23
+
24
+ assert.equal(pkg.version, '7.10.8', 'UI foundation release must use npm version 7.10.8');
25
+ assert.equal(sourceRole, runtimeRole, 'role source/runtime drift');
26
+ assert.equal(sourceBoot, runtimeBoot, 'bootstrap source/runtime drift');
27
+ assert.equal(sourceShell, runtimeShell, 'shell source/runtime drift');
28
+ assert.equal(sourceCss, runtimeCss, 'shell CSS source/runtime drift');
29
+
30
+ for (const code of [sourceRole, runtimeRole]) {
31
+ assert.match(code, /const isGloballyHiddenTab = tab => normalize\(tab\) === 'tab-enums'/, 'global Structure hide missing');
32
+ assert.match(code, /if \(route === 'easy' \|\| isGloballyHiddenTab\(route\)\) return false;/, 'direct Structure route is not denied');
33
+ assert.match(code, /const isHeaderSystemSettingsButton = button =>/, 'header-only System Settings classifier missing');
34
+ assert.match(code, /clickedButton && isHeaderSystemSettingsButton\(clickedButton\)/, 'service-row wrench/arrow can still be intercepted');
35
+ assert.doesNotMatch(code, /clickedButton && isSystemSettingsButton\(clickedButton\)/, 'broad BuildIcon click interception remains');
36
+ assert.doesNotMatch(code, /\['Struktur'.*tab-enums/s, 'Structure remains in role action definitions');
37
+ }
38
+ for (const code of [sourceBoot, runtimeBoot]) {
39
+ assert.match(code, /!isGloballyHiddenTab\(route\)/, 'bootstrap does not deny Structure globally');
40
+ assert.doesNotMatch(code, /route === 'tab-enums'/, 'End User bootstrap still releases Structure');
41
+ }
42
+ for (const code of [sourceShell, runtimeShell]) {
43
+ assert.match(code, /Dienste & Instanzen/, 'modern Services surface missing');
44
+ assert.match(code, /Datenpunkte & Zustände/, 'modern Datapoints surface missing');
45
+ assert.match(code, /title: 'Systemlogs'/, 'modern System Logs surface missing');
46
+ assert.match(code, /ensureTechnicalSurface\(\)/, 'technical surface is not applied');
47
+ assert.match(code, /eos-log-row-error/, 'log severity decoration missing');
48
+ }
49
+ for (const css of [sourceCss, runtimeCss]) {
50
+ for (const marker of [
51
+ '.eos-technical-surface-header',
52
+ 'html.eos-route-instances',
53
+ 'html.eos-route-objects',
54
+ 'html.eos-route-logs',
55
+ '.eos-log-row-error',
56
+ ]) assert.ok(css.includes(marker), `missing modern CSS marker ${marker}`);
57
+ }
58
+ assert.doesNotMatch(drawer, /'tab-users',\s*'tab-enums'/, 'Structure is still part of readyToUse');
59
+ assert.match(drawer, /tab\.name !== 'tab-enums'/, 'Drawer does not hard-filter Structure');
60
+ assert.match(index, /nexowatt-native-shell\.css\?v=7108/, '7.10.8 CSS cache key missing');
61
+ assert.match(index, /eos-role-ui\.js\?v=7108/, '7.10.8 role cache key missing');
62
+ assert.match(index, /nexowatt-stable-v7108\.js\?v=7108/, '7.10.8 stable runtime missing');
63
+
64
+ console.log('[NexoWatt EOS v7108 UI foundation] OK (modern Services/Datapoints/Logs, Structure hidden, Installer service controls native)');
@@ -45,6 +45,8 @@ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-version-sync-selftes
45
45
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-merge-update-selftest.cjs')) fail('merge update selftest is not part of check:eos-stability');
46
46
  if (pkg.scripts['check:eos-stable-v7103'] !== 'node tools/nexowatt-stable-v7103-selftest.cjs') fail('stable v7103 selftest script is missing or incorrect');
47
47
  if (pkg.scripts['test:eos-auto-update-placement'] !== 'node tools/nexowatt-auto-update-placement-selftest.cjs') fail('auto-update placement selftest script is missing or incorrect');
48
+ if (pkg.scripts['test:eos-installer-ems'] !== 'node tools/nexowatt-installer-ems-selftest.cjs') fail('Installer EMS selftest script is missing or incorrect');
49
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-installer-ems-selftest.cjs')) fail('Installer EMS selftest is not part of check:eos-stability');
48
50
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-auto-update-placement-selftest.cjs')) fail('auto-update placement selftest is not part of check:eos-stability');
49
51
  if (pkg.scripts.prepublishOnly !== canonicalPrepublishOnly) fail('prepublishOnly must use the dependency-free direct-publish workflow');
50
52
  if (/\b(?:tsc|tsx)\b|build:(?:backend|frontend)|\bnpx\b|npm\s+(?:i|install|ci)\b/i.test(pkg.scripts.prepublishOnly || '')) fail('prepublishOnly must not require local development dependencies');
@@ -134,14 +136,14 @@ for (const file of [
134
136
  'LICENSE',
135
137
  'NEXOWATT_PROPRIETARY_LICENSE.md',
136
138
  'THIRD_PARTY_NOTICES.md',
137
- 'README_STABILITY_V7.10.6.md',
138
- 'RELEASE_NOTES_V7.10.6.md',
139
- 'PUBLISH_STABLE_V7.10.6.md',
140
- 'INSTALL_TEST_V7.10.6.md',
141
- 'RELEASE_ACCEPTANCE_V7.10.6.md',
139
+ 'README_STABILITY_V7.10.7.md',
140
+ 'RELEASE_NOTES_V7.10.7.md',
141
+ 'PUBLISH_STABLE_V7.10.7.md',
142
+ 'INSTALL_TEST_V7.10.7.md',
143
+ 'RELEASE_ACCEPTANCE_V7.10.7.md',
142
144
  'MERGE_UPDATE.ps1',
143
145
  'MERGE_UPDATE.cmd',
144
- 'MERGE_UPDATE_README_V7.10.6.md',
146
+ 'MERGE_UPDATE_README_V7.10.7.md',
145
147
  'tools/nexowatt-patch-built-frontend.cjs',
146
148
  'tools/nexowatt-native-shell-selftest.cjs',
147
149
  'tools/nexowatt-clean-legacy-runtime.cjs',
@@ -174,7 +176,7 @@ for (const file of [
174
176
  'tools/nexowatt-ui-overview-runtime-selftest.cjs',
175
177
  'adminWww/js/eos-ems-overview.js',
176
178
  'adminWww/css/eos-ems-overview.css',
177
- 'adminWww/static/js/nexowatt-stable-v7106.js',
179
+ 'adminWww/static/js/nexowatt-stable-v7108.js',
178
180
  'src-admin/src/components/Intro/NexoWattEmsOverview.tsx',
179
181
  'tools/nexowatt-publish-channel-guard.cjs',
180
182
  'tools/nexowatt-publish-channel-selftest.cjs',
@@ -1,8 +0,0 @@
1
- # Installation test 7.10.6
2
-
3
- - Install/update EOS Admin 7.10.6 and verify port 8081 remains reachable.
4
- - Sign in as Admin: datapoints are writable; expert mode can be enabled and disabled; Admin and XTerm overview cards are visible.
5
- - Sign in as Installer: no expert head, ioBroker Admin, XTerm, App Center, License, Simulation or Users/Rights page.
6
- - Sign in as End User: Datapoints tab is visible but every write/edit/delete action is disabled; restricted tools are absent.
7
- - Toggle a navigation item with the pencil: EOS Admin must not restart and `system.config` must remain untouched.
8
- - Disable the backup adapter: its navigation item disappears; re-enable it and the item returns.
@@ -1,7 +0,0 @@
1
- # Merge/update note 7.10.6
2
-
3
- Always replace the previous repository with the complete 7.10.6 repository. Do not merge old `adminWww` bundles or deleted role-security files back into this release. In particular, `nexowatt-role-security.js` and `build/lib/eosRoleSecurity.js` are obsolete and must stay absent.
4
-
5
- After a merge, run the package, stability, role-security and publish dry-run checks before publishing.
6
-
7
- The 7.10.6 publish workflow now removes all three obsolete 7.10.4 role-security files automatically before sealing and packaging, including when the ZIP was extracted over an existing working directory.
@@ -1,8 +0,0 @@
1
- # NPM publication 7.10.6
2
-
3
- 1. Use a freshly extracted repository ZIP.
4
- 2. Run `npm publish --dry-run`.
5
- 3. Confirm version `7.10.6`, complete `build/` runtime and all active `adminWww/assets/*-v84.js` files.
6
- 4. Publish with `npm publish` only after the dry run succeeds.
7
-
8
- No `npm install`, `npm ci`, `tsc` or `tsx` is required for the sealed prebuilt release.
@@ -1,5 +0,0 @@
1
- # NexoWatt EOS Admin 7.10.6 – stability and RBAC baseline
2
-
3
- This release retains the validated 7.10.2–7.10.4 crash, package and update-placement fixes. Role decisions now come exclusively from the authenticated `/nexowatt/security/context` response. The removed heuristic must never be restored.
4
-
5
- Administrator is an unconditional full-rights path. End User datapoints are read-only in both frontend and backend. Menu edits are persisted in an adapter state and must never write `system.config`.
@@ -1,11 +0,0 @@
1
- # Release Acceptance 7.10.6
2
-
3
- - [ ] Admin can write every normally writable datapoint.
4
- - [ ] Admin can enable and disable expert mode repeatedly.
5
- - [ ] Admin sees ioBroker Admin and XTerm overview cards.
6
- - [ ] Installer and End User never see expert mode, ioBroker Admin or XTerm.
7
- - [ ] App Center, License, Simulation and account administration are unavailable to Installer/End User.
8
- - [ ] End User sees Datapoints but cannot write, edit, create or delete.
9
- - [ ] Pencil navigation edits do not restart EOS Admin.
10
- - [ ] Backup navigation follows the enabled state of the backup instance.
11
- - [ ] `npm publish --dry-run` succeeds from a fresh extraction.
@@ -1,14 +0,0 @@
1
- # NexoWatt EOS Admin 7.10.6
2
-
3
- ## Endkundenbereich
4
-
5
- - Die Datenpunktansicht bleibt für Endkunden lesbar, blendet aber Bearbeiten-, Löschen- und Einstellungsaktionen vollständig aus.
6
- - Schreibbefehle bleiben zusätzlich serverseitig gesperrt.
7
- - Die Systeminformationskarte erhält Plattform, RAM, Node.js und NPM über einen authentifizierten Nur-Lese-Endpunkt.
8
- - Der fehlerhafte Info-Dialog mit `permissionError` wird für Endkunden nicht mehr angeboten.
9
- - Administratorrechte und die bestehende Admin-Oberfläche bleiben unverändert und vollständig verfügbar.
10
-
11
- ## Veröffentlichung
12
-
13
- - Neue npm-Version 7.10.6, da 7.10.5 bereits veröffentlicht wurde.
14
- - Release-Dateien, Cache-Tags, Repository-Eintrag und versiegeltes Prebuilt-Artefakt sind auf 7.10.6 synchronisiert.