Verify configuration scope without outbound-network assumptions

Use a well-formed local-login fixture for system-settings normalisation, make the existing outbound-IP coverage deterministic through its existing dial seam, and finish the copy audit with fresh inspected browser evidence.

Contract-Neutral: No runtime or archive contract changes. Existing tests now run offline without a real route, and the migration warning uses the required copy style.
Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-10-03 16:12:47 +01:00
parent 73d2c64e0f
commit 26c64634f0
5 changed files with 31 additions and 10 deletions
@@ -127,7 +127,7 @@ const { chromium, webkit } = require('playwright');
const files = ['frontend-modern/src/components/Settings/BackupTransferDialogs.tsx',
'frontend-modern/public/docs/MIGRATION.md', 'frontend-modern/public/docs/UNIFIED_AGENT.md'];
const result = { result: 'passed', playwrightVersion: require('playwright/package.json').version,
baseSha: 'b62042798c7c9b326408dd5532d7fa330d6bb089',
baseSha: '73d2c64e0f5bce57f3a1dc6f9e055b4784e079bd',
scope: 'Real dialog/flow/production Docs rendering with synthetic API; no native migration or shipment',
contentSha256: Object.fromEntries(files.map((file) => [file,
createHash('sha256').update(fs.readFileSync(path.join(workspace, file))).digest('hex')])), observations };
+4 -4
View File
@@ -1,13 +1,13 @@
{
"version": 1,
"result": "passed",
"base_sha": "b62042798c7c9b326408dd5532d7fa330d6bb089",
"verified_at": "2026-10-03T14:52:51.979841Z",
"base_sha": "73d2c64e0f5bce57f3a1dc6f9e055b4784e079bd",
"verified_at": "2026-10-03T15:12:03.997980Z",
"changed_paths": [
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx"
],
"content_sha256": {
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx": "f07fb69d5bd6b185d0e156d7affcf7d5f5fa78418b3f82dd776d49afbceb9341"
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx": "668a53d0741316c9353848ce0b1d5fae917db9ce5053ea43c6fb100d76e32cc4"
},
"routes": [
"/settings/system/recovery (real transfer dialog/flow harness)",
@@ -64,7 +64,7 @@
],
"playwright_version": "1.56.1",
"shipped_asset_sha256": {
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx": "f07fb69d5bd6b185d0e156d7affcf7d5f5fa78418b3f82dd776d49afbceb9341",
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx": "668a53d0741316c9353848ce0b1d5fae917db9ce5053ea43c6fb100d76e32cc4",
"frontend-modern/public/docs/MIGRATION.md": "ad4b5a4b07af44e1657f9512ef468a578b8b5957b9b115a30816824bbd8300e9",
"frontend-modern/public/docs/UNIFIED_AGENT.md": "61a15c9651223ac26f4ca900f5731534f03abf96abfd233c47bf034c2796fc05"
},
@@ -295,7 +295,7 @@ export const BackupTransferDialogs: Component<BackupTransferDialogsProps> = (pro
<p>
<strong>Warning:</strong> Import replaces the included settings and API-token
records, not the whole installation. Back up the destination first. History and
excluded settings are not restored; check the{' '}
excluded settings are not restored. Check the{' '}
<a
href={getShippedDocUrl('MIGRATION.md')}
target="_blank"
+14 -3
View File
@@ -2,6 +2,7 @@ package config
import (
"encoding/base64"
"net"
"os"
"path/filepath"
"testing"
@@ -48,9 +49,19 @@ func TestLoad_GuestMetadataOverrides(t *testing.T) {
}
func TestLoad_OutboundIP(t *testing.T) {
// Calling getOutboundIP for coverage
ip := getOutboundIP()
assert.NotEmpty(t, ip)
// An offline proof guest need not have an outbound route. Exercise the
// existing dial seam, rather than making coverage depend on that route.
original := netDial
t.Cleanup(func() { netDial = original })
calls := 0
netDial = func(network, address string) (net.Conn, error) {
calls++
require.Equal(t, "udp", network)
require.Equal(t, "8.8.8.8:80", address)
return &mockConn{localAddr: &net.UDPAddr{IP: net.ParseIP("192.0.2.44")}}, nil
}
require.Equal(t, "192.0.2.44", getOutboundIP())
require.Equal(t, 1, calls)
}
func TestLoad_Errors(t *testing.T) {
+11 -1
View File
@@ -37,11 +37,17 @@ func TestConfigurationMigrationArchiveScope(t *testing.T) {
// Excluded state exists at both ends. Import must not pretend to transfer it
// or overwrite the destination's excluded files. These are inert sentinels,
// not live databases, credentials or operational agent records.
excluded := []string{".env", "metrics.db", "audit.db", "host_agents.json", "agent_profiles.json", "rbac_roles.json", "license.enc"}
excluded := []string{"metrics.db", "audit.db", "host_agents.json", "agent_profiles.json", "rbac_roles.json", "license.enc"}
for _, name := range excluded {
require.NoError(t, os.WriteFile(filepath.Join(sourceDir, name), []byte("synthetic-source-only"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(targetDir, name), []byte("synthetic-destination-only"), 0600))
}
// Saving imported system settings can normalise .env whitespace. Use a
// well-formed local login override and verify its value is not transferred.
const sourceEnv = "PULSE_AUTH_USER=synthetic-source-admin\n"
const targetEnv = "PULSE_AUTH_USER=synthetic-destination-admin\n"
require.NoError(t, os.WriteFile(filepath.Join(sourceDir, ".env"), []byte(sourceEnv), 0600))
require.NoError(t, os.WriteFile(filepath.Join(targetDir, ".env"), []byte(targetEnv), 0600))
sourceKey, err := os.ReadFile(filepath.Join(sourceDir, ".encryption.key"))
require.NoError(t, err)
targetKey, err := os.ReadFile(filepath.Join(targetDir, ".encryption.key"))
@@ -63,6 +69,7 @@ func TestConfigurationMigrationArchiveScope(t *testing.T) {
require.ElementsMatch(t, []string{"version", "exportedAt", "nodes", "alerts", "alertIntentPolicies", "email", "webhooks", "apprise", "deadMan", "system", "sso", "apiTokens"}, rawKeys(payload))
require.NotContains(t, string(plaintext), "synthetic-nas-secret")
require.NotContains(t, string(plaintext), "synthetic-source-only")
require.NotContains(t, string(plaintext), "synthetic-source-admin")
require.Contains(t, string(plaintext), "synthetic-sso-secret")
baseline := []PVEInstance{{Name: "destination-before", Host: "https://before.example:8006"}}
@@ -97,6 +104,9 @@ func TestConfigurationMigrationArchiveScope(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "synthetic-destination-only", string(data), name)
}
localLogin, err := os.ReadFile(filepath.Join(targetDir, ".env"))
require.NoError(t, err)
require.Equal(t, targetEnv, string(localLogin))
keyAfter, err := os.ReadFile(filepath.Join(targetDir, ".encryption.key"))
require.NoError(t, err)
require.True(t, bytes.Equal(targetKey, keyAfter), "configuration import keeps the destination key")