Skip to content

App Review: provision an isolated dedicated Jellyfin demo environment #280

Description

@jlipworth

Goal

Provision a dedicated, isolated Jellyfin environment that gives Apple App Review a stable end-to-end Labstream path without exposing a personal media server, household account, private hostname, or real library.

Apple requires full review access for account-based features and says backend services must remain live and accessible during review. The current public Jellyfin project demo is useful for development but is third-party infrastructure outside our control; the release candidate should have a Labstream-owned fallback or primary review environment.

Proposed shape

  • A dedicated Jellyfin container/VM, separate from every personal or production media server.
  • A stable public DNS name over ordinary HTTPS port 443 with a system-trusted certificate; no DDNS-only dependency, self-signed certificate, custom port, VPN, IP allowlist, or local-network requirement.
  • Reverse proxy with WebSocket support and Jellyfin Known Proxies configured correctly.
  • A non-admin, non-expiring review user with read-only playback access and no library-management, deletion, download-management, remote-control, or server-administration privileges.
  • A small immutable library of clearly licensed sample video/audio/subtitle/artwork assets. Record license and attribution for every asset.
  • Deterministic Movies, Shows/Seasons/Episodes, Music, subtitles, chapters, resume/progress, and—if practical—transcode/remux examples so App Review can exercise Labstream's core claims.
  • Automatic restoration of user progress/settings and server configuration to a known state without changing credentials during a review window.
  • Health checks and alerting for DNS, TLS, Jellyfin health, authentication, catalog browse, byte-range playback, and one real Labstream request path.

Security/privacy constraints

  • Never reuse a personal account, personal media, personal server database, or production credential.
  • Store the review password only in the deployment secret store and App Store Connect review fields—not Git, CI logs, screenshots, public issues, or diagnostics.
  • Redact/disable full request-path logging because Jellyfin may place API keys in URLs; bound retention and restrict access to proxy/Jellyfin logs.
  • Run rootless/non-root where practical, mount demo media read-only, pin/update the Jellyfin image deliberately, minimize exposed ports, and isolate the service from internal networks.
  • Add rate limiting/abuse controls that do not prevent Apple review, plus a documented emergency credential rotation and shutdown path.
  • Use fictional account and media metadata suitable for a 4+ storefront screenshot/review surface.

Review runbook

  • Record the server URL, username, password, and exact navigation steps privately in App Store Connect.
  • Keep the service live from submission until review and any appeal/re-review completes.
  • Before every submission, test from an off-LAN network and from the exact TestFlight candidate: sign in → browse Movies/Shows/Music → play → seek → subtitle/audio selection → progress update.
  • Keep the public Jellyfin project demo documented as a temporary fallback, but do not make successful review depend solely on it.

Acceptance

  • Dedicated isolated deployment is reproducible from private infrastructure configuration without secrets in this repository.
  • Stable DNS + trusted TLS on 443 pass external checks.
  • Review account is non-admin, non-expiring, and least-privileged.
  • Only licensed fictional/sample content is present, with recorded provenance.
  • Off-LAN Labstream release-candidate browse/playback smoke passes.
  • Reset, monitoring, alerting, backup/restore, credential rotation, and incident shutdown are documented and tested.
  • App Store Connect review notes contain the private credentials and precise steps.

References

Operational privacy follow-up (from #325)

These checks apply only to the project-operated reviewer/demo service, not every user-selected server or the client's local diagnostic storage. #325 owns disclosure reconciliation; this issue owns the service facts it needs.

Verified read-only evidence is recorded in PR #329's sanitized audit: route access logs disabled; Jellyfin Warning logs use bounded file-count/size rotation; the scheduled reset clears catalog progress/favorites, not auth/device/activity records or backups. Configured retention is not proof of effective deletion.

  • Verify aggregate auth/device/activity record ages and actual expiry/cleanup without publishing rows, tokens or identifiers. Existing schema inspection establishes possible storage, not populated values or maximum age.
  • Verify effective centralized-log deletion and edge/provider record types/retention. The declared Loki period was not established as enforced.
  • Reconcile actual backup/snapshot inventories, downstream copies and the source/live Velero schedule discrepancy; copy counts are not maximum-age promises.
  • Verify administrative/read access to service data, log sinks and backups.
  • Record findings/remaining unknowns for Release privacy: reconcile project-operated review demo and collection disclosures #325; propose any operational changes separately for approval. Do not change settings, clear data, install database tools or restart services as part of read-only verification.

These open operational checks do not invalidate the evidence that normal client diagnostics stay local until an explicit sharing action; they concern records held by the separately selected project-operated server.

Activity

  1. jlipworth commented on Aug 22, 2026

    @jlipworth
    OwnerAuthor

    Public-demo evaluation update (2026-08-22):

    • The official stable demo at https://demo.jellyfin.org/stable/ is live on Jellyfin 10.11.11 and is explicitly offered by Jellyfin for evaluation/testing.
    • A credential-ephemeral PMSKit live probe passed the shared views, items, and metadata wrappers (HTTP 200); no token/session/response body was retained and no timeline mutation was enabled.
    • The account is passwordless, which exposed a Labstream UI defect now tracked in Support passwordless Jellyfin accounts #283. A separate Codex task is implementing that fix.
    • The demo currently provides Movies, Shows, Music, Playlists, artwork, and playable public/open test media.
    • It is not yet accepted as the final App Review dependency: shared preferences are mutable, downloads are disabled, historical Jellyfin guidance warns of resets, and marketing-use provenance for each visible poster/backdrop still needs to be established.

    Decision: evaluate the public stable demo first and avoid provisioning new infrastructure unless it fails cross-platform sign-in/playback, rights, reliability, screenshot determinism, or complete reviewer-access gates. Keep this dedicated environment issue open as the fallback/likely final-review lane, but do not provision it yet.

  2. jlipworth commented on Aug 23, 2026

    @jlipworth
    OwnerAuthor

    Public-demo UI evaluation update (2026-08-22):

    • Passwordless support is now merged on main through Support passwordless Jellyfin accounts #283 / PR Support passwordless Jellyfin accounts #284.
    • Clean iPhone and iPad simulator reviewer journeys both passed ordinary UI sign-in, Home browse, opening a live detail surface, and rendered playback against the official stable demo.
    • The result is technically compatible but unsuitable as the final deterministic review/screenshot environment. The shared account exposed pre-existing progress and arbitrary Continue Watching state; identical fresh logins inherited that mutable state.
    • Home artwork did not finish loading before the first semantically-ready capture even though metadata rails were present, while detail artwork loaded later. Store capture therefore needs explicit artwork-readiness gates and controlled assets.
    • The public account disables downloads while Labstream's download-capable platforms still expose the feature, so it cannot demonstrate the complete submitted product contract.
    • Catalog/artwork marketing-rights provenance remains unresolved.

    Decision: the no-new-infrastructure experiment has now failed the determinism, complete-review-access, and rights gates even though compatibility passed. Proceed with this issue's minimal controlled environment. Prefer the smallest isolated container/LXC that meets the security and availability contract rather than a general-purpose VM.

    Remaining device-family testing should be repeated against the controlled catalog once available; there is no value in treating further shared-demo success as closing the blockers above.

  3. jlipworth commented on Aug 23, 2026

    @jlipworth
    OwnerAuthor

    Infrastructure progress: a dedicated GitOps merge request is open for an isolated, non-admin Jellyfin App Review environment. It includes a deterministic fictional Movies/Shows/Music catalog with playable video, audio, subtitles, chapters, and downloads; read-only regenerated media; nightly account-state reset; public-path health checks; bounded/redacted logging; backup/rotation/shutdown procedures; and machine-readable provenance for the procedural payload and candidate key art. The public hostname and all credentials remain outside Git.

    Remaining human gates are: approve the candidate artwork for App Review/storefront use, enter the private secrets, create the publicly resolvable proxied DNS record for ordinary trusted HTTPS, merge/promote the infrastructure change, and complete the documented off-LAN TestFlight iPhone/iPad journey. No App Store Connect state was changed.

    Infrastructure MR: https://gitlab.com/jlipworth/proxmox-project/-/merge_requests/321

  4. jlipworth commented on Aug 23, 2026

    @jlipworth
    OwnerAuthor

    Infrastructure update (sanitized): the Jellyfin review change is now on the GitOps deployment branch and Argo observed the deployed revision. The namespace, restricted policies/RBAC, both Longhorn PVCs, service, bounded CronJobs, monitoring rule, and checksum-pinned media seed reconciled. The live seed Job completed and verified the prepared Blender open-film release; the completed Job also remained stable across Argo retries rather than downloading it repeatedly. Target-based unit, Kustomize client/server dry-run, and isolated real-Jellyfin ingest/direct-play/byte-range integration checks passed before promotion.

    The live close-loop is not complete. ExternalSecret/jellyfin-review-credentials is Ready=False (SecretSyncedError) because the private Infisical entry /kubernetes/apps/jellyfin-review does not yet exist. No target Secret was created, so Argo correctly stopped before the Jellyfin Deployment and hostname-derived Certificate/IngressRoute. Consequently there is no live endpoint yet, and public DNS/TLS, /health, reviewer authentication, Movies/Shows/Music browse with the Blender artwork, actual live playback/download, reset, and off-LAN checks could not be run. Bounded Job/events/log inspection found this missing-secret gate and no media-seed failure.

    Exact human gate (values must remain private): create ADMIN_PASSWORD, ADMIN_PASSWORD_PREVIOUS (initially equal), REVIEW_PASSWORD, and PUBLIC_HOSTNAME at that Infisical path; then create the proxied publicly resolvable DNS record for the selected hostname. After External Secrets and Argo retry successfully, the live smoke/reset and off-LAN iPhone/iPad journey still must pass before this can be called closed.

    GitLab MR !321 is superseded by the owner-authorized direct deployment; its source is aligned with the deployment branch and has no intended merge delta.

  5. jlipworth commented on Aug 23, 2026

    @jlipworth
    OwnerAuthor

    Sanitized infrastructure close-loop update: the selected hostname now has an explicit Cloudflare-proxied public A record managed by the existing Kubernetes DDNS workflow. The protected API check confirmed the record is present and proxied without displaying its content. LAN resolvers now CNAME that same hostname to Cloudflare's public edge, so on-LAN traffic does not bypass the selected public path.

    External Secrets reconciled the four private values (Ready=True) without displaying them. Argo completed successfully at the deployment revision and both the Jellyfin and DDNS Applications are Synced/Healthy. The Jellyfin Deployment is 1/1 ready, the media seed remains complete, the Certificate is Ready, and the TLS IngressRoute is active. During live rollout validation I corrected three deployment-only issues found in the real environment: insufficient config-PVC headroom, the post-DNAT Kubernetes API egress port needed by the least-privileged edge reconciler, and Cloudflare rejecting urllib's generic default user agent. All fixes landed directly on k8s_deployment and reconciled successfully.

    Deployed public-path validation passed: trusted TLS and /health; reviewer authentication with the non-admin/download-enabled policy; hidden admin absent from the public user list; Movies, Shows, and Music browse; Spring and Wing It! presence and primary artwork loading; actual 64 KiB byte-range playback and download from Spring; video/audio/subtitle streams and chapters; and the public attribution page. A deliberately created reviewer favorite was then removed by the real reset Job, which reported nine catalog records restored, and a fresh sign-in confirmed clean state. The scheduled (not only manual) public smoke also completed successfully. Independent external probes in North America and Europe both received HTTP 200 with authorized TLS, providing an off-LAN path check.

    The deployed infrastructure validation loop is closed. A final physical TestFlight journey on the required iPhone/iPad families (including offline download playback and UI-level browse/detail/seek/subtitle behavior) remains a human device/App Review gate; this infrastructure result does not claim that device-level gate has run.

  6. jlipworth commented on Sep 15, 2026

    @jlipworth
    OwnerAuthor

    Reviewed screenshot/provenance branch 7f93e1e without merging: nine screenshot tooling tests pass; the plan distinguishes synthetic placeholders from final app captures and preserves required display-class, attribution and age-suitability gates. Actual screenshots, normal review-account login and exact TestFlight reviewer journeys remain open. Separate privacy follow-up #325 reconciles the public no-developer-backend claim with this project-operated review/demo service; infrastructure evidence alone does not approve privacy disclosures or close #280.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions