diff --git a/AppImage/messages/es/common.json b/AppImage/messages/es/common.json index a9754ca6..02a4260b 100644 --- a/AppImage/messages/es/common.json +++ b/AppImage/messages/es/common.json @@ -1723,6 +1723,16 @@ "searchApplications": "Buscar aplicaciones", "searchingApplications": "Buscando aplicaciones…", "noApplicationsDetected": "No se han detectado aplicaciones.", + "nativeEvidencePort": "Puerto TCP a la escucha", + "nativeEvidenceFile": "Archivo instalado", + "nativeEvidenceProcess": "Ejecutable en marcha", + "nativeEvidenceDirectory": "Directorio de trabajo", + "nativeEvidenceService": "Definición del servicio", + "nativeScanFailed": "La búsqueda de aplicaciones no ha podido terminar. Lo detectado antes puede estar desactualizado; vuelve a intentarlo.", + "nativeScanPartial": "La búsqueda de aplicaciones está incompleta. Revisa lo que se ha encontrado y vuelve a intentarlo.", + "nativeVersionUnknown": "Versión instalada desconocida", + "nativeEvidenceStale": "Lo detectado puede estar desactualizado o incompleto.", + "nativeRegisterOnly": "Confirma el registro en el editor. Una versión conocida se guarda como valor manual; no se configura ningún actualizador.", "noNewApplicationsDetected": "No se han detectado aplicaciones nuevas.", "oneNewApplicationDetected": "Se ha detectado una aplicación nueva.", "newApplicationsDetected": "Se han detectado {count} aplicaciones nuevas.", diff --git a/AppImage/scripts/native_app_discovery.py b/AppImage/scripts/native_app_discovery.py index ac9daa9e..3ba83ec5 100644 --- a/AppImage/scripts/native_app_discovery.py +++ b/AppImage/scripts/native_app_discovery.py @@ -146,6 +146,8 @@ SERVICE_SCRIPT = r''' command -v awk >/dev/null && command -v head >/dev/null || exit 1 n=0 for dir in /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /etc/init.d; do + # With a merged /usr, /lib is /usr/lib: the same units must not count twice. + [ "$dir" = /lib/systemd/system ] && [ /lib/systemd/system -ef /usr/lib/systemd/system ] && continue [ ! -d "$dir" ] || [ -r "$dir" ] || exit 1 for f in "$dir"/*; do [ -f "$f" ] || continue @@ -204,7 +206,8 @@ elif command -v netstat >/dev/null; then pid=$7; sub(/\/.*$/,"",pid); if(pid ~ /^[0-9]+$/) printf "L\t%s\t%s\n",pid,port} END {print failed ? "FAILED" : (limited ? "LIMIT" : "END")}' else - exit 1 + # Without ss or netstat there is no listener evidence; a retry would not change it. + printf 'END\n' fi ''' HESTIA_PANEL_SCRIPT = r''' diff --git a/AppImage/scripts/tests/test_native_app_discovery.py b/AppImage/scripts/tests/test_native_app_discovery.py index 397bb3fc..dc24424a 100644 --- a/AppImage/scripts/tests/test_native_app_discovery.py +++ b/AppImage/scripts/tests/test_native_app_discovery.py @@ -590,6 +590,28 @@ class DiscoveryFixtures(unittest.TestCase): self.assertNotIn('SECRET', output) self.assertFalse(marker.exists()) + def test_merged_usr_units_are_counted_once(self): + usr = self.root / 'usr-units' + usr.mkdir() + (usr / 'handmade.service').write_text('[Service]\nExecStart=/opt/handmade/server\n') + lib = self.root / 'lib-units' + lib.symlink_to(usr) + check = '[ "$dir" = /lib/systemd/system ] && [ /lib/systemd/system -ef /usr/lib/systemd/system ]' + self.assertIn(check, native.SERVICE_SCRIPT) + script = (native.SERVICE_SCRIPT + .replace('/etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /etc/init.d', f'{usr} {lib}') + .replace(check, f'[ "$dir" = {lib} ] && [ {lib} -ef {usr} ]')) + output = native.bounded_run(['sh', '-c', script], time.monotonic() + 3) + self.assertEqual(output.count('handmade.service'), 1) + + def test_a_guest_without_ss_or_netstat_has_no_listener_evidence(self): + bin_dir = self.root / 'no-tools' + bin_dir.mkdir() + (bin_dir / 'awk').symlink_to('/usr/bin/awk') + output = native.bounded_run(['sh', '-c', 'PATH=' + str(bin_dir) + '\n' + native.PORT_SCRIPT, 'fixture', '256'], + time.monotonic() + 3) + self.assertEqual(native.parse_records(output, 'L'), ([], False, 0)) + def test_actual_process_parser_skips_docker_and_never_reads_environ_cmdline(self): proc = self.root / 'proc' proc.mkdir()