Prove authenticated member paths through the real public edge.
This harness runs from outside the VPS against the final HTTPS origin with a disposable member created by an operator-only provisioning command. It verifies login, account posture, library/media access, byte-range delivery, explicit download policy, non-authoritative checkout returns, and owner gate exposure without printing recovery secrets.
Create the disposable member on the VPS
# Run with the intended VPS environment loaded and the key directory already created.
cargo run -- smoke-member-provision \
--recovery-key-file /secure/operator/nocturne-smoke-recovery-key.txt \
--source-reference external-member-smoke-YYYYMMDD
The provision command creates one age-attested member, confirms recovery custody immediately, grants a short manual thirty_day_pass by default, and prints the exact external smoke command with the generated member ID. It stores no email, raw IP address, user-agent, ID document, or plaintext recovery key.
--recovery-key-file. The file must not already exist, is written with 0600 permissions on Unix, and should be copied only through the operator's secure channel. --allow-stdout-key exists only as an explicit disposable-test escape hatch.Run after the public edge smoke and provisioning pass
chmod 600 /secure/operator/nocturne-smoke-recovery-key.txt
NOCTURNE_PUBLIC_ORIGIN=https://members.final-domain.example \
NOCTURNE_SMOKE_MEMBER_ID=nctm_disposable_member \
NOCTURNE_SMOKE_RECOVERY_KEY_FILE=/secure/operator/nocturne-smoke-recovery-key.txt \
make external-member-smoke
The script also accepts the origin as its first argument. The recovery key should come from a local file whenever possible so it does not land in shell history. Environment fallback exists for private disposable tests, and NOCTURNE_SMOKE_RECOVERY_KEY_STDIN=1 can read one piped line.
What must exist before running it
- The final HTTPS origin resolves externally and external edge smoke passes from outside the VPS network.
- The app runs in the intended production-edge profile behind the selected Caddy/nginx template or equivalent reverse proxy.
- A disposable member exists from
smoke-member-provision, can log in with its recovery key, has confirmed self-custody recovery, and has active entitlement to the preview catalog/media. - The private media fixture for
asset_preview_still_001exists underNOCTURNE_MEDIA_ROOT, remains outside the public static/docs root, and keepsdownload_allowedpolicy for this fixture. - Owner dashboard posture is intentional: either disabled with no owner key, or enabled but gated by the owner key/cookie flow.
The local seed helper remains local-profile-only. Use smoke-member-provision for private VPS validation because it is non-destructive, writes the generated recovery key to an operator file by default, and grants only short-lived smoke access.
What the member smoke proves
| Check | Expected result | Why it matters |
|---|---|---|
/login | Login form renders, disposable credentials authenticate, and a session cookie is accepted through the proxy. | Confirms secure-cookie/browser session posture works at the final origin. |
/account | Private account page renders with recovery-confirmed posture. | Confirms self-custody recovery confirmation gates member-only access as intended. |
/library | Preview entitlement and the expected fixture media link render. | Confirms entitlement checks survive external HTTPS routing. |
/media/asset_preview_still_001 | Media detail page exposes inline viewer and explicit download affordance. | Confirms member media is gated through app routes rather than public files. |
/media/.../file with Range: bytes=0-9 | 206, Content-Range, and Accept-Ranges. | Confirms video-friendly byte-range delivery works through the proxy without reading whole files into memory. |
/media/.../download with range | 206 plus attachment Content-Disposition. | Confirms download policy stays explicit and separate from inline viewing. |
/checkout, /checkout/start, success return | Checkout session is created, success route renders, and browser return stays non-authoritative. | Confirms the provider-neutral checkout skeleton cannot grant access without provider-proof replay. |
/owner | Disabled, unauthorized, or non-dashboard gate body; never an unlocked owner surface without auth. | Confirms private review tools are not accidentally exposed at the public edge. |
/logout | The smoke session is closed at the end. | Keeps disposable external testing from accumulating live browser sessions. |
What to fix first
- Login fails: verify the member ID/key pair, recovery-key rotation state, secure-cookie settings, final HTTPS origin, and proxy cookie/header forwarding.
- Account is not recovery-confirmed: stop and confirm the disposable key through the normal recovery-confirmation flow before rerunning.
- Library/media fails: verify entitlement status, catalog fixture visibility, media storage key, private media root mount, quarantine state, and media rate limits.
- Range returns
200or misses headers: inspect proxy buffering/range handling and app media response headers before using video fixtures. - Download route fails: confirm the asset uses
download_allowed; view-only assets must not pass this fixture check. - Checkout success grants access: treat it as a blocking bug. Browser returns must remain status-only until provider-proof replay records a paid proof.
- Owner returns an unlocked dashboard: remove public owner bypasses, verify the owner key digest/session config, and rerun production preflight before any invite testing continues.
After a passing smoke
cargo run -- smoke-member-cleanup \
--member-id nctm_disposable_member \
--confirm-smoke-member-cleanup
rm -f /secure/operator/nocturne-smoke-recovery-key.txt
cargo run -- payment-checkout-expire
- Run
smoke-member-cleanupfor the disposable member. It revokes active entitlements and active sessions, but keeps pseudonymous records for audit continuity. - Delete the local recovery-key file from the operator workstation or move it back to the sealed credentials store.
- Expire stale checkout sessions with
payment-checkout-expirebefore wider private testing. - Record the date, origin, app commit, proxy type/version, and pass/fail output through
deployment-evidence-recordwith artifact hashes instead of pasted logs or recovery secrets. - Run
production-preflightlocally on the VPS again after any proxy/app changes, record sealed backup dump/media hashes withbackup-manifest-record, record encrypted/offsite custody withbackup-custody-record, then runprivate-vps-readinessbefore widening private testing.
What this smoke does not prove
- It does not prove live payment provider approval, webhook signature verification, subscription cancellation sync, or tax/accounting packaging.
- It does not prove WAF/rate-limit tuning, DDoS resilience, abuse escalation, or trust/safety response SLA readiness.
- It does not prove backup encryption, offsite retention, or a completed restore drill.
- It does not replace manual playback QA for larger real video files, mobile browsers, or scroll-driven visual presentation work.
- It does not authorize public launch; it is private external-test evidence only.