iobroker.eos-admin 7.10.3 → 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 -36
- package/PUBLISH_STABLE_V7.10.5.md +8 -0
- package/README.md +4 -4
- 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 -14
- 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 +14 -11
- package/io-package.json +31 -9
- package/package.json +14 -11
- 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 +131 -0
- 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.3.md +0 -7
- package/MERGE_UPDATE_README_V7.10.3.md +0 -3
- package/PUBLISH_STABLE_V7.10.3.md +0 -10
- package/README_STABILITY_V7.10.3.md +0 -5
- package/RELEASE_ACCEPTANCE_V7.10.3.md +0 -3
- package/RELEASE_NOTES_V7.10.3.md +0 -7
|
@@ -23,7 +23,7 @@ for (const code of [mainSource, mainBuilt]) {
|
|
|
23
23
|
"LEGACY_BACKUP_ADAPTER_NAME = 'backitup'", 'shouldHideLegacyBackupFromNonAdmins',
|
|
24
24
|
'getLegacyBackupAclObjectIds', 'ensureLegacyBackupVisibleOnlyToAdmins',
|
|
25
25
|
'EOS ACL guard restricted internal', '/^system\\.adapter\\.(?:admin|backitup)(?:\\.|$)/',
|
|
26
|
-
'/^(?:admin|backitup)\\.\\d+(?:\\.|$)/', 'internal Service reserve is Admin/Service-only',
|
|
26
|
+
'/^(?:admin|backitup|xterm)\\.\\d+(?:\\.|$)/', 'internal Service reserve is Admin/Service-only',
|
|
27
27
|
]) if (!code.includes(marker)) fail(`backend reserve marker missing: ${marker}`);
|
|
28
28
|
}
|
|
29
29
|
for (const code of [webSource, webBuilt]) {
|
|
@@ -1,11 +1,11 @@
|
|
|
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 login layout] '+m);process.exit(1)};const must=(v,m)=>{if(!v)fail(m)};
|
|
4
|
-
const css=read('adminWww/css/nexowatt-native-shell.css'),source=read('src-admin/public/css/nexowatt-native-shell.css'),login=read('src-admin/src/login/Login.tsx'),stableLogin=read('adminWww/static/js/nexowatt-stable-login.js'),stable=read(
|
|
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'),source=read('src-admin/public/css/nexowatt-native-shell.css'),login=read('src-admin/src/login/Login.tsx'),stableLogin=read('adminWww/static/js/nexowatt-stable-login.js'),stable=read(`adminWww/static/js/nexowatt-stable-v${shellTag}.js`),index=read('adminWww/index.html');
|
|
5
5
|
must(css===source,'CSS mirror drift');
|
|
6
6
|
for(const marker of ['NexoWatt EOS 7.9.98 – stable scrolling','width: min(456px','width: min(400px','overflow: visible !important'])must(css.includes(marker),`base stable login marker missing: ${marker}`);
|
|
7
7
|
must(login.includes('placeholder={`${I18n.t(\'enterLogin\')} *`}')&&login.includes('placeholder={`${I18n.t(\'enterPassword\')} *`}'),'clean placeholder login missing');
|
|
8
8
|
must(!/data-nw-login-card|createElement\(['"]style/.test(stableLogin),'stable login runtime mutates geometry');
|
|
9
|
-
must(stable.includes(
|
|
10
|
-
must(index.includes(
|
|
9
|
+
must(stable.includes(`VERSION = 'v${shellTag}-scroll-standard-password'`)&&!stable.includes('first-password'),'stable shell runtime incorrect');
|
|
10
|
+
must(index.includes(`nexowatt-stable-v${shellTag}.js?v=${shellTag}`),'current stable login runtime not active');
|
|
11
11
|
console.log('[NexoWatt EOS login layout] OK');
|
|
@@ -16,7 +16,7 @@ for (const file of [
|
|
|
16
16
|
'MERGE_UPDATE.ps1',
|
|
17
17
|
'MERGE_UPDATE.cmd',
|
|
18
18
|
'MERGE_UPDATE.sh',
|
|
19
|
-
'MERGE_UPDATE_README_V7.10.
|
|
19
|
+
'MERGE_UPDATE_README_V7.10.5.md',
|
|
20
20
|
'tools/nexowatt-apply-ems-overview.cjs',
|
|
21
21
|
'tools/nexowatt-sync-release-version.cjs',
|
|
22
22
|
'tools/nexowatt-version-sync-selftest.cjs',
|
|
@@ -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');
|
|
@@ -0,0 +1,131 @@
|
|
|
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');
|
|
36
|
+
}
|
|
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}`);
|
|
46
|
+
}
|
|
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.
|
|
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.3.md
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
# Installationstest 7.10.3
|
|
2
|
-
|
|
3
|
-
1. Version 7.10.3 installieren und EOS Admin starten.
|
|
4
|
-
2. Mindestens 60 Sekunden prüfen, dass kein Start-/Stop-Loop auftritt.
|
|
5
|
-
3. Übersicht und Module öffnen: Die Karte **Automatische Adapter-Updates** darf dort nicht sichtbar sein.
|
|
6
|
-
4. Schraubenschlüssel öffnen: Die Karte muss direkt unter der Kopfleiste der Systemeinstellungen erscheinen.
|
|
7
|
-
5. Schalter einmal deaktivieren und wieder aktivieren; Status und Repository müssen weiter angezeigt werden.
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
# Merge-/Update-Hinweis 7.10.3
|
|
2
|
-
|
|
3
|
-
Für einen reproduzierbaren Stand den bisherigen Arbeitsordner vollständig ersetzen oder die Repository-ZIP in einen leeren Ordner entpacken. Danach `npm publish --dry-run` ausführen. Eine Vermischung mit älteren `adminWww/js/eos-auto-update.js`-Dateien würde die alte globale Platzierung wieder aktivieren und wird durch die Selbsttests blockiert.
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# NPM-Veröffentlichung 7.10.3
|
|
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,5 +0,0 @@
|
|
|
1
|
-
# NexoWatt EOS Admin 7.10.3 – Stabilitätsstand
|
|
2
|
-
|
|
3
|
-
Version 7.10.3 übernimmt die validierten Backend-, Paket- und Restart-Schutzmaßnahmen aus 7.10.2 unverändert. Die sichtbare Karte **Automatische Adapter-Updates** wird ausschließlich im Dialog **Systemeinstellungen** hinter dem Schraubenschlüssel eingebunden. Sie darf weder in der Übersicht noch in Module, Dienste, Datenpunkte oder anderen Hauptseiten erscheinen.
|
|
4
|
-
|
|
5
|
-
Die Browserdateien `src-admin/public/js/eos-auto-update.js` und `adminWww/js/eos-auto-update.js` sowie die zugehörigen CSS-Dateien müssen identisch sein. Der Cache-Schlüssel `7103` erzwingt nach dem Update das Laden der neuen Platzierungslogik.
|
package/RELEASE_NOTES_V7.10.3.md
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
# Release Notes 7.10.3
|
|
2
|
-
|
|
3
|
-
- Automatische NexoWatt-Adapter-Updates aus dem normalen Seiteninhalt entfernt.
|
|
4
|
-
- Update-Karte ausschließlich in **Systemeinstellungen** hinter dem Schraubenschlüssel platziert.
|
|
5
|
-
- Keine Änderung an Stable-Repository, verwalteten Adaptern oder Update-Backendlogik.
|
|
6
|
-
- Eigener Browser-Cache-Schlüssel `7103` verhindert die Verwendung der alten Platzierung.
|
|
7
|
-
- Neuer Placement-Selbsttest verhindert eine spätere Rückkehr auf Übersicht oder Module.
|