iobroker.eos-admin 7.10.4 → 7.10.5
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.
- package/INSTALL_TEST_V7.10.5.md +8 -0
- package/MERGE_UPDATE_README_V7.10.5.md +7 -0
- package/NEXOWATT_EOS_BUILD_INFO.json +22 -18
- package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +37 -39
- package/PUBLISH_STABLE_V7.10.5.md +8 -0
- package/README_STABILITY_V7.10.5.md +5 -0
- package/RELEASE_ACCEPTANCE_V7.10.5.md +11 -0
- package/RELEASE_NOTES_V7.10.5.md +11 -0
- package/SECURITY_ROLE_MATRIX_V7.10.5.md +12 -0
- package/adminWww/assets/Intro-DkwRiz1n-v84.js +2 -2
- package/adminWww/assets/Objects-DPan0bzw-v84.js +1 -1
- package/adminWww/assets/bootstrap-COulQZax-v84.js +2 -2
- package/adminWww/css/nexowatt-native-shell.css +12 -1
- package/adminWww/index.html +14 -15
- package/adminWww/js/eos-role-bootstrap.js +5 -5
- package/adminWww/js/eos-role-ui.js +130 -17
- package/adminWww/js/nexowatt-native-shell.js +1 -1
- package/adminWww/static/js/{nexowatt-stable-v7101.js → nexowatt-stable-v7105.js} +1 -1
- package/build/main.js +13 -15
- package/io-package.json +27 -5
- package/package.json +9 -9
- package/tools/nexowatt-account-password-flow-selftest.cjs +3 -3
- package/tools/nexowatt-clean-legacy-runtime.cjs +6 -0
- package/tools/nexowatt-internal-reserve-selftest.cjs +1 -1
- package/tools/nexowatt-login-layout-selftest.cjs +3 -3
- package/tools/nexowatt-merge-update-selftest.cjs +1 -1
- package/tools/nexowatt-modern-ui-selftest.cjs +2 -2
- package/tools/nexowatt-role-security-selftest.cjs +129 -41
- package/tools/nexowatt-runtime-cleanup-selftest.cjs +4 -0
- package/tools/nexowatt-stable-v7103-selftest.cjs +4 -4
- package/tools/nexowatt-ui-overview-runtime-selftest.cjs +2 -2
- package/tools/nexowatt-validate-package.cjs +9 -8
- package/INSTALL_TEST_V7.10.4.md +0 -9
- package/MERGE_UPDATE_README_V7.10.4.md +0 -3
- package/PUBLISH_STABLE_V7.10.4.md +0 -10
- package/README_STABILITY_V7.10.4.md +0 -12
- package/RELEASE_ACCEPTANCE_V7.10.4.md +0 -3
- package/RELEASE_NOTES_V7.10.4.md +0 -11
- package/adminWww/nexowatt-role-security.js +0 -336
- package/build/lib/eosRoleSecurity.js +0 -310
- package/src-admin/README.md +0 -69
- package/src-admin/nexowatt-role-security.js +0 -336
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
const fs=require('node:fs'),path=require('node:path');const root=path.resolve(__dirname,'..');const read=r=>fs.readFileSync(path.join(root,r),'utf8');const fail=m=>{console.error('[NexoWatt EOS modern UI] '+m);process.exit(1)};const must=(v,m)=>{if(!v)fail(m)};
|
|
4
|
-
const css=read('adminWww/css/nexowatt-native-shell.css'),sourceCss=read('src-admin/public/css/nexowatt-native-shell.css'),index=read('adminWww/index.html'),boot=read('adminWww/js/eos-role-bootstrap.js'),shell=read('adminWww/js/nexowatt-native-shell.js'),role=read('adminWww/js/eos-role-ui.js'),assist=read('adminWww/js/eos-assistant.js');
|
|
4
|
+
const info=JSON.parse(read('NEXOWATT_EOS_BUILD_INFO.json')),shellTag=String(info.shellCacheTag||info.shellCacheVersion);const css=read('adminWww/css/nexowatt-native-shell.css'),sourceCss=read('src-admin/public/css/nexowatt-native-shell.css'),index=read('adminWww/index.html'),boot=read('adminWww/js/eos-role-bootstrap.js'),shell=read('adminWww/js/nexowatt-native-shell.js'),role=read('adminWww/js/eos-role-ui.js'),assist=read('adminWww/js/eos-assistant.js');
|
|
5
5
|
must(css===sourceCss,'CSS source/build drift');
|
|
6
6
|
for(const marker of ['#app-paper','.MuiDialog-paper','.MuiButton-root',':focus-visible','persistent native overview scrolling','eos-overview-edit-controls'])must(css.includes(marker),`CSS marker missing: ${marker}`);
|
|
7
|
-
for(const marker of ['nexowatt-native-shell.css','eos-role-bootstrap.js','eos-auto-update.js'
|
|
7
|
+
for(const marker of ['nexowatt-native-shell.css','eos-role-bootstrap.js','eos-auto-update.js',`nexowatt-stable-v${shellTag}.js`])must(index.includes(marker),`active asset missing: ${marker}`);
|
|
8
8
|
must(!index.includes('eos-account-management.js'),'custom reset asset active');
|
|
9
9
|
must(boot.includes('NEXOWATT_EOS_STANDARD_PASSWORD_MODE')&&!boot.includes('installIntegratedFirstLogin(base);'),'standard login mode missing');
|
|
10
10
|
must(shell.includes('ensureModernOverview'),'modern overview missing');
|
|
@@ -1,43 +1,131 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 index = read('adminWww/index.html');
|
|
13
|
+
const sourceIndex = read('src-admin/index.html');
|
|
14
|
+
const bootstrap = read('adminWww/js/eos-role-bootstrap.js');
|
|
15
|
+
const roleUi = read('adminWww/js/eos-role-ui.js');
|
|
16
|
+
const sourceRoleUi = read('src-admin/public/js/eos-role-ui.js');
|
|
17
|
+
const sourceMain = read('src/main.ts');
|
|
18
|
+
const builtMain = read('build/main.js');
|
|
19
|
+
const appSource = read('src-admin/src/App.tsx');
|
|
20
|
+
const objectsSource = read('src-admin/src/tabs/Objects.tsx');
|
|
21
|
+
const introSource = read('src-admin/src/tabs/Intro.tsx');
|
|
22
|
+
const drawerSource = read('src-admin/src/components/Drawer.tsx');
|
|
23
|
+
const bootstrapBundle = read('adminWww/assets/bootstrap-COulQZax-v84.js');
|
|
24
|
+
const objectsBundle = read('adminWww/assets/Objects-DPan0bzw-v84.js');
|
|
25
|
+
const introBundle = read('adminWww/assets/Intro-DkwRiz1n-v84.js');
|
|
26
|
+
const io = json('io-package.json');
|
|
27
|
+
const cleanupSource = read('tools/nexowatt-clean-legacy-runtime.cjs');
|
|
28
|
+
|
|
29
|
+
// The removed DOM-text heuristic classified a real administrator as end user when the
|
|
30
|
+
// visible header happened to contain "user". Only authenticated backend policy may define the role.
|
|
31
|
+
for (const html of [index, sourceIndex]) {
|
|
32
|
+
assert.doesNotMatch(html, /nexowatt-role-security\.js/i, 'legacy heuristic role guard is still loaded');
|
|
33
|
+
assert.match(html, /eos-role-bootstrap\.js\?v=7105/, 'authoritative role bootstrap cache tag is missing');
|
|
34
|
+
assert.match(html, /eos-policy-client\.js\?v=7105/, 'authoritative policy client cache tag is missing');
|
|
35
|
+
assert.match(html, /eos-role-ui\.js\?v=7105/, 'authoritative role UI cache tag is missing');
|
|
34
36
|
}
|
|
35
|
-
|
|
36
|
-
assert.
|
|
37
|
-
assert.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
assert.equal(fs.existsSync(path.join(root, 'adminWww/nexowatt-role-security.js')), false, 'legacy runtime still exists');
|
|
38
|
+
assert.equal(fs.existsSync(path.join(root, 'build/lib/eosRoleSecurity.js')), false, 'legacy backend heuristic still exists');
|
|
39
|
+
assert.doesNotMatch(builtMain, /eosRoleSecurity|installHttpGuard|enforceRoleAcls/);
|
|
40
|
+
for (const obsolete of [
|
|
41
|
+
'adminWww/nexowatt-role-security.js',
|
|
42
|
+
'src-admin/nexowatt-role-security.js',
|
|
43
|
+
'build/lib/eosRoleSecurity.js',
|
|
44
|
+
]) {
|
|
45
|
+
assert.ok(cleanupSource.includes(`'${obsolete}'`), `runtime cleanup must remove stale ${obsolete}`);
|
|
42
46
|
}
|
|
43
|
-
|
|
47
|
+
for (const code of [bootstrap, roleUi, sourceRoleUi]) {
|
|
48
|
+
assert.match(code, /policy\?\.user === 'system\.user\.admin'/, 'system.user.admin is not explicitly authoritative');
|
|
49
|
+
assert.match(code, /policy\?\.isAdministrator/, 'backend administrator capability is not honored');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Admin is the unconditional full-rights bypass. Restrictions below this branch must never run for Admin.
|
|
53
|
+
for (const code of [sourceMain, builtMain]) {
|
|
54
|
+
const bypass = code.indexOf("if (role === 'admin')");
|
|
55
|
+
const endUserWriteDeny = code.indexOf('end-user datapoints are read-only in EOS Admin');
|
|
56
|
+
assert.ok(bypass >= 0 && endUserWriteDeny > bypass, 'Admin socket bypass must precede all restricted-role rules');
|
|
57
|
+
assert.match(code, /password administration is Service-only/);
|
|
58
|
+
assert.match(code, /\.info\.uiTabsVisible/);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Expert mode is an Admin-only control, but the administrator can freely toggle both directions.
|
|
62
|
+
assert.match(appSource, /const isEosAdministrator = \(\): boolean => \['admin', 'service'\]\.includes/);
|
|
63
|
+
assert.match(appSource, /newState\.expertMode = isEosAdministrator\(\)/);
|
|
64
|
+
assert.match(appSource, /data-eos-expert-control="1"/);
|
|
65
|
+
assert.match(appSource, /this\.setState\(\{ expertMode: !this\.state\.expertMode \}\)/);
|
|
66
|
+
assert.match(bootstrapBundle, /"data-eos-expert-control":"1"/);
|
|
67
|
+
assert.match(bootstrapBundle, /l\.expertMode=\["admin","service"\]\.includes\(String\(window\.NEXOWATT_EOS_ACCESS_ROLE/);
|
|
68
|
+
assert.match(bootstrapBundle, /c\?jsxRuntimeExports\.jsx\(IsVisible,\{name:"admin\.appBar\.expertMode"/);
|
|
69
|
+
assert.match(bootstrapBundle, /:null,c&&this\.state\.expertMode\?jsxRuntimeExports\.jsx/);
|
|
70
|
+
assert.match(roleUi, /if \(state\.role === 'admin'\) return false;/, 'Admin expert-mode cleanup must be a no-op');
|
|
71
|
+
assert.match(roleUi, /if \(state\.role === 'admin' \|\| state\.role === 'unknown'\) return;/, 'Admin click handling must not be intercepted');
|
|
72
|
+
|
|
73
|
+
// Datapoints: Admin/Installer retain native write support; only End User is read-only.
|
|
74
|
+
assert.match(objectsSource, /const readOnly = eosRole === 'enduser'/);
|
|
75
|
+
for (const marker of [
|
|
76
|
+
'enableStateValueEdit={!readOnly}',
|
|
77
|
+
'objectEditBoolean={!readOnly}',
|
|
78
|
+
'objectAddBoolean={!readOnly}',
|
|
79
|
+
'objectImportExport={!readOnly}',
|
|
80
|
+
'objectEditOfAccessControl={!readOnly}',
|
|
81
|
+
]) assert.ok(objectsSource.includes(marker), `Objects source missing ${marker}`);
|
|
82
|
+
assert.match(objectsBundle, /_eosReadOnly=_eosRole==="enduser"/);
|
|
83
|
+
for (const marker of [
|
|
84
|
+
'enableStateValueEdit:!_eosReadOnly',
|
|
85
|
+
'objectEditBoolean:!_eosReadOnly',
|
|
86
|
+
'objectAddBoolean:!_eosReadOnly',
|
|
87
|
+
'objectImportExport:!_eosReadOnly',
|
|
88
|
+
'objectEditOfAccessControl:!_eosReadOnly',
|
|
89
|
+
]) assert.ok(objectsBundle.includes(marker), `Objects runtime missing ${marker}`);
|
|
90
|
+
assert.match(bootstrap, /route === 'tab-objects'/, 'End User datapoint route is not released');
|
|
91
|
+
assert.match(roleUi, /clean === 'tab-objects'/, 'End User datapoint route is not released in runtime UI policy');
|
|
92
|
+
|
|
93
|
+
// The Admin and XTerm cards stay visible for Admin and are removed only for non-admin roles.
|
|
94
|
+
assert.match(introSource, /if \(!isAdministrator && \/\^\(\?:admin\|xterm\)/);
|
|
95
|
+
assert.match(introSource, /forceVisibleAdminCard = isAdministrator/);
|
|
96
|
+
assert.match(introBundle, /if\(!_eosAdmin&&\/\^\(\?:admin\|xterm\)/);
|
|
97
|
+
assert.match(introBundle, /_forceAdmin=_eosAdmin/);
|
|
98
|
+
assert.doesNotMatch(introSource, /NEXOWATT_EOS_ACCESS_ROLE \|\| 'admin'/, 'Intro source must fail closed while role is unresolved');
|
|
99
|
+
assert.doesNotMatch(introBundle, /NEXOWATT_EOS_ACCESS_ROLE\|\|"admin"/, 'Intro runtime must fail closed while role is unresolved');
|
|
100
|
+
|
|
101
|
+
// App Center, License, Simulation and normal account administration are not available to Installer/End User.
|
|
102
|
+
for (const token of ['app center', 'app-center', 'appcenter', 'simulation', 'simulator', 'lizenz', 'license']) {
|
|
103
|
+
assert.ok(roleUi.toLowerCase().includes(token), `role UI is missing protected action ${token}`);
|
|
104
|
+
}
|
|
105
|
+
assert.match(roleUi, /applyPrivilegedIframePolicy/);
|
|
106
|
+
assert.match(roleUi, /:8188\/logout\?/);
|
|
107
|
+
assert.match(roleUi, /route !== 'tab-users'/);
|
|
108
|
+
assert.match(bootstrap, /tab-users\|tab-hosts\|tab-files/);
|
|
109
|
+
|
|
110
|
+
// Pencil/menu edits must not touch system.config (which restarts the running adapter).
|
|
111
|
+
const drawerMethod = drawerSource.slice(
|
|
112
|
+
drawerSource.indexOf('async getTabs(update?: boolean)'),
|
|
113
|
+
drawerSource.indexOf('getNavigationItems(): JSX.Element[]'),
|
|
114
|
+
);
|
|
115
|
+
assert.match(drawerSource, /info\.uiTabsVisible/);
|
|
116
|
+
assert.match(drawerMethod, /socket\.setState/);
|
|
117
|
+
assert.doesNotMatch(drawerMethod, /setSystemConfig|getSystemConfig\(/);
|
|
118
|
+
const builtDrawer = bootstrapBundle.slice(
|
|
119
|
+
bootstrapBundle.indexOf('async getTabs(e){'),
|
|
120
|
+
bootstrapBundle.indexOf('getNavigationItems(){', bootstrapBundle.indexOf('async getTabs(e){')),
|
|
121
|
+
);
|
|
122
|
+
assert.match(builtDrawer, /info\.uiTabsVisible/);
|
|
123
|
+
assert.match(builtDrawer, /socket\.setState/);
|
|
124
|
+
assert.doesNotMatch(builtDrawer, /setSystemConfig|getSystemConfig\(/);
|
|
125
|
+
assert.ok((io.instanceObjects || []).some(object => object?._id === 'info.uiTabsVisible'), 'navigation state object missing');
|
|
126
|
+
|
|
127
|
+
// Backup navigation is emitted only for an actually enabled instance.
|
|
128
|
+
assert.match(drawerSource, /backupAdapters\.has\(adapterName\) && instance\.enabled !== true/);
|
|
129
|
+
assert.match(builtDrawer, /o\.has\(A\)&&d\.enabled!==!0/);
|
|
130
|
+
|
|
131
|
+
console.log('[NexoWatt EOS role security] OK (authoritative Admin rights, End User read-only datapoints, protected tools, restart-safe menu storage)');
|
|
@@ -15,6 +15,7 @@ try {
|
|
|
15
15
|
fs.mkdirSync(path.join(temp, 'src-admin', 'public', 'js'), { recursive: true });
|
|
16
16
|
fs.mkdirSync(path.join(temp, 'src-admin', 'public', 'static', 'js'), { recursive: true });
|
|
17
17
|
fs.mkdirSync(path.join(temp, 'adminWww', 'static', 'js'), { recursive: true });
|
|
18
|
+
fs.mkdirSync(path.join(temp, 'build', 'lib'), { recursive: true });
|
|
18
19
|
fs.writeFileSync(path.join(temp, 'NEXOWATT_EOS_BUILD_INFO.json'), JSON.stringify({ runtimeEntry: 'v82', shellCacheVersion: 98 }));
|
|
19
20
|
|
|
20
21
|
const keep = [
|
|
@@ -36,6 +37,9 @@ try {
|
|
|
36
37
|
'src-admin/public/js/eos-security-ui.js',
|
|
37
38
|
'adminWww/static/js/nexowatt-stable-v97.js',
|
|
38
39
|
'src-admin/public/static/js/nexowatt-stable-v95.js',
|
|
40
|
+
'adminWww/nexowatt-role-security.js',
|
|
41
|
+
'src-admin/nexowatt-role-security.js',
|
|
42
|
+
'build/lib/eosRoleSecurity.js',
|
|
39
43
|
];
|
|
40
44
|
for (const rel of [...keep, ...remove]) {
|
|
41
45
|
const file = path.join(temp, rel);
|
|
@@ -25,18 +25,18 @@ const index = read('adminWww/index.html');
|
|
|
25
25
|
const ems = read('adminWww/js/eos-ems-overview.js');
|
|
26
26
|
const intro = read('src-admin/src/tabs/Intro.tsx');
|
|
27
27
|
const bundle = read('adminWww/assets/Intro-DkwRiz1n-v84.js');
|
|
28
|
-
const stable = read(
|
|
28
|
+
const stable = read(`adminWww/static/js/nexowatt-stable-v${String(info.shellCacheTag || info.shellCacheVersion)}.js`);
|
|
29
29
|
const autoBackend = read('src/lib/eosAutoUpdate.ts');
|
|
30
30
|
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.
|
|
34
|
+
must(pkg.version === '7.10.5' && io.version === '7.10.5' && io.common.version === '7.10.5' && info.version === '7.10.5', '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');
|
|
38
38
|
must(main.includes('standardPasswordMode: true') && main.includes('nexowattPasswordChangeRequired: false'), 'account migration missing');
|
|
39
|
-
must(role.includes("route
|
|
39
|
+
must(role.includes("route !== 'tab-users'") && main.includes("command === 'changePassword'") && main.includes('password administration is Service-only'), 'non-admin account/password administration guard missing');
|
|
40
40
|
must(css.includes('persistent native overview scrolling') && stable.includes("overflow-y','scroll"), 'persistent scroll missing');
|
|
41
41
|
must(intro.includes('eos-overview-edit-controls') && bundle.includes('eos-overview-edit-controls'), 'edit control not in bottom grid');
|
|
42
42
|
must(!ems.includes('Vollständige EMS-Diagnose öffnen'), 'unsupported EMS link remains');
|
|
@@ -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: System Settings only.
|
|
52
|
+
// 7.10.4 placement acceptance remains mandatory in 7.10.5: 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');
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
const fs=require('node:fs');const path=require('node:path');const root=path.resolve(__dirname,'..');const read=rel=>fs.readFileSync(path.join(root,rel),'utf8');const fail=msg=>{console.error(`[NexoWatt EOS UI overview runtime] ${msg}`);process.exit(1)};
|
|
4
|
-
const runtime=read('adminWww/js/eos-ems-overview.js');const source=read('src-admin/public/js/eos-ems-overview.js');const css=read('adminWww/css/eos-ems-overview.css');const index=read('adminWww/index.html');const role=read('adminWww/js/eos-role-ui.js');const shell=read('adminWww/js/nexowatt-native-shell.js');const intro=read('src-admin/src/tabs/Intro.tsx');const introBundle=read('adminWww/assets/Intro-DkwRiz1n-v84.js');const bootstrap=read('adminWww/assets/bootstrap-COulQZax-v84.js');const generic=read('adminWww/assets/index-D2ymscJA-v84.js');
|
|
4
|
+
const info=JSON.parse(read('NEXOWATT_EOS_BUILD_INFO.json')),shellTag=String(info.shellCacheTag||info.shellCacheVersion);const runtime=read('adminWww/js/eos-ems-overview.js');const source=read('src-admin/public/js/eos-ems-overview.js');const css=read('adminWww/css/eos-ems-overview.css');const index=read('adminWww/index.html');const role=read('adminWww/js/eos-role-ui.js');const shell=read('adminWww/js/nexowatt-native-shell.js');const intro=read('src-admin/src/tabs/Intro.tsx');const introBundle=read('adminWww/assets/Intro-DkwRiz1n-v84.js');const bootstrap=read('adminWww/assets/bootstrap-COulQZax-v84.js');const generic=read('adminWww/assets/index-D2ymscJA-v84.js');
|
|
5
5
|
if(runtime!==source)fail('runtime source/build drift');
|
|
6
6
|
if(runtime.includes('Vollständige EMS-Diagnose öffnen'))fail('unsupported EMS link remains');
|
|
7
7
|
for(const marker of ['nexowatt-ems-overview-v1','nexowatt-ui.*.info.adminOverview.*','system.adapter.nexowatt-ui.*.alive','POLL_MS = 5000','STALE_MS = 20000',"REQUIRED_UI_VERSION = '0.8.198'",'getForeignStates','Keine Kachel besitzt Schreibhoheit','currentDecisions','§14a-Fallback','nexowatt-eos-admin-socket-ready','readUiAdapterInfo','socketFromReact'])if(!runtime.includes(marker))fail(`runtime marker missing: ${marker}`);
|
|
8
8
|
for(const forbidden of ['setForeignState','setState(','sendToHost','writeFile','extendObject'])if(runtime.includes(forbidden))fail(`read-only runtime contains ${forbidden}`);
|
|
9
|
-
for(const marker of [
|
|
9
|
+
for(const marker of [`eos-ems-overview.css?v=${shellTag}`,`eos-ems-overview.js?v=${shellTag}`,`nexowatt-stable-v${shellTag}.js?v=${shellTag}`])if(!index.includes(marker))fail(`index marker missing: ${marker}`);
|
|
10
10
|
if(!css.includes('#eos-ems-overview-runtime')||!css.includes('.eos-ems-overview-metrics')||!css.includes('startup and compatibility messages stay compact'))fail('EMS card CSS incomplete');
|
|
11
11
|
if(role.includes('overview.innerHTML = `')||!role.includes('never cover the real Admin Intro'))fail('obsolete role overview still active');
|
|
12
12
|
if(!shell.includes("label: 'Installateur'")||!shell.includes("label: 'Endkunde'")||!shell.includes('eosNativeReactOverview'))fail('native overview role bridge incomplete');
|
|
@@ -68,6 +68,7 @@ if (io.native?.nexowattHideLegacyBackupFromNonAdmins !== true) fail('NexoWatt ba
|
|
|
68
68
|
const instanceObjectIds = new Set((io.instanceObjects || []).map(object => object?._id));
|
|
69
69
|
if (!instanceObjectIds.has('info.nexowattStableUpdatesEnabled')) fail('restart-safe auto-update enabled state is missing');
|
|
70
70
|
if (!instanceObjectIds.has('info.nexowattStableUpdatesState')) fail('restart-safe auto-update runtime state is missing');
|
|
71
|
+
if (!instanceObjectIds.has('info.uiTabsVisible')) fail('restart-safe navigation state info.uiTabsVisible is missing');
|
|
71
72
|
for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
|
|
72
73
|
if (JSON.stringify(pkgLock.packages?.['']?.[key]) !== JSON.stringify(pkg[key])) {
|
|
73
74
|
fail(`package-lock root ${key} must match package.json`);
|
|
@@ -133,14 +134,14 @@ for (const file of [
|
|
|
133
134
|
'LICENSE',
|
|
134
135
|
'NEXOWATT_PROPRIETARY_LICENSE.md',
|
|
135
136
|
'THIRD_PARTY_NOTICES.md',
|
|
136
|
-
'README_STABILITY_V7.10.
|
|
137
|
-
'RELEASE_NOTES_V7.10.
|
|
138
|
-
'PUBLISH_STABLE_V7.10.
|
|
139
|
-
'INSTALL_TEST_V7.10.
|
|
140
|
-
'RELEASE_ACCEPTANCE_V7.10.
|
|
137
|
+
'README_STABILITY_V7.10.5.md',
|
|
138
|
+
'RELEASE_NOTES_V7.10.5.md',
|
|
139
|
+
'PUBLISH_STABLE_V7.10.5.md',
|
|
140
|
+
'INSTALL_TEST_V7.10.5.md',
|
|
141
|
+
'RELEASE_ACCEPTANCE_V7.10.5.md',
|
|
141
142
|
'MERGE_UPDATE.ps1',
|
|
142
143
|
'MERGE_UPDATE.cmd',
|
|
143
|
-
'MERGE_UPDATE_README_V7.10.
|
|
144
|
+
'MERGE_UPDATE_README_V7.10.5.md',
|
|
144
145
|
'tools/nexowatt-patch-built-frontend.cjs',
|
|
145
146
|
'tools/nexowatt-native-shell-selftest.cjs',
|
|
146
147
|
'tools/nexowatt-clean-legacy-runtime.cjs',
|
|
@@ -173,7 +174,7 @@ for (const file of [
|
|
|
173
174
|
'tools/nexowatt-ui-overview-runtime-selftest.cjs',
|
|
174
175
|
'adminWww/js/eos-ems-overview.js',
|
|
175
176
|
'adminWww/css/eos-ems-overview.css',
|
|
176
|
-
'adminWww/static/js/nexowatt-stable-
|
|
177
|
+
'adminWww/static/js/nexowatt-stable-v7105.js',
|
|
177
178
|
'src-admin/src/components/Intro/NexoWattEmsOverview.tsx',
|
|
178
179
|
'tools/nexowatt-publish-channel-guard.cjs',
|
|
179
180
|
'tools/nexowatt-publish-channel-selftest.cjs',
|
|
@@ -219,7 +220,7 @@ if (!index.includes(`eos-auto-update.css?v=${autoUpdateTag}`)) fail('auto-update
|
|
|
219
220
|
if (!index.includes(`eos-assistant.js?v=${shellTag}`)) fail('EOS Assist cache key mismatch');
|
|
220
221
|
if (!index.includes(`eos-ems-overview.js?v=${shellTag}`)) fail('EMS overview cache key mismatch');
|
|
221
222
|
if (!index.includes(`eos-ems-overview.css?v=${shellTag}`)) fail('EMS overview CSS cache key mismatch');
|
|
222
|
-
if (!index.includes(`nexowatt-stable-
|
|
223
|
+
if (!index.includes(`nexowatt-stable-v${shellTag}.js?v=${shellTag}`)) fail('stable shell overlay cache key mismatch');
|
|
223
224
|
if (index.indexOf(`eos-manual-write-policy.js?v=${shellTag}`) > index.indexOf(`hostInit-${runtime}.js?v=${runtimeNumber}`)) fail('manual-write policy must load before the React runtime');
|
|
224
225
|
if (!index.includes('class="eos-native-shell"')) fail('native NexoWatt shell class missing');
|
|
225
226
|
for (const legacy of ['eos-branding.js', 'eos-security-ui.js', 'eos-console-quiet.js', 'eos-objects-state-tools.js']) {
|
package/INSTALL_TEST_V7.10.4.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Installationstest 7.10.4
|
|
2
|
-
|
|
3
|
-
1. Version 7.10.4 in einem neuen Arbeitsordner veröffentlichen bzw. installieren.
|
|
4
|
-
2. EOS Admin mindestens 60 Sekunden ohne Start-/Stop-Schleife beobachten.
|
|
5
|
-
3. Als Administrator App-Center, Lizenz, Simulation, Benutzer/Rechte, Expertenmodus, ioBroker Admin und XTerm prüfen.
|
|
6
|
-
4. Als Installateur müssen diese Bereiche vollständig fehlen bzw. bei direktem Aufruf gesperrt sein.
|
|
7
|
-
5. Als Endkunde müssen Datenpunkte sichtbar, aber nicht beschreibbar sein; Benutzer/Rechte und Passwortverwaltung dürfen nicht erreichbar sein.
|
|
8
|
-
6. Backup-Instanz deaktivieren: der Navigationspunkt Sicherung muss verschwinden. Backup-Instanz aktivieren: der Punkt muss wieder erscheinen.
|
|
9
|
-
7. Systemeinstellungen öffnen: die Karte Automatische Adapter-Updates darf nur dort sichtbar sein.
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
# Merge-/Update-Hinweis 7.10.4
|
|
2
|
-
|
|
3
|
-
Den bisherigen Arbeitsordner vollständig ersetzen oder die Repository-ZIP in einen leeren Ordner entpacken. Nicht über eine ältere Version kopieren, weil veraltete Browser-Bundles, Rollen-Skripte oder Paket-Lifecycle-Einträge sonst bestehen bleiben können. Danach zuerst `npm publish --dry-run` ausführen.
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# NPM-Veröffentlichung 7.10.4
|
|
2
|
-
|
|
3
|
-
Aus einer frisch entpackten Repository-ZIP ausführen:
|
|
4
|
-
|
|
5
|
-
```powershell
|
|
6
|
-
npm publish --dry-run
|
|
7
|
-
npm publish
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
Der Publish-Workflow ist dependency-frei und darf weder `tsc`, `tsx`, `npm install` noch einen verschachtelten `npm pack`-Prozess verlangen.
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# NexoWatt EOS Admin 7.10.4 – Stabilitäts- und Sicherheitsstand
|
|
2
|
-
|
|
3
|
-
Version 7.10.4 baut auf dem absturz- und publish-sicheren Stand 7.10.3 auf. Die automatische Update-Karte bleibt ausschließlich in den Systemeinstellungen hinter dem Schraubenschlüssel.
|
|
4
|
-
|
|
5
|
-
Zusätzlich gilt eine rollenbasierte Sicherheitsgrenze:
|
|
6
|
-
|
|
7
|
-
- Administrator: vollständiger Zugriff einschließlich App-Center, Lizenz, Simulation, Expertenmodus, Benutzer/Rechte, ioBroker Admin und XTerm.
|
|
8
|
-
- Installateur: technische Bedienoberfläche ohne App-Center, Lizenz, Simulation, Expertenmodus, Benutzer/Rechte, ioBroker Admin und XTerm.
|
|
9
|
-
- Endkunde: Cockpit, Smart Home und Datenpunkte mit Nur-Lesezugriff; keine Schreib-, Rechte-, Passwort- oder Expertenfunktionen.
|
|
10
|
-
- Sicherung: Navigation nur bei installierter und aktivierter Backup-Instanz.
|
|
11
|
-
|
|
12
|
-
Die Sperren werden nicht nur optisch, sondern zusätzlich im EOS-HTTP-Guard und über die Endkunden-ACLs durchgesetzt.
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
# Release Acceptance 7.10.4
|
|
2
|
-
|
|
3
|
-
Akzeptiert, wenn Paketvalidierung, Stabilitätstests, Prebuilt-Manifest, Backend-Runtime, Rollen-Selbsttest und `npm publish --dry-run` erfolgreich sind. Zusätzlich müssen Administrator-, Installateur- und Endkundenrechte im Feldtest der dokumentierten Rollenmatrix entsprechen.
|
package/RELEASE_NOTES_V7.10.4.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Release Notes 7.10.4
|
|
2
|
-
|
|
3
|
-
- App-Center, Lizenzverwaltung und Simulation auf Administratoren begrenzt.
|
|
4
|
-
- Expertenmodus und Expertenkopf für Installateur und Endkunde entfernt.
|
|
5
|
-
- Benutzer-, Gruppen-, Rechte- und Passwortverwaltung für Nicht-Administratoren gesperrt.
|
|
6
|
-
- ioBroker Admin und XTerm für Installateur und Endkunde ausgeblendet und serverseitig abgefangen.
|
|
7
|
-
- Endkunden-Datenpunkte sichtbar, aber nur lesbar; Schreibaufrufe werden blockiert.
|
|
8
|
-
- Sicherungsnavigation nur bei aktiver Backup-Instanz.
|
|
9
|
-
- Bereits bestehende privilegierte UI-Sitzungen werden bei Nicht-Administratoren nicht weiterverwendet.
|
|
10
|
-
- Update-Karte weiterhin ausschließlich unter Systemeinstellungen.
|
|
11
|
-
- Absturz-, Runtime- und dependency-freier NPM-Publish-Schutz aus 7.10.2/7.10.3 beibehalten.
|