mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-05-09 08:25:54 +02:00
[PR #1067] [CLOSED] fix(virtual-printer): Tailscale cert provisioning — hardening + maintainer feedback #1156
Labels
No labels
A1
automated
automated
bug
bug
Closed due to inactivity
contrib
dependencies
dependencies
duplicate
enhancement
feedback
hold
invalid
Notes
P1S
pull-request
security
ThumbsUp
user-report
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/bambuddy-maziggy-1#1156
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/maziggy/bambuddy/pull/1067
Author: @legend813
Created: 4/21/2026
Status: ❌ Closed
Base:
dev← Head:feature/tailscale-cert-integration📝 Commits (10+)
af90380feat(virtual-printer): add Tailscale certificate provisioning9116f83fix(virtual-printer): harden Tailscale cert provisioning01d35bftest(virtual-printer): extend Tailscale test coverage2243249feat(virtual-printer): add Tailscale status UI to virtual printer settingsb2251dcfix(virtual-printer): harden Tailscale cert provisioning95ad6a0test(virtual-printer): extend Tailscale test coverage to 33 testsd66ca43fix(virtual-printer): improve Tailscale fallback logging and error detectioncd18226test(virtual-printer): cover HTTPS-disabled detection and readability checkfe860aaMerge branch 'dev' into feature/tailscale-cert-integration66a17bdfix(virtual-printer): address maintainer review feedback on PR #1067📊 Changes
20 files changed (+10423 additions, -51 deletions)
View changed files
📝
backend/app/api/routes/virtual_printers.py(+33 -0)📝
backend/app/services/virtual_printer/certificate.py(+35 -2)📝
backend/app/services/virtual_printer/manager.py(+150 -4)➕
backend/app/services/virtual_printer/tailscale.py(+333 -0)➕
backend/tests/integration/test_tailscale_api.py(+61 -0)➕
backend/tests/unit/services/test_tailscale.py(+919 -0)📝
frontend/src/api/client.ts(+14 -1)📝
frontend/src/components/VirtualPrinterCard.tsx(+7 -1)📝
frontend/src/components/VirtualPrinterList.tsx(+38 -3)📝
frontend/src/i18n/locales/de.ts(+6 -0)📝
frontend/src/i18n/locales/en.ts(+6 -0)📝
frontend/src/i18n/locales/fr.ts(+6 -0)📝
frontend/src/i18n/locales/it.ts(+6 -0)📝
frontend/src/i18n/locales/ja.ts(+6 -0)📝
frontend/src/i18n/locales/pt-BR.ts(+6 -0)📝
frontend/src/i18n/locales/zh-CN.ts(+6 -0)📝
frontend/src/i18n/locales/zh-TW.ts(+6 -0)➕
static/assets/index-B5tNePLk.js(+8743 -0)➕
static/assets/index-b56DyY_w.css(+1 -0)📝
static/index.html(+41 -40)📄 Description
What this PR does
Adds automatic Tailscale TLS certificate provisioning for Virtual Printers. When Tailscale is installed and connected, Bambuddy obtains a Let's Encrypt certificate via
tailscale certand applies it to all VP TLS services (MQTTS, FTPS, Bind). SSDP then advertises the Tailscale FQDN instead of a local IP — so slicers connect via a hostname covered by a publicly trusted cert, eliminating manual CA installation.Falls back silently to the existing self-signed cert when Tailscale is absent or provisioning fails.
Documentation
Wiki PR: maziggy/bambuddy-wiki#13 — adds a new Tailscale Certificate (Optional) section to the Virtual Printer page covering:
/var/run/tailscalesocket bind-mount with annotated compose exampleWhy
tailscale certinstead oftailscale serveThe original design discussion considered
tailscale serve. After deeper analysis,tailscale serveis not viable for this protocol stack:tailscale serveis an HTTPS reverse proxy and cannot terminate bare TLS socketstailscale certprovisions a cert that the VP TLS listener loads directly, which works for all three protocols. This is the only technically compatible path for the full VP stack.Review Feedback Addressed (maintainer review #4147826937)
Major issues
_resolve_cert_and_advertise()returns self-signed cert immediately in proxy mode; renewal loop not started for proxy VPsuse_tailscale_certtoggle)Code-level fixes
_cancel_renewal_tasksilences real bugsCancelledErrorandExceptionnow split; unexpected errors logged as warningsasyncio.TimeoutErrorhandlingget_status()andprovision_cert()now catchTimeoutErrorand return safe defaultsself._cert_restart_task; cancelled instop_server()+stop_proxy()_restart_for_cert_renewal()re-spawns the renewal loop in its except blockArchitecture
New:
TailscaleService(backend/app/services/virtual_printer/tailscale.py)get_status()— runstailscale status --jsonto get FQDN and Tailscale IPs; returnsTailscaleStatus(available=False)on any errorprovision_cert()— runstailscale cert --cert-file … --key-file … <fqdn>; validates FQDN, creates output directory, sets key permissions to0o600, verifies readabilitycert_needs_renewal()— checks expiry against a 30-day threshold and validates FQDN against cert SANs (RFC 4343 case-insensitive)ensure_cert()— combines renewal check + provisioning in one callshutil.which()to prevent PATH hijacking;_SUBPROCESS_ENVallowlist strips JWT keys, DB URLs, and SMTP passwords from subprocess environment;asyncio.wait_fortimeouts (5 s for status, 60 s for cert provisioning)Changes to
CertificateService(certificate.py)ts_cert_path/ts_key_pathproperties pointing to per-VP Tailscale cert filesuse_tailscale_cert(fqdn, tailscale_svc)methodChanges to
VirtualPrinterInstance(manager.py)_resolve_cert_and_advertise()— proxy mode always uses self-signed; server mode tries Tailscale then falls back_cert_renewal_loop()— daily background task; schedules restart via_cert_restart_taskon renewal_cancel_renewal_task()/_cancel_restart_task()helpers with proper exception logging_restart_for_cert_renewal()re-spawns the loop if restart failsNew API endpoint
GET /api/v1/virtual-printers/tailscale-status— returnsTailscaleStatusResponse; protected byRequirePermissionIfAuthEnabled(SETTINGS_READ)Frontend (separate PR #1070)
VirtualPrinterListShieldCheckbadge inVirtualPrinterCardwhen activeuse_tailscale_certtoggle in settingsFallback behaviour
tailscalebinary not foundget_status()returnsavailable=False; self-signed cert usedtailscale statusexits non-zero; self-signed cert usedtailscale certtimes outTimeoutErrorcaught; self-signed cert usedos.access()check after write; actionablesudo chownlog; self-signed cert usedCert auto-renewal
CancelledErroron VP stop exits cleanlyTest plan
pytest backend/tests/unit/services/test_tailscale.py -v— 43 tests, all passpytest backend/tests/unit/ -v— no regressionsnpm run build— clean, no TypeScript errors"[VP …] Using Tailscale cert for <fqdn>"GET /api/v1/virtual-printers/tailscale-statusreturns FQDN andavailable: true"Tailscale not available, using self-signed cert"Closes #701
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.