mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 03:54:17 +02:00
fix(install): sign the Python that macOS grants local network access to (issue #3114)
macOS attributes Local Network permission to a code signature and judges a launchd-spawned process on its own, rather than letting it inherit the grant of the Terminal that started it. Homebrew ships Python unsigned on Intel, so there is no identity for the grant to attach to: every connection to a LAN address is dropped with no error the application can log and no permission prompt. The printer reads as unreachable and nothing says why, and the entry in Privacy & Security cannot be made to work because it refers to an identity that no longer resolves. install.sh signs during a macOS install; update_macos.sh re-checks on every update, because `brew upgrade python` installs a fresh unsigned binary under a new versioned path. Both sign only what is currently unsigned. That gate is load-bearing: on arm64 the linker ad-hoc signs every binary and the identity is a hash of the file, so re-signing would rotate it and revoke a working grant on each update. A python.org build carries a real Developer ID and must not be downgraded for the same reason. The interpreter and the framework's Python.app are both signed. The first is what sys._base_executable resolves to and what the reporter's TCC log names; the second is what his fix actually targeted. Which one macOS attributes could not be established from either, and signing both costs nothing. ----- fix(diagnostics): name the macOS permission that silently blocks the printer (issue #3114) The port checks reported all three ports unreachable while the subnet check passed, and port_mqtt's fix text sent the reporter after firewalls and IP addresses. On a macOS native install that pattern has a cause neither of those covers: no Local Network grant, denied with no error and no prompt. A new macos_local_network check, appended on macOS only so no permanently dimmed row appears for anyone else. It passes when the control port answered, which is proof the permission is in place and means the signature probe never runs on a healthy diagnostic. Otherwise it probes the interpreter: an unsigned one gets the repair that fixes it, a signed one gets System Settings — the arm64 case, where the identity is a hash of the binary, so a Python upgrade presents macOS with a new application and strands the old grant. Always warn, never fail, and only once port_mqtt has already failed, so this can never be why a green diagnostic turns red. A printer that is simply switched off produces the same all-ports-dead pattern, which is why the signature, not the pattern, is what earns the specific advice. An undeterminable signature is reported as the generic case rather than as unsigned: that advice rewrites a file in the user's Python installation and must not be offered on a guess.
This commit is contained in:
@@ -245,6 +245,51 @@ describe('ConnectionDiagnosticModal', () => {
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it('names the interpreter when macOS has no signature to grant against (#3114)', async () => {
|
||||
const spy = vi.spyOn(api, 'diagnosePrinter').mockResolvedValue({
|
||||
...PROBLEM_RESULT,
|
||||
overall: 'problems',
|
||||
checks: [
|
||||
{
|
||||
id: 'macos_local_network',
|
||||
status: 'warn',
|
||||
params: {
|
||||
reason: 'unsigned',
|
||||
executable: '/usr/local/Cellar/python@3.14/3.14.7/Frameworks/Python.framework/Versions/3.14/bin/python3.14',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
renderModal({ printerId: 1, printerName: 'Test P1S', onClose: vi.fn() });
|
||||
|
||||
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
|
||||
expect(await screen.findByText(/macOS Local Network permission/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/has no code signature/i)).toBeInTheDocument();
|
||||
// The path is what tells the user which of several Pythons is meant.
|
||||
expect(screen.getByText(/Versions\/3\.14\/bin\/python3\.14/)).toBeInTheDocument();
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it('points a signed-but-blocked macOS install at System Settings (#3114)', async () => {
|
||||
const spy = vi.spyOn(api, 'diagnosePrinter').mockResolvedValue({
|
||||
...PROBLEM_RESULT,
|
||||
overall: 'problems',
|
||||
checks: [{ id: 'macos_local_network', status: 'warn', params: { reason: 'permission' } }],
|
||||
});
|
||||
|
||||
renderModal({ printerId: 1, printerName: 'Test P1S', onClose: vi.fn() });
|
||||
|
||||
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
|
||||
expect(await screen.findByText(/Privacy & Security > Local Network/i)).toBeInTheDocument();
|
||||
// The signing repair must not be offered to a machine that is already
|
||||
// signed: re-signing it would revoke the grant it still has.
|
||||
expect(screen.queryByText(/update_macos\.sh/i)).not.toBeInTheDocument();
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it('falls back to the generic skip text when no reason is present', async () => {
|
||||
const spy = vi.spyOn(api, 'diagnosePrinter').mockResolvedValue({
|
||||
...PROBLEM_RESULT,
|
||||
|
||||
@@ -6988,6 +6988,12 @@ export default {
|
||||
pass: 'Erreichbar — der Kamerastream funktioniert.',
|
||||
warn: 'Port {{port}} ist nicht erreichbar. Die Live-Kameraansicht funktioniert nicht. Dies betrifft das Drucken nicht.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS-Berechtigung „Lokales Netzwerk“',
|
||||
pass: 'macOS erlaubt Bambuddy den Zugriff auf das lokale Netzwerk.',
|
||||
warn_unsigned: 'Das Python, das Bambuddy ausführt, hat keine Code-Signatur. Damit hat macOS nichts, woran es die Berechtigung „Lokales Netzwerk“ binden könnte, und verwirft jede Verbindung zum Drucker stillschweigend — ohne Fehler und ohne Nachfrage. Führe das Bambuddy-Update-Skript (install/update_macos.sh) aus, das die Signatur setzt, und starte Bambuddy anschließend neu. Interpreter: {{executable}}',
|
||||
warn_permission: 'Wenn der Drucker eingeschaltet und unter dieser Adresse erreichbar ist, öffne Systemeinstellungen > Datenschutz & Sicherheit > Lokales Netzwerk und stelle sicher, dass das Python von Bambuddy aktiviert ist. macOS verwirft lokale Verbindungen sonst stillschweigend, und ein Python-Update kann die alte Berechtigung zurücklassen.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Container-Netzwerkmodus',
|
||||
genericRuntime: 'einem Container',
|
||||
|
||||
@@ -7039,6 +7039,12 @@ export default {
|
||||
pass: 'Reachable — the camera stream will work.',
|
||||
warn: 'Port {{port}} is unreachable. The live camera view will not work. This does not affect printing.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS Local Network permission',
|
||||
pass: 'macOS is allowing Bambuddy to reach the local network.',
|
||||
warn_unsigned: 'The Python that runs Bambuddy has no code signature, so macOS has nothing to attach a Local Network permission to and silently drops every connection to the printer — no error and no prompt. Run the Bambuddy updater (install/update_macos.sh), which signs it, then restart Bambuddy. Interpreter: {{executable}}',
|
||||
warn_permission: 'If the printer is powered on and at this address, open System Settings > Privacy & Security > Local Network and make sure the Python that runs Bambuddy is enabled. macOS drops local connections silently when it is not, and updating Python can leave the old permission behind.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Container network mode',
|
||||
genericRuntime: 'a container',
|
||||
|
||||
@@ -6996,6 +6996,12 @@ export default {
|
||||
pass: 'Accesible — la transmisión de la cámara funcionará.',
|
||||
warn: 'El puerto {{port}} no es accesible. La vista de la cámara en directo no funcionará. Esto no afecta a la impresión.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'Permiso de red local de macOS',
|
||||
pass: 'macOS permite que Bambuddy acceda a la red local.',
|
||||
warn_unsigned: 'El Python que ejecuta Bambuddy no tiene firma de código, así que macOS no tiene a qué asociar el permiso de red local y descarta en silencio todas las conexiones con la impresora: sin error y sin solicitud. Ejecuta el actualizador de Bambuddy (install/update_macos.sh), que lo firma, y reinicia Bambuddy. Intérprete: {{executable}}',
|
||||
warn_permission: 'Si la impresora está encendida y en esta dirección, abre Ajustes del Sistema > Privacidad y seguridad > Red local y comprueba que el Python de Bambuddy esté activado. Si no lo está, macOS descarta las conexiones locales en silencio, y actualizar Python puede dejar atrás el permiso anterior.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Modo de red del contenedor',
|
||||
genericRuntime: 'un contenedor',
|
||||
|
||||
@@ -6978,6 +6978,12 @@ export default {
|
||||
pass: 'Accessible — le flux de la caméra fonctionnera.',
|
||||
warn: 'Le port {{port}} est inaccessible. La vue caméra en direct ne fonctionnera pas. Cela n\'affecte pas l\'impression.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'Autorisation « Réseau local » de macOS',
|
||||
pass: 'macOS autorise Bambuddy à accéder au réseau local.',
|
||||
warn_unsigned: 'Le Python qui exécute Bambuddy n’a pas de signature de code : macOS n’a donc rien à quoi rattacher l’autorisation « Réseau local » et rejette silencieusement toutes les connexions vers l’imprimante, sans erreur ni demande. Lancez le script de mise à jour de Bambuddy (install/update_macos.sh), qui le signe, puis redémarrez Bambuddy. Interpréteur : {{executable}}',
|
||||
warn_permission: 'Si l’imprimante est allumée et joignable à cette adresse, ouvrez Réglages Système > Confidentialité et sécurité > Réseau local et vérifiez que le Python de Bambuddy est activé. Sinon macOS rejette les connexions locales en silence, et une mise à jour de Python peut laisser l’ancienne autorisation derrière elle.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Mode réseau du conteneur',
|
||||
genericRuntime: 'un conteneur',
|
||||
|
||||
@@ -6977,6 +6977,12 @@ export default {
|
||||
pass: 'Raggiungibile — lo streaming della fotocamera funzionerà.',
|
||||
warn: 'La porta {{port}} non è raggiungibile. La visualizzazione live della fotocamera non funzionerà. Questo non influisce sulla stampa.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'Autorizzazione « Rete locale » di macOS',
|
||||
pass: 'macOS consente a Bambuddy di raggiungere la rete locale.',
|
||||
warn_unsigned: 'Il Python che esegue Bambuddy non ha una firma del codice, quindi macOS non ha nulla a cui associare l’autorizzazione « Rete locale » e scarta in silenzio ogni connessione alla stampante, senza errori e senza richiesta. Esegui lo script di aggiornamento di Bambuddy (install/update_macos.sh), che lo firma, poi riavvia Bambuddy. Interprete: {{executable}}',
|
||||
warn_permission: 'Se la stampante è accesa e raggiungibile a questo indirizzo, apri Impostazioni di Sistema > Privacy e sicurezza > Rete locale e verifica che il Python di Bambuddy sia abilitato. In caso contrario macOS scarta le connessioni locali in silenzio, e un aggiornamento di Python può lasciare indietro la vecchia autorizzazione.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Modalità di rete del container',
|
||||
genericRuntime: 'un container',
|
||||
|
||||
@@ -6989,6 +6989,12 @@ export default {
|
||||
pass: '到達可能 — カメラストリームは機能します。',
|
||||
warn: 'ポート{{port}}に到達できません。ライブカメラ表示は機能しません。これは印刷には影響しません。',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS のローカルネットワーク権限',
|
||||
pass: 'macOS は Bambuddy のローカルネットワークへのアクセスを許可しています。',
|
||||
warn_unsigned: 'Bambuddy を実行している Python にコード署名がないため、macOS はローカルネットワーク権限を結び付ける対象を持てず、プリンターへの接続をエラーも確認ダイアログもなく破棄します。署名を行う Bambuddy の更新スクリプト (install/update_macos.sh) を実行してから、Bambuddy を再起動してください。インタープリター: {{executable}}',
|
||||
warn_permission: 'プリンターの電源が入っていてこのアドレスで到達できる場合は、システム設定 > プライバシーとセキュリティ > ローカルネットワーク を開き、Bambuddy の Python が有効になっているか確認してください。無効だと macOS はローカル接続を無言で破棄します。また Python を更新すると以前の許可が引き継がれないことがあります。',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'コンテナのネットワークモード',
|
||||
genericRuntime: 'コンテナ',
|
||||
|
||||
@@ -7089,6 +7089,12 @@ export default {
|
||||
pass: '연결 가능 — 카메라 스트림이 작동합니다.',
|
||||
warn: '포트 {{port}}에 연결할 수 없습니다. 라이브 카메라 보기가 작동하지 않습니다. 인쇄에는 영향을 주지 않습니다.'
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS 로컬 네트워크 권한',
|
||||
pass: 'macOS가 Bambuddy의 로컬 네트워크 접근을 허용하고 있습니다.',
|
||||
warn_unsigned: 'Bambuddy를 실행하는 Python에 코드 서명이 없어 macOS가 로컬 네트워크 권한을 연결할 대상을 찾지 못하고, 프린터로 향하는 모든 연결을 오류도 확인 창도 없이 조용히 차단합니다. 서명을 수행하는 Bambuddy 업데이트 스크립트(install/update_macos.sh)를 실행한 다음 Bambuddy를 재시작하십시오. 인터프리터: {{executable}}',
|
||||
warn_permission: '프린터가 켜져 있고 이 주소로 연결할 수 있다면 시스템 설정 > 개인 정보 보호 및 보안 > 로컬 네트워크를 열어 Bambuddy의 Python이 활성화되어 있는지 확인하십시오. 활성화되어 있지 않으면 macOS는 로컬 연결을 조용히 차단하며, Python을 업데이트하면 이전 권한이 남지 않을 수 있습니다.',
|
||||
},
|
||||
network_mode: {
|
||||
title: '컨테이너 네트워크 모드',
|
||||
genericRuntime: '컨테이너',
|
||||
|
||||
@@ -7039,6 +7039,12 @@ export default {
|
||||
pass: 'Bereikbaar — de camerastream werkt.',
|
||||
warn: 'Poort {{port}} is niet bereikbaar. De livecamera werkt niet. Dit heeft geen invloed op afdrukken.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS-toegang tot lokaal netwerk',
|
||||
pass: 'macOS staat Bambuddy toe het lokale netwerk te bereiken.',
|
||||
warn_unsigned: 'De Python waarmee Bambuddy draait heeft geen codehandtekening, dus macOS heeft niets om de toegang tot het lokale netwerk aan te koppelen en laat elke verbinding met de printer stilletjes vallen — zonder fout en zonder vraag. Voer het updatescript van Bambuddy (install/update_macos.sh) uit, dat de handtekening plaatst, en start Bambuddy daarna opnieuw. Interpreter: {{executable}}',
|
||||
warn_permission: 'Staat de printer aan en is hij op dit adres bereikbaar, open dan Systeeminstellingen > Privacy en beveiliging > Lokaal netwerk en controleer of de Python van Bambuddy is ingeschakeld. Zo niet, dan laat macOS lokale verbindingen stilletjes vallen, en een Python-update kan de oude toestemming achterlaten.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Netwerkmodus van de container',
|
||||
genericRuntime: 'een container',
|
||||
|
||||
@@ -6977,6 +6977,12 @@ export default {
|
||||
pass: 'Acessível — o streaming da câmera funcionará.',
|
||||
warn: 'A porta {{port}} está inacessível. A visualização ao vivo da câmera não funcionará. Isso não afeta a impressão.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'Permissão de rede local do macOS',
|
||||
pass: 'O macOS está permitindo que o Bambuddy alcance a rede local.',
|
||||
warn_unsigned: 'O Python que executa o Bambuddy não tem assinatura de código, então o macOS não tem a que vincular a permissão de rede local e descarta silenciosamente todas as conexões com a impressora — sem erro e sem solicitação. Execute o atualizador do Bambuddy (install/update_macos.sh), que faz a assinatura, e reinicie o Bambuddy. Interpretador: {{executable}}',
|
||||
warn_permission: 'Se a impressora estiver ligada e acessível neste endereço, abra Ajustes do Sistema > Privacidade e Segurança > Rede Local e verifique se o Python do Bambuddy está ativado. Caso contrário, o macOS descarta conexões locais em silêncio, e atualizar o Python pode deixar a permissão antiga para trás.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Modo de rede do contêiner',
|
||||
genericRuntime: 'um contêiner',
|
||||
|
||||
@@ -6617,6 +6617,12 @@ export default {
|
||||
pass: "Доступен — видеопоток камеры будет работать.",
|
||||
warn: "Порт {{port}} недоступен. Просмотр камеры в реальном времени работать не будет. На печать это не влияет.",
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'Разрешение macOS на доступ к локальной сети',
|
||||
pass: 'macOS разрешает Bambuddy доступ к локальной сети.',
|
||||
warn_unsigned: 'У Python, под которым работает Bambuddy, нет подписи кода, поэтому macOS не к чему привязать разрешение на доступ к локальной сети и молча отбрасывает все подключения к принтеру — без ошибки и без запроса. Запустите сценарий обновления Bambuddy (install/update_macos.sh), который подписывает его, и перезапустите Bambuddy. Интерпретатор: {{executable}}',
|
||||
warn_permission: 'Если принтер включён и доступен по этому адресу, откройте Настройки системы > Конфиденциальность и безопасность > Локальная сеть и убедитесь, что Python, под которым работает Bambuddy, включён. Иначе macOS молча отбрасывает локальные подключения, а обновление Python может оставить старое разрешение позади.',
|
||||
},
|
||||
network_mode: {
|
||||
title: "Сетевой режим контейнера",
|
||||
genericRuntime: "контейнере",
|
||||
|
||||
@@ -6927,6 +6927,12 @@ export default {
|
||||
pass: 'Erişilebilir — kamera akışı çalışacak.',
|
||||
warn: 'Port {{port}} erişilemez. Canlı kamera görünümü çalışmayacak. Bu, baskıyı etkilemez.',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS Yerel Ağ izni',
|
||||
pass: 'macOS, Bambuddy’nin yerel ağa erişmesine izin veriyor.',
|
||||
warn_unsigned: 'Bambuddy’yi çalıştıran Python’un kod imzası yok; bu yüzden macOS Yerel Ağ iznini bağlayacak bir kimlik bulamıyor ve yazıcıya giden tüm bağlantıları hata vermeden, sormadan sessizce düşürüyor. İmzalamayı yapan Bambuddy güncelleme betiğini (install/update_macos.sh) çalıştırın, ardından Bambuddy’yi yeniden başlatın. Yorumlayıcı: {{executable}}',
|
||||
warn_permission: 'Yazıcı açıksa ve bu adresten erişilebiliyorsa Sistem Ayarları > Gizlilik ve Güvenlik > Yerel Ağ bölümünü açıp Bambuddy’nin Python’unun etkin olduğundan emin olun. Etkin değilse macOS yerel bağlantıları sessizce düşürür; ayrıca Python güncellemesi eski izni geride bırakabilir.',
|
||||
},
|
||||
network_mode: {
|
||||
title: 'Konteyner ağ modu',
|
||||
genericRuntime: 'bir konteyner',
|
||||
|
||||
@@ -7031,6 +7031,12 @@ export default {
|
||||
pass: "Доступно — потік камери працюватиме.",
|
||||
warn: "Порт {{port}} недоступний. Перегляд з камери в реальному часі не працюватиме. Це не впливає на друк.",
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'Дозвіл macOS на доступ до локальної мережі',
|
||||
pass: 'macOS дозволяє Bambuddy доступ до локальної мережі.',
|
||||
warn_unsigned: 'Python, під яким працює Bambuddy, не має підпису коду, тож macOS нема до чого прив’язати дозвіл на локальну мережу і мовчки відкидає всі з’єднання з принтером — без помилки та без запиту. Запустіть сценарій оновлення Bambuddy (install/update_macos.sh), який його підписує, і перезапустіть Bambuddy. Інтерпретатор: {{executable}}',
|
||||
warn_permission: 'Якщо принтер увімкнений і доступний за цією адресою, відкрийте Системні параметри > Конфіденційність і безпека > Локальна мережа та переконайтеся, що Python від Bambuddy увімкнено. Інакше macOS мовчки відкидає локальні з’єднання, а оновлення Python може залишити старий дозвіл позаду.',
|
||||
},
|
||||
network_mode: {
|
||||
title: "Мережевий режим контейнера",
|
||||
genericRuntime: "контейнері",
|
||||
|
||||
@@ -6975,6 +6975,12 @@ export default {
|
||||
pass: '可达 — 摄像头视频流将正常工作。',
|
||||
warn: '端口 {{port}} 不可达。实时摄像头视图将无法工作。这不影响打印。',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS 本地网络权限',
|
||||
pass: 'macOS 已允许 Bambuddy 访问本地网络。',
|
||||
warn_unsigned: '运行 Bambuddy 的 Python 没有代码签名,macOS 因此无法将本地网络权限绑定到任何身份,会静默丢弃所有到打印机的连接——既没有错误,也不会弹出授权提示。请运行会完成签名的 Bambuddy 更新脚本 (install/update_macos.sh),然后重启 Bambuddy。解释器:{{executable}}',
|
||||
warn_permission: '如果打印机已开机并可通过该地址访问,请打开 系统设置 > 隐私与安全性 > 本地网络,确认 Bambuddy 使用的 Python 已启用。未启用时 macOS 会静默丢弃本地连接,而且升级 Python 可能不会保留原有授权。',
|
||||
},
|
||||
network_mode: {
|
||||
title: '容器网络模式',
|
||||
genericRuntime: '容器',
|
||||
|
||||
@@ -6975,6 +6975,12 @@ export default {
|
||||
pass: '可達 — 攝影機串流將正常運作。',
|
||||
warn: '連接埠 {{port}} 無法連線。即時攝影機檢視將無法運作。這不影響列印。',
|
||||
},
|
||||
macos_local_network: {
|
||||
title: 'macOS 本地網路權限',
|
||||
pass: 'macOS 已允許 Bambuddy 存取本地網路。',
|
||||
warn_unsigned: '執行 Bambuddy 的 Python 沒有程式碼簽章,macOS 因此無法將本地網路權限繫結到任何身分,會靜默丟棄所有連往印表機的連線——既沒有錯誤,也不會出現授權提示。請執行會完成簽章的 Bambuddy 更新指令碼 (install/update_macos.sh),然後重新啟動 Bambuddy。直譯器:{{executable}}',
|
||||
warn_permission: '若印表機已開機且可透過此位址連線,請開啟 系統設定 > 隱私權與安全性 > 本地網路,確認 Bambuddy 使用的 Python 已啟用。未啟用時 macOS 會靜默丟棄本地連線,而且更新 Python 可能不會保留原有授權。',
|
||||
},
|
||||
network_mode: {
|
||||
title: '容器網路模式',
|
||||
genericRuntime: '容器',
|
||||
|
||||
Reference in New Issue
Block a user