fix: prefill verified Hestia panel endpoint

This commit is contained in:
VAIO73
2026-10-17 11:27:16 +00:00
parent 20acf0852a
commit 503302cea3
3 changed files with 32 additions and 3 deletions
+11 -1
View File
@@ -460,11 +460,21 @@ def candidate(vmid, record, footprint):
{'kind': 'working_directory', {'kind': 'working_directory',
'value': record.get('process_root', record['root'])}]) 'value': record.get('process_root', record['root'])}])
ports = sorted(set(record.get('listening_ports') or [])) ports = sorted(set(record.get('listening_ports') or []))
# Hestia's control panel is a narrow, verified exception to generic port
# inference: its own executable serves the panel on fixed HTTPS port 8083.
# Keep this declaration on the exact runtime signature so an unrelated
# application merely listening on 8083 never receives an HTTPS guess.
hestia_panel = (record['name'] == 'Hestia'
and record['path'] == _HESTIA_NGINX
and record['root'] == _HESTIA_ROOT
and _HESTIA_PANEL_PORT in ports)
evidence.extend({'kind': 'tcp_listener', 'value': str(port)} for port in ports) evidence.extend({'kind': 'tcp_listener', 'value': str(port)} for port in ports)
return {'slug': identity, 'discovery_id': identity, 'source': 'native_metadata', return {'slug': identity, 'discovery_id': identity, 'source': 'native_metadata',
'name': record['name'], 'installed_version': version, 'evidence': evidence, 'name': record['name'], 'installed_version': version, 'evidence': evidence,
'installation_path': record['path'], 'default_ports': [], 'installation_path': record['path'],
'default_ports': [_HESTIA_PANEL_PORT] if hestia_panel else [],
'listening_ports': ports, 'listening_ports': ports,
**({'scheme': 'https'} if hestia_panel else {}),
'metadata_issue': metadata_issue, 'metadata_issue': metadata_issue,
'tracking_suggestion': ({'installed_via': 'manual', 'installed_version': version, 'tracking_suggestion': ({'installed_via': 'manual', 'installed_version': version,
'detected_version': version, 'detector_verified': True} 'detected_version': version, 'detector_verified': True}
@@ -153,9 +153,18 @@ class DiscoveryFixtures(unittest.TestCase):
self.assertEqual(item['name'], 'Hestia') self.assertEqual(item['name'], 'Hestia')
self.assertEqual(item['installation_path'], hestia) self.assertEqual(item['installation_path'], hestia)
self.assertEqual(item['listening_ports'], [8083]) self.assertEqual(item['listening_ports'], [8083])
self.assertEqual(item['default_ports'], [8083])
self.assertEqual(item['scheme'], 'https')
self.assertIn({'kind': 'working_directory', 'value': '/'}, item['evidence']) self.assertIn({'kind': 'working_directory', 'value': '/'}, item['evidence'])
self.assertIn('metadata_limit', result['issues']) self.assertIn('metadata_limit', result['issues'])
unrelated = native.candidate(101, {
'name': 'other-panel', 'path': '/opt/other-panel/server', 'root': '/opt/other-panel',
'process': '/opt/other-panel/server', 'listening_ports': [8083],
}, 'FILE\n')
self.assertEqual(unrelated['default_ports'], [])
self.assertNotIn('scheme', unrelated)
self.calls.clear() self.calls.clear()
result = native.scan(101, self.runner( result = native.scan(101, self.runner(
services='END\n', processes='LIMIT\n', ports='END\n')) services='END\n', processes='LIMIT\n', ports='END\n'))
@@ -23,7 +23,7 @@ const candidate = {
evidence: [{kind: 'installation_file', value: '/opt/handmade/server'}], default_ports: [], evidence: [{kind: 'installation_file', value: '/opt/handmade/server'}], default_ports: [],
} }
function fixture() { function fixture({nativeCandidate = candidate} = {}) {
let cursor = 0, tree, props, effects = [], states = [], refs = [], effectStates = [] let cursor = 0, tree, props, effects = [], states = [], refs = [], effectStates = []
const calls = [], cachedWrites = [] const calls = [], cachedWrites = []
let native = {vmid: 101, status: 'not_scanned', candidates: [], stale: false} let native = {vmid: 101, status: 'not_scanned', candidates: [], stale: false}
@@ -49,7 +49,7 @@ function fixture() {
if (url.endsWith('/native-discovery')) { if (url.endsWith('/native-discovery')) {
if (options.method === 'POST') { if (options.method === 'POST') {
if (scanGate) await scanGate if (scanGate) await scanGate
native = {...native, status: scanStatus, candidates: [candidate]} native = {...native, status: scanStatus, candidates: [nativeCandidate]}
} }
return structuredClone(native) return structuredClone(native)
} }
@@ -123,6 +123,16 @@ async function main() {
assert.equal(payload.repo, '') assert.equal(payload.repo, '')
assert.equal(payload.upstream_type, '') assert.equal(payload.upstream_type, '')
const hestia = fixture({nativeCandidate: {
...candidate, name: 'Hestia', default_ports: [8083], scheme: 'https',
}})
hestia.render(); await hestia.settle()
await hestia.button('searchApplications').props.onClick(); hestia.render()
await hestia.button('registerButton').props.onClick(); hestia.render()
await hestia.button('saveButton').props.onClick(); hestia.render()
const hestiaPayload = JSON.parse(hestia.calls.find(c => /\/apps$/.test(c.url) && c.method === 'POST').body)
assert.deepEqual(hestiaPayload.ports, [{port: 8083, scheme: 'https', web_path: ''}],
'a verified Hestia panel pre-fills only its fixed HTTPS endpoint')
const partial = fixture() const partial = fixture()
partial.render(); await partial.settle(); partial.setScanStatus('partial') partial.render(); await partial.settle(); partial.setScanStatus('partial')
await partial.button('searchApplications').props.onClick(); partial.render() await partial.button('searchApplications').props.onClick(); partial.render()