Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ tokio-tungstenite = { version = "0.30", default-features = false, features = [
"handshake",
"rustls-tls-native-roots",
] }
# Named directly only so the binary can install a crypto provider by name. See
# `install_crypto_provider`: rustls otherwise picks one from crate features and
# panics at the first handshake when the resolution enables neither provider or
# both, and with no lockfile that is not fixed at any point in time.
rustls = { version = "0.23", default-features = false, features = [
"aws-lc-rs",
"std",
] }
futures-util = { version = "0.3", default-features = false, features = ["sink"] }
tokio = "1"
url = "2.5"
Expand Down
1 change: 1 addition & 0 deletions apps/chuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ url.workspace = true
serde.workspace = true
serde_json.workspace = true
tauri = { workspace = true, optional = true }
rustls.workspace = true
tauri-runtime-blitz.workspace = true
tokio-tungstenite.workspace = true
futures-util.workspace = true
Expand Down
24 changes: 23 additions & 1 deletion apps/chuzz/build.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
use std::process::Command;

// Everything below is the embedded browser chrome, which only a `gui` build
// compiles. Off that feature these are dead, and an unused import is a warning
// the workspace denies.
#[cfg(feature = "gui")]
use std::fs;
#[cfg(feature = "gui")]
use std::io::Write;
#[cfg(feature = "gui")]
use std::path::{Path, PathBuf};
use std::process::Command;

#[cfg(feature = "gui")]
use brotli::CompressorWriter;

#[cfg(feature = "gui")]
const CSS_MARKER: &str = "__CHUZZ_EMBEDDED_CSS__";
#[cfg(feature = "gui")]
const JS_URL: &str = "chuzz://ui/__chuzz__/app.js";

/// First line of a command's stdout, or `None` when it fails or prints nothing.
Expand Down Expand Up @@ -51,6 +61,7 @@ fn stamp_build() {
println!("cargo:rerun-if-changed=src");
}

#[cfg(feature = "gui")]
fn only_file_with_extension(directory: &Path, extension: &str) -> PathBuf {
let mut matches = fs::read_dir(directory)
.unwrap_or_else(|error| panic!("cannot read {}: {error}", directory.display()))
Expand All @@ -68,6 +79,7 @@ fn only_file_with_extension(directory: &Path, extension: &str) -> PathBuf {
path
}

#[cfg(feature = "gui")]
fn compress_asset(path: &Path, output: &Path, quality: u32) -> usize {
let input =
fs::read(path).unwrap_or_else(|error| panic!("cannot read {}: {error}", path.display()));
Expand All @@ -84,6 +96,7 @@ fn compress_asset(path: &Path, output: &Path, quality: u32) -> usize {

/// Compile and Brotli-embed the Solid browser chrome using the same asset
/// loading shape as AgencyZero's Blitz document factory.
#[cfg(feature = "gui")]
fn build_frontend() {
let manifest_dir = PathBuf::from(
std::env::var_os("CARGO_MANIFEST_DIR").expect("Cargo sets CARGO_MANIFEST_DIR"),
Expand Down Expand Up @@ -170,6 +183,15 @@ fn strip_unused_frameworks() {
fn main() {
strip_unused_frameworks();
stamp_build();
// The Solid browser chrome, consumed only by `frontend.rs`, which is itself
// behind `gui`. Building it unconditionally meant `cargo build --bin
// chuzz-headless --no-default-features` shelled out to `bun run build` for
// assets that binary never links, and then failed on any machine where
// `apps/chuzz/frontend/node_modules` was not installed. That is every CI
// runner using the headless-host action, which installs the site's
// dependencies and has no reason to install this crate's. It took the whole
// fleet's QA red.
#[cfg(feature = "gui")]
build_frontend();
// Generates the Tauri context, which only the `chuzz-gui` binary consumes.
// A headless build has no `tauri` in its graph for the context to describe,
Expand Down
4 changes: 4 additions & 0 deletions apps/chuzz/src/headless_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
use chuzz_gui::serve;

fn main() {
// Before the loader can reach the network. See the function's own comment
// for why the provider is named here rather than left to the resolution.
chuzz_gui::install_crypto_provider();

let args: Vec<String> = std::env::args().collect();
let target = match serve::target_from(&args) {
Ok(target) => target,
Expand Down
22 changes: 22 additions & 0 deletions apps/chuzz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@
//! the harness, so the harness measured a browser nobody ships. There is one
//! loader now, and one place a gap gets fixed.

/// Name the TLS provider, rather than letting the resolver imply one.
///
/// `rustls` selects its cryptographic provider from crate features, and panics
/// at the first handshake when the graph enables neither `ring` nor `aws-lc-rs`
/// or enables both. Features are additive across a dependency graph, so which
/// of those holds is an outcome of resolution rather than a decision anyone
/// made. This repository commits no lockfile, so it is not fixed at any point
/// in time either: one crate picking up `ring` in a later release is enough to
/// turn every `https://` fetch and every `wss://` connection into a panicked
/// worker on the next runner that resolves it.
///
/// It presents as a site bug rather than a browser one. The socket never
/// opens, Solid halts reactivity on the escaped error, and the page collapses
/// to unnamed nodes, so a QA run reports a broken site.
///
/// Both binaries call this before anything can reach the network. An `Err`
/// means a provider is already installed, which is the outcome being asked
/// for, so it is discarded.
pub fn install_crypto_provider() {
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
}

// The window and its Tauri command surface. Behind `gui` because `tauri` is,
// and because a headless build has no window to drive.
#[cfg(feature = "gui")]
Expand Down
5 changes: 5 additions & 0 deletions apps/chuzz/src/tauri_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ fn flag_value(args: &[String], flag: &str) -> Option<String> {
}

fn main() {
// Before any of the entry points below can reach the network. See the
// function's own comment for why the provider is named here rather than
// left to the resolution.
chuzz_gui::install_crypto_provider();

// Before `--capture`, and matched by equality rather than by prefix, so the
// two flags cannot be confused for each other in either direction.
#[cfg(feature = "capture")]
Expand Down
Loading