summaryrefslogtreecommitdiff
path: root/docs/CHAT-PRODUCTION.txt
diff options
context:
space:
mode:
Diffstat (limited to 'docs/CHAT-PRODUCTION.txt')
-rw-r--r--docs/CHAT-PRODUCTION.txt247
1 files changed, 247 insertions, 0 deletions
diff --git a/docs/CHAT-PRODUCTION.txt b/docs/CHAT-PRODUCTION.txt
new file mode 100644
index 0000000..7e0e315
--- /dev/null
+++ b/docs/CHAT-PRODUCTION.txt
@@ -0,0 +1,247 @@
+Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+PRODUCTION CHAT INTEGRATION
+
+ Implemented on feature/private-chat. Building and testing a release does not
+ merge main or activate the VPS. This is experimental software without an
+ independent cryptographic or application security audit. Read the limitations
+ in CHAT-APPLICATION.txt before using it for private conversations.
+
+ Four services run through rootless Podman: Caddy, cgit, SearXNG, and chat.
+ The release contains statically linked x86_64 GNU/Linux management and chat
+ binaries, the WASM browser module, exact corresponding sources, and saved
+ native container images. The chat image starts FROM scratch: no compiler,
+ shell, package manager, or first-party Python. Its root filesystem is read
+ only, capabilities are dropped, and only its private data directory is writable.
+
+ Caddy terminates HTTPS at CHAT_HOST and redirects www.CHAT_HOST while keeping
+ the requested path. CHAT_UPSTREAM defaults to chat:8080 on the private
+ container network. Chat publishes no host ports. Production publishes only
+ the gateway HTTP and TCP/UDP HTTPS ports. Existing host SSH policy is separate.
+
+ The gateway supplies an explicit external origin selected from root .env.
+ The server accepts that exact HTTPS origin or the dedicated local gateway
+ origin. Forwarded client headers never select the trusted origin. Origin
+ checks supplement cryptographic authentication; they are not authentication.
+
+BUILD ON THE WORKSTATION
+
+ Current releases require an x86_64 GNU/Linux build host and matching target.
+ Use the pinned Rust toolchain, Podman, Git, GnuPG, a GCC-compatible C compiler,
+ Linux UAPI headers, libclang, pkg-config, make, Perl, curl, and tar. Native
+ workspace checks need OpenSSL 3.5+ development libraries. Browser testing
+ additionally needs Node, Playwright, Chromium, and Firefox. These tools remain
+ on the workstation; production does not need Cargo or a compiler.
+
+ cargo stack release
+
+ This runs formatting, strict Clippy, all workspace tests, rustdoc, cargo-deny,
+ and cargo-about. It then builds static native binaries, the WASI module,
+ corresponding sources, the chat/cgit images, and the complete image export.
+ THIRD-PARTY-LICENSES.html is regenerated from the full workspace before
+ packaging. Check the archive checksum and test recovery before deployment.
+
+ infra/chat/build-native.sh verifies OpenSSL 3.6.5's original source archive:
+ a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98
+ It verifies Alpine musl-dev 1.2.6-r3 headers:
+ 310b51cff12e1d5ce5f135c558a82e2550427da5465bbd16c9ff9b05e63ee3d9
+ Sources come from the official OpenSSL GitHub release and Alpine CDN. The
+ compiler uses isolated musl/GCC built-in headers plus host Linux UAPI headers;
+ glibc headers are excluded. OpenSSL is static, has no dynamic providers, and
+ seeds its RNG through getrandom. The native cryptographic compatibility probe
+ must pass after the build. WASI uses its separately verified SDK and OpenSSL
+ build recorded in CHAT-OPENSSL-MIGRATION.txt. No crypto algorithm was changed.
+
+ Cached inputs live only under .tools/. Rebuild OpenSSL when its version,
+ source, or build flags change. An OpenSSL update requires reviewing upstream
+ security notices, updating every affected URL/hash, native and WASI rebuilds,
+ rerunning both browsers and cargo-deny, regenerating notices and exact source,
+ and repeating release recovery. Never approve a dependency advisory merely
+ to make the build pass. cargo-deny does not audit C/OpenSSL advisories.
+
+ The source download includes first-party code, Cargo-vendored dependencies,
+ and unmodified OpenSSL source. Toolchain/sysroot development inputs are not
+ bundled as application sources. Saved images preserve the tested runtime.
+ An ARM host needs a separately supported native release; do not copy these
+ x86_64 binaries there and assume they will work.
+
+LOCAL MODES AND ORIGIN BINDING
+
+ Direct Rust development:
+ cargo stack chat
+ http://127.0.0.1:9080/
+ var/data/chat
+
+ Container preview:
+ cargo stack dev
+ http://chat.localhost:8080/
+ var/data/chat-local
+
+ Production:
+ ./bin/stack up --production
+ https://CHAT_HOST/ with the configured HTTPS_PORT
+ var/data/chat
+
+ These are distinct browser origins and require separate identity files. The
+ direct process and production deliberately use the same relative database
+ name on their respective machines. Do not switch an installation containing
+ valuable identities between direct development and production. Use a fresh
+ restored release directory for integration tests. Rebuild the release after
+ edits to refresh the packaged browser, server, sources, notices, and image.
+
+ The single root .env holds public hostnames, ports, upstreams, backup settings,
+ SEARXNG_SECRET, and CHAT_SETUP_TOKEN. The example is public; actual .env is
+ ignored and never included in public releases or source downloads. Caddy keys
+ and chat databases are generated private runtime state under var/data.
+ Initialization preserves configured values and generates missing secrets.
+
+DEPLOY AND CREATE THE REAL OWNER FILE
+
+ Use the release upload/activation instructions in OPERATIONS.txt. Extract
+ the new prebuilt management binary into var/incoming/bootstrap and invoke
+ it with --root pointing at the current installation. The older three-service
+ management binary cannot parse the new chat service schema; do not use that
+ older binary to activate this release. The new binary verifies the archive
+ and installs packaged chat artifacts before starting services.
+ The host needs rootless Podman prerequisites, user linger, low-port permission,
+ DNS A/AAAA records for CHAT_HOST and www.CHAT_HOST, and the normal 80/443
+ firewall rules. Caddy obtains and renews public certificates automatically.
+ Public certificate validation requires standard reachable ACME ports.
+
+ The systemd user service runs ./bin/stack up --production at boot and
+ ./bin/stack down on stop. Podman restart policies restart failed containers.
+ Neither mechanism compiles code or requests a registry pull for a complete
+ release on the matching architecture. Check all four services after activation:
+
+ ./bin/stack status
+
+ Check HTTPS, HTTP-to-HTTPS and www redirects, the homepage Services entry,
+ /LIMITATIONS.txt, /javascript.html, and /SOURCE.tar.gz on the chat origin.
+ The displayed limitations are CHAT-APPLICATION.txt. Chat has its own origin;
+ the main website remains JavaScript-free. Its Message Me links lead to chat.
+
+ In the browser on the production HTTPS origin, choose OWNER SETUP. Read the
+ setup token from the production root .env locally; never publish it or send it
+ through chat. Choose a unique owner-file password, save the downloaded file,
+ reopen it, and unlock it. Store that file and password in KeePassXC and keep
+ a protected backup of the database. The setup token cannot replace this file.
+ Never copy a development owner file and silently change its pinned origin.
+
+BACKUP, RESTORE, AND KEY LOSS
+
+ A complete encrypted application export:
+ ./bin/stack backup --include-images
+
+ Download the .gpg and .sha256 files off the VPS. A backup on the same VPS is
+ vulnerable to loss of that VPS. Existing configured backup recipients apply.
+ This export includes the single .env, consistent SQLite snapshots for chat
+ and chat-local, Caddy certificate state, repositories, static binaries, WASM,
+ sources, and exact container images. SQLite uses its online backup API; chat
+ is left unpaused so a pending writer cannot block snapshot completion.
+ The database contains ciphertext and public keys, plus the metadata described
+ in CHAT-APPLICATION.txt. The owner private file and GnuPG secret key are not
+ server data; back them up separately.
+
+ Restore to a new directory, verify, then explicitly start production mode:
+ ./bin/stack restore /path/export.tar.gz.gpg /path/stack-restored
+ cd /path/stack-restored
+ ./bin/stack up --production
+
+ Restore defaults to local mode and changes container project names to avoid
+ accidentally replacing another installation. up --production selects the
+ production database and HTTPS origin again. Keep the same hostname/origin,
+ point DNS at the replacement host, and use unchanged owner/visitor files and
+ passwords. A new IP does not change an origin. A changed hostname or HTTPS
+ port does. Do not expose two restored copies simultaneously under one origin.
+ Server restart invalidates sessions; reopening identity files authenticates
+ again. Historical ciphertext and counters persist across restart and recovery.
+
+ Losing the owner private file cannot be repaired by CHAT_SETUP_TOKEN. If its
+ backups are also lost, reset deliberately deletes every stored conversation
+ and message. It does not decrypt or recover anything. This backend operation
+ has no HTTP endpoint and requires filesystem/Podman access:
+
+ ./bin/stack chat --owner-fingerprint
+ ./bin/stack down
+ ./bin/stack chat --reset-owner PASTE_CURRENT_OWNER_FINGERPRINT_HERE
+ ./bin/stack up --production
+
+ A running server holds a filesystem lock; reset refuses until it stops. The
+ full fingerprint must match. Root .env and previous exports are preserved.
+ Create a new production owner file afterward. Old visitor files reject its
+ changed pinned owner key and need a new chat identity. A reset does not erase
+ copies already present in exports or external snapshots.
+
+VERIFICATION
+
+ The browser harness supports packaged HTTPS installations without Rust or
+ target/ inside them. It creates disposable identities and a separate temporary
+ GnuPG key, takes a complete encrypted export with images during live chat,
+ restores into a new directory, starts the saved images, and reopens the same
+ files to decrypt history. It also exercises wrong passwords, safe text,
+ counters, 0-to-N history, 50-row batches, retry deduplication, origin rejection,
+ browser storage checks, and backend reset guards. It never resets real data.
+
+ Example after restoring a release to a disposable staging directory and
+ configuring fixture .localhost hostnames, WEB_BIND=127.0.0.1, HTTP_PORT=8181,
+ HTTPS_PORT=8443, and LOCAL_HTTP_PORT=8180:
+
+ ./bin/stack up --production
+ CHAT_TEST_ROOT=/absolute/disposable/stack CHAT_TEST_ORIGIN=https://chat.fixture.localhost:8443 PLAYWRIGHT_BROWSERS_PATH=.tools/browsers node crates/chat-server/tests/browser.mjs
+
+ Run from the source checkout for the harness and Playwright installation.
+ Add CHAT_LIBREJS=1 for Firefox with the actual GNU LibreJS add-on. That test
+ verifies the add-on is active and blocks an unlicensed control script.
+ Disposable staging needs a fresh database for each complete run.
+
+ Browser automation permits the fixture's private CA only for functional tests.
+ Separately verify its chain and hostname with curl --cacert and --resolve;
+ test the canonical route and www redirect without disabling verification.
+ Production uses ordinary trusted public certificates with no TLS bypass.
+ Passing these checks demonstrates recovery and functional compatibility; it
+ does not establish absence of attacks or constitute an independent audit.
+
+RECORDED RESULTS, 2026-10-31
+
+ The complete native workspace check passed: formatting, strict Clippy,
+ 14 tests, private rustdoc, cargo-deny with no ignored advisories, and
+ cargo-about generation. Static musl and WASI OpenSSL 3.6.5 probes passed
+ without changing the required RFC 9980 algorithms.
+
+ Direct development passed in Chromium. Packaged HTTPS passed independently
+ in Chromium and Firefox with GNU LibreJS 7.21.1 active; its unlicensed-script
+ control was rejected. Both packaged tests recovered a complete encrypted
+ application export, including saved images, into a new directory, then
+ reopened the unchanged owner/visitor files and decrypted the history.
+ Export and checksum permissions were verified as 0600.
+
+ Runtime inspection verified read-only root filesystem, zero effective
+ capabilities, no chat host ports, and unless-stopped restart policy. Killing
+ the disposable chat process with SIGKILL caused an automatic restart, and
+ its owner fingerprint persisted. The supplied systemd user unit passed
+ systemd-analyze verification; this did not reboot the real VPS.
+
+ curl independently verified the fixture CA chain and hostname for canonical
+ chat, www redirect, and homepage. The homepage Services limitations link
+ resolved correctly. The source download matched the packaged source archive
+ byte-for-byte and contained only .env.example, without actual .env.
+
+ Upgrade testing started the 2026-10-30 three-service release, then activated
+ the chat-enabled release through its new prebuilt management binary. All
+ four services started, existing data and SearXNG secret persisted, and the
+ new owner setup token was generated in the same root .env. These tests used
+ disposable local data; they did not register a real production owner.