fabro/Cargo.toml
Bryan Helmkamp fac0b10244
feat(server): preserve comments in setup_register TOML edits
`setup_register` in `web_auth.rs` used to round-trip the user's
settings file through `toml::Value` + `toml::to_string_pretty`, which
strips every comment, blank line, and explicit key ordering on the
way out. A user who'd hand-commented their `~/.fabro/settings.toml`
would see all of that lost on the next GitHub App registration.

Switches the edit path to `toml_edit::DocumentMut`, which preserves
prefix decoration (comments, blank lines) on every key. Adds
`toml_edit = "0.22"` as a workspace dependency (already pulled in
transitively via `toml 0.8`) and declares it in `fabro-server`.

Implementation notes:

- New `ensure_nested_table(doc, &["server", "web"])` walks a dotted
  path and `or_insert`s missing intermediate tables without touching
  existing ones.
- New `set_preserving_decor(table, key, value)` replaces an entry's
  value while copying the old key's `leaf_decor` forward. Without
  that workaround, `toml_edit::Table::insert` drops the prefix
  decoration of the replaced key -- which would strip a top-of-file
  comment attached to `_version = 1` or any other value we update.
- `_version` is only inserted when missing; it's always `1` today, so
  rewriting it every time is unnecessary and would trample its decor.
- `merge_settings_keys` now takes `&mut toml_edit::DocumentMut`
  instead of `&mut toml::Value`. The flow in `setup_register` parses
  the file on disk into a `DocumentMut`, applies the merge, and
  writes `doc.to_string()` back.

Adds a new test
`merge_settings_keys_preserves_comments_and_unrelated_keys` that
round-trips a fixture file containing:

- A top-of-file comment attached to `_version`
- A comment above `[server.storage]`
- A comment above a pre-existing `[server.integrations.slack]` table
- Unrelated keys in `[server.storage]`, `[server.integrations.slack]`,
  and `[run.model]`

and asserts that every comment and every unrelated key survives the
merge, that the new GitHub App keys are present, and that the final
output still parses as a valid v2 `SettingsFile` via
`fabro_config::ConfigLayer::parse`.

Also strengthens the existing
`merge_settings_keys_writes_v2_server_integrations_github` test with
a round-trip parse of the emitted TOML through `ConfigLayer::parse`
to ensure the output is real v2 config, not just a JSON-shaped blob.

3,765 workspace tests pass (+1 new). `cargo fmt --check --all` and
`cargo clippy --workspace -- -D warnings` are clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:18:10 -04:00

125 lines
3.7 KiB
TOML

[workspace]
members = ["lib/crates/*", "test/twin/openai", "test/twin/github"]
default-members = ["lib/crates/fabro-cli"]
resolver = "2"
[workspace.package]
edition = "2021"
version = "0.176.2"
license = "MIT"
[workspace.dependencies]
anyhow = "1"
axum = { version = "0.8" }
axum-extra = { version = "0.10", features = ["cookie-private"] }
cookie = { version = "0.18", features = ["percent-encode", "private", "signed", "key-expansion"] }
thiserror = "2"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["preserve_order"] }
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.13", default-features = false, features = ["json", "stream", "rustls", "query", "form", "multipart"] }
ulid = "1"
uuid = { version = "1", features = ["v4", "v7", "v8"] }
rand = "0.8"
dotenvy = "0.15"
futures = "0.3"
tokio-stream = "0.1"
async-trait = "0.1"
base64 = "0.22"
bytes = "1"
tokio-util = "0.7"
clap = { version = "4", features = ["derive", "env"] }
clap_complete = "4"
jsonschema = { version = "0.42", default-features = false }
chrono = { version = "0.4", features = ["clock"] }
bollard = "0.18"
tar = "0.4"
cli-table = { version = "0.5", default-features = false }
console = "0.15"
dialoguer = "0.12"
git2 = { version = "0.20", default-features = false }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
tracing-appender = "0.2"
rmcp = { version = "1.3", default-features = false }
walkdir = "2"
regex = "1"
semver = "1"
aho-corasick = "1"
dirs = "6"
mac_address = "1"
md5 = "0.7"
mime_guess = "2"
indicatif = "0.18"
termimad = "0.34"
toml = "0.8"
toml_edit = "0.22"
jsonwebtoken = { version = "10", features = ["aws_lc_rs"] }
hmac = "0.12"
sha2 = "0.10"
hex = "0.4"
insta = "1"
fabro-test = { path = "lib/crates/fabro-test" }
twin-openai = { path = "test/twin/openai" }
twin-github = { path = "test/twin/github" }
tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] }
futures-util = "0.3"
daytona-sdk = { git = "https://github.com/brynary/daytona-sdk-rust", rev = "06033ca", package = "daytona-sdk" }
daytona-api-client = { git = "https://github.com/brynary/daytona-sdk-rust", rev = "06033ca", package = "daytona-api-client" }
sentry = { version = "0.35", default-features = false, features = ["backtrace", "contexts", "ureq", "rustls"] }
fork = "0.2"
exec = "0.3"
slatedb = "0.11.2"
object_store = { version = "0.12.5", features = ["aws"] }
rust-embed = "8"
percent-encoding = "2"
[workspace.lints.rust]
unsafe_code = "deny"
unreachable_pub = "warn"
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -2 }
# Allowed pedantic lints
implicit_hasher = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
similar_names = "allow"
struct_excessive_bools = "allow"
too_many_arguments = "allow"
too_many_lines = "allow"
cast_precision_loss = "allow"
doc_markdown = "allow"
# Disallowed restriction lints
print_stdout = "warn"
print_stderr = "warn"
dbg_macro = "warn"
empty_drop = "warn"
empty_structs_with_brackets = "warn"
exit = "warn"
get_unwrap = "warn"
rc_buffer = "warn"
rc_mutex = "warn"
rest_pat_in_fully_bound_structs = "warn"
use_self = "warn"
# Project-specific lints
wildcard_imports = "warn"
absolute_paths = "warn"
[profile.release]
lto = "thin"
strip = true
[profile.dev.package."*"]
debug = false # Disable debug info for all dependencies
opt-level = 1 # Shrinks monomorphized generics, reducing test binary size
# regex is extremely slow in debug builds (~10s to compile gitleaks patterns)
[profile.dev.package.regex]
opt-level = 2
[profile.dev.package.regex-automata]
opt-level = 2
[profile.dev.package.regex-syntax]
opt-level = 2