feat: Sprint 1 — production hardening, TLS lifecycle, CI coverage, lint cleanup
- Fix 3 client panics: replace .unwrap()/.expect() with proper error handling in rpc.rs (AUTH_CONTEXT lock), repl.rs (pending_member), and retry.rs (last_err) - Add --danger-accept-invalid-certs flag with InsecureServerCertVerifier for development TLS bypass, plus mdBook TLS documentation - Add CI coverage job (cargo-tarpaulin) and Docker build validation to GitHub Actions workflow, plus README CI badge - Add [workspace.lints] config, fix 46 clippy warnings across 8 crates, zero warnings on all buildable crates - Update Dockerfile for all 11 workspace members
This commit is contained in:
@@ -284,6 +284,7 @@ async fn ensure_server(
|
||||
|
||||
// ── REPL entry point ─────────────────────────────────────────────────────────
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn run_repl(
|
||||
state_path: &Path,
|
||||
server: &str,
|
||||
@@ -497,6 +498,7 @@ async fn auto_upload_keys(
|
||||
}
|
||||
|
||||
/// Determine the access token, performing OPAQUE registration/login as needed.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn resolve_access_token(
|
||||
state_path: &Path,
|
||||
server: &str,
|
||||
@@ -715,13 +717,11 @@ fn cmd_list(session: &SessionState) -> anyhow::Result<()> {
|
||||
fn cmd_switch(session: &mut SessionState, target: &str) -> anyhow::Result<()> {
|
||||
let target = target.trim();
|
||||
|
||||
let conv = if target.starts_with('@') {
|
||||
let username = &target[1..];
|
||||
let conv = if let Some(username) = target.strip_prefix('@') {
|
||||
session.conv_store.list_conversations()?.into_iter().find(|c| {
|
||||
matches!(&c.kind, ConversationKind::Dm { peer_username: Some(u), .. } if u == username)
|
||||
})
|
||||
} else if target.starts_with('#') {
|
||||
let name = &target[1..];
|
||||
} else if let Some(name) = target.strip_prefix('#') {
|
||||
session.conv_store.find_group_by_name(name)?
|
||||
} else {
|
||||
// Try as display name
|
||||
@@ -861,7 +861,7 @@ async fn cmd_dm(
|
||||
display_name: format!("@{username}"),
|
||||
mls_group_blob: member
|
||||
.group_ref()
|
||||
.map(|g| bincode::serialize(g))
|
||||
.map(bincode::serialize)
|
||||
.transpose()
|
||||
.context("serialize group")?,
|
||||
keystore_blob: None,
|
||||
@@ -905,7 +905,7 @@ fn cmd_create_group(session: &mut SessionState, name: &str) -> anyhow::Result<()
|
||||
display_name: format!("#{name}"),
|
||||
mls_group_blob: member
|
||||
.group_ref()
|
||||
.map(|g| bincode::serialize(g))
|
||||
.map(bincode::serialize)
|
||||
.transpose()
|
||||
.context("serialize group")?,
|
||||
keystore_blob: None,
|
||||
@@ -1099,7 +1099,7 @@ async fn cmd_join(
|
||||
|
||||
// Try to process with existing groups first
|
||||
let mut handled = false;
|
||||
for (_cid, member) in &mut session.members {
|
||||
for member in session.members.values_mut() {
|
||||
match member.receive_message(&mls_payload) {
|
||||
Ok(_) => { handled = true; break; }
|
||||
Err(_) => continue,
|
||||
@@ -1147,7 +1147,7 @@ async fn cmd_join(
|
||||
display_name: format!("#{display}"),
|
||||
mls_group_blob: new_member
|
||||
.group_ref()
|
||||
.map(|g| bincode::serialize(g))
|
||||
.map(bincode::serialize)
|
||||
.transpose()
|
||||
.context("serialize joined group")?,
|
||||
keystore_blob: None,
|
||||
@@ -1570,7 +1570,13 @@ async fn try_auto_join(
|
||||
}
|
||||
|
||||
// Take ownership of the pending member.
|
||||
let member = session.pending_member.take().unwrap();
|
||||
let member = match session.pending_member.take() {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
tracing::error!("pending_member disappeared after successful join");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let member_keys = member.member_identities();
|
||||
|
||||
// Figure out the peer (any member that isn't us).
|
||||
|
||||
Reference in New Issue
Block a user