diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/CHAT-APPLICATION.txt | 79 | ||||
| -rw-r--r-- | docs/CHAT-DESIGN.txt | 4 | ||||
| -rw-r--r-- | docs/CHAT-OPENSSL-MIGRATION.txt | 5 | ||||
| -rw-r--r-- | docs/CHAT-PRODUCTION.txt | 247 | ||||
| -rw-r--r-- | docs/CHAT-SECURITY-REVIEW.txt | 5 | ||||
| -rw-r--r-- | docs/CONFIGURATION.txt | 35 | ||||
| -rw-r--r-- | docs/OPERATIONS.txt | 45 | ||||
| -rw-r--r-- | docs/POLICY.txt | 12 |
8 files changed, 375 insertions, 57 deletions
diff --git a/docs/CHAT-APPLICATION.txt b/docs/CHAT-APPLICATION.txt index 7e58051..28c576b 100644 --- a/docs/CHAT-APPLICATION.txt +++ b/docs/CHAT-APPLICATION.txt @@ -16,9 +16,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. EXPERIMENTAL PRIVATE CHAT - Branch: feature/private-chat. This application is for local testing. - Production remains on main with its under-construction Message Me page. - No public chat service, TLS route, or new production identity was deployed. + Available on main. Direct development and a prebuilt Podman/HTTPS + deployment path are implemented. See CHAT-PRODUCTION.txt for the release, + production setup, and recovery procedure; feature work does not itself merge + main or activate the VPS. This is working experimental software, not an independently audited messenger. WHAT EXISTS @@ -28,6 +29,13 @@ WHAT EXISTS a capability-limited WASI host. Text is displayed through textContent. SearXNG and the other existing services are unchanged. + Startup shows an ASCII download bar, percentage, and received/total MiB + while fetching the cryptographic module. If its size is unavailable, it shows + received MiB. A 45-second gap without download progress aborts with a reload + instruction; slow transfers continue while bytes arrive. After download, + a separate status identifies the connection to chat. No browser cache or + storage was added. + Visitors choose CREATE NEW CHAT or OPEN CHAT FILE. Creation generates a purpose-specific identity locally and downloads its protected file. Reopening the exact downloaded file and entering its password is required before the @@ -49,7 +57,7 @@ WHAT EXISTS LOCAL PREREQUISITES AND COMMANDS - Start in the root of the stack repository on feature/private-chat. Native + Start in the root of the stack repository on main. Native development needs Rust, libclang, OpenSSL 3.5 or newer development libraries, a C compiler, pkg-config, make, Perl, curl, and tar. The checked configuration uses OpenSSL 3.6.5. The WASI build script currently targets an x86_64 GNU/Linux @@ -97,12 +105,11 @@ LOCAL PREREQUISITES AND COMMANDS Stop the development server with Control-C. A server restart invalidates all sessions but preserves identities, conversations, counts, and ciphertext. - The server currently refuses a non-loopback bind or an origin that does not - exactly match its development bind address. HTTP is allowed only for the - explicit loopback development origin. The intended production origin remains - https://chat.doan.luuduct.ai/. Production Podman packaging, TLS configuration, - operational review, and a main-branch merge remain separate work. Do not - expose this experimental development service through a public proxy. + The direct development server refuses a non-loopback bind or an origin that + does not exactly match its development bind address. Packaged production uses + a private container listener behind Caddy HTTPS, with an explicit external + CHAT_HOST/HTTPS_PORT origin. Forwarded request headers do not choose that + origin. Do not expose the direct development server through a public proxy. OWNER FILE LOSS AND BACKEND RESET @@ -116,9 +123,11 @@ OWNER FILE LOSS AND BACKEND RESET Run these commands locally at the stack root for the current development build. There is no reset operation in the HTTP API. Filesystem access to - the private chat directory is the administrative boundary. A future production - package must expose the same options through its prebuilt server binary; - do not install Rust on the VPS for these development commands. + the private chat directory is the administrative boundary. Production uses + ./bin/stack chat --owner-fingerprint and ./bin/stack chat --reset-owner + through an isolated maintenance container. Stop production with ./bin/stack + down first; restart with ./bin/stack up --production. No Rust is needed on + the VPS. See CHAT-PRODUCTION.txt before a destructive reset. Read the current public fingerprint, even if you have lost the private file: @@ -130,8 +139,8 @@ OWNER FILE LOSS AND BACKEND RESET cargo stack chat --reset-owner PASTE_CURRENT_OWNER_FINGERPRINT_HERE A fingerprint mismatch refuses without deleting data. The server and reset - process share a filesystem lock; reset also requires the loopback service - port to be free. This prevents resetting a running service, including a + process share a filesystem lock. Direct development additionally requires + the loopback service port to be free. This prevents resetting a running service, including a development process launched before the lock was added. Online snapshots and reading the public owner fingerprint remain available while chat is running. @@ -158,11 +167,24 @@ FILE AND MESSAGE CRYPTOGRAPHY a fixed purpose-only user ID. Names are not placed in public certificate IDs. The server rejects uploaded secret-key material and unsupported certificates. - The JSON identity file is an authenticated encrypted envelope. Its fixed - format identifier is authenticated as associated data: + New JSON identity files are indented and use an array of 80-character + Base64 ciphertext chunks; the final chunk may be shorter. JSON indentation, + quotes, and commas are additional to the ciphertext width. The reader joins + the chunks before Base64 decoding. No private fields become plaintext. + This is the application's own JSON envelope, not OpenPGP ASCII armor. + The new file-format identifier is authenticated as associated data: + + stack-chat-file/v2;argon2id-m65536-t3-p1;aes256-gcm + + Existing compact v1 files with one ciphertext string remain supported: stack-chat-file/v1;argon2id-m65536-t3-p1;aes256-gcm + v1 uses its original identifier as associated data. Changing a version label + or converting its field shape does not convert a file: the authentication tag + binds the version. No existing file needs rewriting; old readers do not support + new v2 exports. Cryptographic algorithms and KDF parameters are unchanged. + Argon2id version 0x13 uses 65536 KiB, three passes, one lane, and a 32-byte derived key. A fresh CSPRNG salt of 16 bytes and AES-256-GCM nonce of 12 bytes are generated for each file; the authentication tag is 16 bytes. These KDF @@ -287,7 +309,8 @@ BACKUP, EXPORT, AND RESTORE SQLite's online backup API for chat.sqlite. It does not copy a live SQLite file or journal with ordinary file-copy code. It can take a consistent chat snapshot while the local chat server runs. Existing Podman data still follows - the stack's previous pause/copy/resume process. A database snapshot is atomic + the stack's pause/copy/resume process; the chat container stays unpaused. + Separate snapshots cover both chat and chat-local. A snapshot is atomic for chat data; unrelated services do not share a global transaction with it. The backup includes the single root .env and must remain private/encrypted. @@ -339,6 +362,11 @@ LICENSES, SOURCE, AND VERIFICATION The local check used Alpine musl 1.2.6 headers with the host C compiler for the C object build and Rust's self-contained musl runtime for final linking. + The rendered dependency-license page is centralized on the main website at + https://doan.luuduct.ai/THIRD-PARTY-LICENSES.html. Chat links point there; its + previous local license-page URL redirects there. cgit keeps ordinary source + and raw-file views without a custom HTML renderer. + First-party software is GNU AGPL version 3 or later. Legal license headers are the exception to the no-comments convention. Documentation is plaintext. JavaScript has GNU LibreJS @license/@license-end markers and a linked @@ -368,14 +396,17 @@ LICENSES, SOURCE, AND VERIFICATION cargo stack check PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" node crates/chat-crypto/tests/browser.mjs PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" node crates/chat-server/tests/browser.mjs + PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" node crates/chat-server/tests/progress.mjs Browser automation additionally needs Node, Playwright under .tools/browser, and its browser downloads under .tools/browsers. These are development tools excluded from releases. The fixtures use temporary isolated installation roots with one temporary .env each, and remove their private data on completion. They listen on loopback port 9081 by default (override with CHAT_TEST_PORT), - leaving the normal local preview on 9080 available. They do not initialize - your real owner identity or touch production. + leaving the normal local preview on 9080 available. The optional packaged + HTTPS variant is documented in CHAT-PRODUCTION.txt and retains its disposable + installation roots for inspection. Tests do not initialize the real owner + identity or touch the VPS. LibreJS verification uses the Mozilla-distributed GNU LibreJS 7.21.1 in Playwright Firefox 157.0, without whitelisting the application. The full chat @@ -402,9 +433,11 @@ LICENSES, SOURCE, AND VERIFICATION live database snapshot restoration with both original identity files, owner setup/access controls, refusing reset while running or with a mismatched fingerprint, successful backend reset and fresh registration, rejecting old - visitor key pins, in-flight - lock, back/forward restoration, and checks for plaintext persistence or private - credential uploads. + visitor key pins, in-flight lock, back/forward restoration, and checks for + plaintext persistence in the database/journals or private credential uploads. + The packaged variant additionally verifies certificate trust/hostname through + curl, restrictive export permissions, and full encrypted recovery with saved + images and no build directories inside the recovered installation. Native tests cover authorization, challenge reuse, expiry, locked sessions, quotas, idempotency, and SQLite snapshot recovery. See CHAT-DESIGN.txt and CHAT-OPENSSL-MIGRATION.txt for the design and historical backend review. diff --git a/docs/CHAT-DESIGN.txt b/docs/CHAT-DESIGN.txt index d85ad44..fa2ad1b 100644 --- a/docs/CHAT-DESIGN.txt +++ b/docs/CHAT-DESIGN.txt @@ -16,10 +16,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. PRIVATE CHAT DESIGN AND LIMITATIONS - Status: experimental local implementation on feature/private-chat. + Status: experimental implementation on feature/private-chat. CHAT-APPLICATION.txt records the implemented formats, behavior, commands, tests, and current limitations. This document preserves the original design. - Nothing is deployed to production. + CHAT-PRODUCTION.txt records the later packaged deployment path. USER EXPERIENCE diff --git a/docs/CHAT-OPENSSL-MIGRATION.txt b/docs/CHAT-OPENSSL-MIGRATION.txt index 17149ac..9e63730 100644 --- a/docs/CHAT-OPENSSL-MIGRATION.txt +++ b/docs/CHAT-OPENSSL-MIGRATION.txt @@ -17,8 +17,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. OPENSSL BACKEND MIGRATION RECORD Date: 2026-10-30. Branch: feature/private-chat. - Scope: a compatibility and dependency-security experiment, not a messenger. - Main and production are unchanged. No real identity files are created. + Scope at this checkpoint: a compatibility and dependency-security experiment. + The later messenger and packaged deployment are described separately in + CHAT-APPLICATION.txt and CHAT-PRODUCTION.txt. Tests use disposable identities. DECISION AND FIXED ALGORITHMS diff --git a/docs/CHAT-PRODUCTION.txt b/docs/CHAT-PRODUCTION.txt new file mode 100644 index 0000000..c1a2402 --- /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 main after merging the original feature/private-chat branch. + Building and testing a release does not 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. diff --git a/docs/CHAT-SECURITY-REVIEW.txt b/docs/CHAT-SECURITY-REVIEW.txt index 4567322..6257f3c 100644 --- a/docs/CHAT-SECURITY-REVIEW.txt +++ b/docs/CHAT-SECURITY-REVIEW.txt @@ -18,8 +18,9 @@ CHAT CRYPTOGRAPHY SECURITY REVIEW Date: 2026-10-30. Historical review of the initial Rust backend. The current OpenSSL migration is recorded in CHAT-OPENSSL-MIGRATION.txt. - Private-message use and production deployment are still not ready. - Branch: feature/private-chat. Production and main remain unchanged. + At that checkpoint, private-message use and deployment were not ready. + This historical review is not the current implementation status; see + CHAT-APPLICATION.txt and CHAT-PRODUCTION.txt for the implemented application. FIXED REQUIREMENT diff --git a/docs/CONFIGURATION.txt b/docs/CONFIGURATION.txt index 9660e20..fc18c41 100644 --- a/docs/CONFIGURATION.txt +++ b/docs/CONFIGURATION.txt @@ -33,10 +33,17 @@ PUBLIC SETTINGS Root web/WKD domain. www aliases are derived from each configured host. SITE_HOST, GIT_HOST, SEARCH_HOST, WKD_HOST, CHAT_HOST - Fully qualified DNS names without schemes, paths, or ports. The first - four configure production Caddy routing. CHAT_HOST supplies the intended - public chat link; production chat routing remains unimplemented on this - experimental feature branch. + Fully qualified DNS names without schemes, paths, or ports. These + configure production HTTPS routes and their canonical www redirects. + CHAT_HOST also selects the exact trusted external chat origin. + + CHAT_LOCAL_HOST + Dedicated development gateway hostname ending in .localhost. Default: + chat.localhost. Browser identity files bind to this origin and local port. + + WEB_BIND + Production host publish address. Default :: serves IPv4 and IPv6. Use + 127.0.0.1 for isolated staging; development mode always uses loopback. HTTP_PORT, HTTPS_PORT Production Caddy listener and Podman published ports. HTTPS also publishes @@ -53,16 +60,18 @@ PUBLIC SETTINGS image state remain in var/state.json; an explicit .env local port takes precedence over the previously saved port. - CGIT_UPSTREAM, SEARXNG_UPSTREAM - Proxy connection targets such as cgit:8080 and searxng:8080. These are + CGIT_UPSTREAM, SEARXNG_UPSTREAM, CHAT_UPSTREAM + Proxy connection targets such as cgit:8080, searxng:8080, and chat:8080. These are addresses, not upstream bind settings. The bundled images' internal 8080 listeners and health checks remain image contracts. Changing a target to another host/port requires an actual service at that address. CHAT_BIND, CHAT_ORIGIN - Chat socket and exact browser origin. Default: 127.0.0.1:9080 and - http://127.0.0.1:9080. The experimental server requires loopback and an - exact HTTP origin match. --bind overrides CHAT_BIND for testing. + Direct development socket and exact browser origin. Defaults: + 127.0.0.1:9080 and http://127.0.0.1:9080. Direct development requires + loopback and an exact HTTP origin match. --bind overrides CHAT_BIND. + The container binds privately to 0.0.0.0:8080; its trusted origin comes + from CHAT_HOST/HTTPS_PORT or CHAT_LOCAL_HOST/LOCAL_HTTP_PORT instead. Identity files pin their origin; editing these values does not migrate encrypted identities or grant access on another origin. @@ -77,7 +86,7 @@ PRIVATE SETTINGS Generated on first stack initialization. Existing values are preserved. CHAT_SETUP_TOKEN - Generated by cargo stack chat --init. Used only to authorize first owner + Generated by chat initialization or first stack startup. Used only to authorize first owner registration, including a fresh registration after an explicit backend reset. It cannot recover a lost owner private key. @@ -104,7 +113,7 @@ RENDER AND APPLY Do not run Caddy directly on an unrendered template. Podman mounts the generated files. Public host/origin changes reach Caddy routes, www redirects, website links, the cgit clone prefix, and the chat page's navigation. Local rendering - uses /git and /search paths and the configured local chat origin. + uses /git and /search paths and http://CHAT_LOCAL_HOST:LOCAL_HTTP_PORT for chat. To apply changes to the existing services: @@ -125,8 +134,8 @@ PUBLICATION AND LIMITS The shared stack-config crate uses an explicit public allowlist for template substitution. A {{CHAT_SETUP_TOKEN}} or other private/unknown placeholder causes an error rather than publishing its value. Generated public pages and - proxy configuration never receive a full environment dump. Each container - still receives only the environment keys listed for that service; Caddy uses + proxy configuration never receive a full environment dump. Chat receives the public configuration allowlist plus CHAT_SETUP_TOKEN; + other containers receive only their declared service secrets. Caddy uses rendered public configuration and does not need the .env or private tokens. The root .env, runtime files, local render outputs, exports, and tool caches diff --git a/docs/OPERATIONS.txt b/docs/OPERATIONS.txt index 2cf4693..5b1da25 100644 --- a/docs/OPERATIONS.txt +++ b/docs/OPERATIONS.txt @@ -103,8 +103,11 @@ EXPORT AND BACK UP PRODUCTION cd ~/stack ./bin/stack backup --include-images - The command briefly pauses the three services while copying consistent + The command briefly pauses Caddy, cgit, and SearXNG while copying their application files, then resumes them before compression and encryption. + Chat remains unpaused so SQLite online backups can complete during active + writes. Consistent snapshots cover both chat and chat-local databases; raw + SQLite journals and server lock files are excluded. It uses the published public key, verifies the recipient fingerprint, checks bare Git repositories, saves exact images, and produces: @@ -261,8 +264,9 @@ MAKE AND DEPLOY A RELEASE cd ~/stack cargo stack release - Release reruns the full check, builds a static Rust binary locally, - builds the cgit container locally, and packages the configured image set. + Release reruns the full check, builds static Rust management and chat + binaries plus the browser WASM module, packages corresponding sources, + builds cgit/chat containers locally, and saves the configured image set. Outputs are dist/stack-release-TIMESTAMP.tar.gz and its .sha256 file. No .env, live data, .git history, or previous backup is included. @@ -291,8 +295,16 @@ MAKE AND DEPLOY A RELEASE cd ~/stack/var/incoming sha256sum -c stack-release-TIMESTAMP.tar.gz.sha256 cd ~/stack - ./bin/stack activate var/incoming/stack-release-TIMESTAMP.tar.gz + mkdir -p var/incoming/bootstrap + tar -xzf var/incoming/stack-release-TIMESTAMP.tar.gz -C var/incoming/bootstrap stack/bin/stack + var/incoming/bootstrap/stack/bin/stack --root "$PWD" activate var/incoming/stack-release-TIMESTAMP.tar.gz ./bin/stack status + rm -rf -- var/incoming/bootstrap + + Use the management binary from the verified new release for activation. + Older binaries can reject a new service schema before installing it. This + bootstrap path handles the upgrade from three services to the chat-enabled + release without installing a compiler or overwriting private configuration. Activation verifies the release and platform, replaces public source and the binary, loads exact images, preserves .env and var/data, and replaces @@ -310,9 +322,11 @@ RECOVERY LIMITS AND SECRET ROTATION Changing CPU architecture requires a native release build. Registry access is needed only when images are omitted or rebuilding for another target. - Current persistent state is files, Git repositories, and Caddy state. - When adding a database, add its supported flush/dump procedure to the - export workflow and test recovery before relying on that database's backup. + Current persistent state includes files, Git repositories, Caddy state, + and encrypted chat records in SQLite. Chat uses the SQLite online backup + API; recovery testing must reopen both participants' unchanged identity + files and decrypt history. See CHAT-PRODUCTION.txt for this release's tests. + Future databases need their own supported snapshot and recovery procedure. If changing the OpenPGP backup recipient, publish its public key, update the command's default fingerprint, and test encryption and restoration. @@ -324,11 +338,14 @@ RECOVERY LIMITS AND SECRET ROTATION The current command intentionally accepts only its verified format-2 archives. Fresh format-2 production backups replace the normal workflow. -LICENSE PAGE IN CGIT +CENTRAL THIRD-PARTY LICENSE PAGE + + cargo-about generates web/THIRD-PARTY-LICENSES.html. Caddy serves the rendered + document at https://doan.luuduct.ai/THIRD-PARTY-LICENSES.html, using the + configured SITE_HOST for other deployments. Website and chat license links + use that same canonical page. Local previews use the local main-site origin. - The stack repository's About tab renders only - web/THIRD-PARTY-LICENSES.html. Source and Raw links retain the normal cgit - views and preserve revision queries. Other files are not rendered as HTML. - The rendered document is isolated in a sandboxed frame, with scripts and - external resources blocked. The standalone website license page remains - available at /THIRD-PARTY-LICENSES.html. + cgit no longer has a custom license renderer, Lua filter, or license About + tab. The generated file remains accessible through its normal Source and Raw + views in the repository. The old chat /THIRD-PARTY-LICENSES.html URL redirects + to the canonical site page. Source exports retain license texts for offline use. diff --git a/docs/POLICY.txt b/docs/POLICY.txt index f662dd4..16d97c2 100644 --- a/docs/POLICY.txt +++ b/docs/POLICY.txt @@ -72,7 +72,8 @@ PORTABILITY Host SSH keys, firewall policy, accounts, and disks are host administration, not application export contents. - Releases currently contain a static x86_64 Linux command and native + Releases contain static x86_64 Linux management/chat commands, the WASM + browser crypto module, exact corresponding sources, and native linux/amd64 container images. They are portable across compatible x86_64 Linux machines. An ARM machine needs a native release build; the command rejects mismatched production images. Development mode may fetch/build @@ -82,3 +83,12 @@ PORTABILITY Generated third-party legal texts retain upstream whitespace and line endings. .gitattributes exempts only THIRD-PARTY-LICENSES.html from whitespace errors; first-party source checks remain strict. Workspace audits include every member. + +STATIC ASSET CACHING + + Main-site stylesheet links include the SHA-256 of web/styles.css as a query + version. Update both website templates when CSS changes. The render test + checks that the published URL matches the current stylesheet, preventing + old cached CSS from being paired with new markup. Tooltip text carries the + native hidden attribute as well as CSS visibility rules, so a stylesheet + failure cannot expose it as ordinary page text. |
