Commit graph

194 commits

Author SHA1 Message Date
Bryan Helmkamp
cdd46b4fa8
Make git metadata sandbox-native 2026-04-27 21:43:15 -07:00
Bryan Helmkamp
3a8e1a0517
refactor(sandbox): make Docker clone-based by default
Switch Docker sandboxes from host bind mounts to per-run clone-based containers with structured run metadata, reconnect validation, archive-based file transfer, and Docker resource defaults.

Extend run config/API surfaces so Docker image and clone settings flow through manifests, server preflight, workflow startup, and generated clients.

Update docs and tests for the new default Docker provider path.
2026-04-26 18:21:02 -04:00
Bryan Helmkamp
583fa1e9d1
refactor(config): share log destination resolution
Move FABRO_LOG_DESTINATION parsing into fabro-config so CLI and server worker startup use the same validation behavior. Worker startup now exports one canonical resolved destination instead of relying on a generic env allowlist path.
2026-04-26 17:47:22 -04:00
Bryan Helmkamp
d07596ca80
feat(server): support stdout log destination
Add configurable server log destinations with an environment override so containers can stream foreground server logs to stdout while local installs keep file logging by default. Validate configured log filters at load time and reject stdout logging for daemon mode.
2026-04-26 14:52:15 -04:00
Bryan Helmkamp
11be286fa1
refactor(dev): simplify generated docs tooling
Share the real CLI parser with reference generation, reuse option metadata flattening, and centralize dev command execution helpers.
2026-04-24 18:41:00 -04:00
Bryan Helmkamp
12ea5341bb
feat(dev): generate options reference
Add a settings reference generator backed by OptionsMetadata on the sparse config layer structs. The generated user-configuration page is fenced and checked in CI alongside the CLI reference.
2026-04-24 16:49:16 -04:00
Bryan Helmkamp
80de5ca616 refactor(static): centralize env var names
Add fabro-static::EnvVars as the shared registry for fixed environment variable names and migrate env reads, clap env bindings, and subprocess/test allowlists to use it.

Add clippy bans for raw std::env lookup APIs so future dynamic env facades must be documented explicitly.
2026-04-24 12:29:51 -04:00
Bryan Helmkamp
906868c30c
drop unused test-support feature from fabro-config
SettingsLayer::{test_default, ensure_test_auth_methods} are `pub(crate)`
and only called from fabro-config's own in-crate tests, but their impl
block was gated on `cfg(any(test, feature = "test-support"))`. No
external crate enabled the `test-support` feature, so under
`--all-features` the methods compiled in without reachable callers and
clippy flagged them as dead code. Narrow the gate to `cfg(test)` and
drop the vestigial feature entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:29:29 -04:00
Bryan Helmkamp
64dbdf2500
fix(ci): resolve workspace test and lint regressions 2026-04-23 20:49:30 -04:00
Bryan Helmkamp
d380c8f496
drop vestigial fabro-macros dep and DurationLayer aliases
After Unit 3.1 of the config boundary refactor, fabro-types no longer has
any #[derive(Combine)] sites — the fabro-macros dep is unused. Likewise
`Duration as DurationLayer` was an artifact from when layer and vocabulary
types lived side-by-side; the resolved Duration type has no Layer form now,
so the alias was misleading.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 20:06:19 -04:00
Bryan Helmkamp
f16becd2f7
clean up settings warning fallout 2026-04-23 19:53:40 -04:00
Bryan Helmkamp
6fc7251471
close config boundary audit and settings snapshot naming 2026-04-23 19:30:30 -04:00
Bryan Helmkamp
941c6e83f9
route fabro-config parsing through settings fromstr 2026-04-23 19:20:02 -04:00
Bryan Helmkamp
1bd7b7688f
lock down sparse settings exports in fabro-types 2026-04-23 19:10:45 -04:00
Bryan Helmkamp
73a47c1256
move fabro-config hidden settings tests in-crate 2026-04-23 19:04:57 -04:00
Bryan Helmkamp
9a898b12cd
move sparse settings layers into fabro-config 2026-04-23 18:10:12 -04:00
Bryan Helmkamp
b9fe542c5b
move serve runtime resolution behind config helper 2026-04-23 17:45:09 -04:00
Bryan Helmkamp
12ca64f5bf
route manifest assembly through builder source setters 2026-04-23 17:40:24 -04:00
Bryan Helmkamp
7d2600126a
drop raw settings merges from cli loaders 2026-04-23 17:37:22 -04:00
Bryan Helmkamp
2c55f10e62
store manifest defaults as run layers 2026-04-23 17:33:31 -04:00
Bryan Helmkamp
a5978b0b3c
split cli manifest overrides into run and cli layers 2026-04-23 17:28:45 -04:00
Bryan Helmkamp
2ec9e8bcdc
route project config discovery through file-based builders 2026-04-23 17:22:47 -04:00
Bryan Helmkamp
134d8c32d5
add dense run settings builder 2026-04-23 16:37:00 -04:00
Bryan Helmkamp
3cc094316b
add dense run goal and working dir helpers 2026-04-23 16:20:11 -04:00
Bryan Helmkamp
4c8f7fe164
use workflow builders in root and run fixtures 2026-04-23 15:20:42 -04:00
Bryan Helmkamp
662825ac65
use toml builders in config fixtures 2026-04-23 15:15:05 -04:00
Bryan Helmkamp
2a60b6c3dc
add workflow settings builder toml entrypoint 2026-04-23 15:12:48 -04:00
Bryan Helmkamp
68b9fc13a5
inline builtin defaults layer 2026-04-23 15:09:05 -04:00
Bryan Helmkamp
dc6a92e696
drop public settings load wrappers 2026-04-23 14:59:48 -04:00
Bryan Helmkamp
2ee9850abb
drop server resolve wrapper 2026-04-23 14:57:10 -04:00
Bryan Helmkamp
916b97c0ad
drop cli and features resolve wrappers 2026-04-23 14:43:07 -04:00
Bryan Helmkamp
43d32464a2
drop project run workflow resolve wrappers 2026-04-23 14:40:09 -04:00
Bryan Helmkamp
e20d8d9435
route project namespace resolution through workflow builders 2026-04-23 14:38:54 -04:00
Bryan Helmkamp
30986207cb
trim config wrapper and storage override helpers 2026-04-23 12:01:49 -04:00
Bryan Helmkamp
9220af6e80
migrate remaining run settings consumers to dense snapshots 2026-04-23 11:55:12 -04:00
Bryan Helmkamp
b2bcf0d5a8
refactor settings builders and dense run snapshots 2026-04-23 11:35:21 -04:00
Bryan Helmkamp
a770eb8e12
Merge remote-tracking branch 'origin/main' 2026-04-23 08:52:44 -04:00
Bryan Helmkamp
fc4e0381ac
simplify: dedupe splice helpers, trim dead map wrapper surface
- Collapse splice_model_fallbacks and splice_events into a single
  generic splice_combine guarded by a new SpliceMarker trait; the
  Combine impl for Vec<T: SpliceMarker> replaces the two per-enum impls.
- Drop inherent iter/iter_mut (redundant with Deref/DerefMut),
  AsRef/AsMut, and IntoIterator for &_/&mut _ on ReplaceMap/StickyMap/
  MergeMap — they had zero external callers. DerefMut and IntoIterator
  for Self stay because labels.extend(...) relies on both.
- Drop unused _api parameter on resolve_web.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:52:41 -04:00
Bryan Helmkamp
da9453cbd1
refactor(config): move settings combine into types 2026-04-23 08:42:19 -04:00
Bryan Helmkamp
37cd8ff45f
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/src/lib.rs
#	lib/crates/fabro-server/src/serve.rs
#	lib/crates/fabro-server/src/server.rs
2026-04-23 08:34:44 -04:00
Bryan Helmkamp
f5758d99d0
refactor(config): collapse settings resolver 2026-04-23 08:00:56 -04:00
Bryan Helmkamp
e6e091fe8e
refactor(server): lock down server secrets 2026-04-23 07:15:27 -04:00
Bryan Helmkamp
ec18c1864b
simplify: rename Resolver::from_file → from_layer and trim docs
The fresh `Resolver` API takes a `&SettingsLayer`, not a file path, so
its constructor should match the existing `ServerSettings::from_layer`
and `UserSettings::from_layer` naming. The `*_from_file` suffix on the
older free helpers is a legacy choice (their input was historically
loaded from a file); leave those names alone since they're a stable
public API used across many call sites.

Also drop two doc-comment references to specific call sites (the simplify
guidelines treat those as rot bait — call sites move, the doc lies).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:21:43 -04:00
Bryan Helmkamp
52d24531df
simplify: introduce Resolver to apply settings defaults once
Previously, each per-namespace `resolve_*_from_file` helper, together with
`resolve_storage_root` and the `*Settings::from_layer` constructors, called
`apply_builtin_defaults(file.clone())` independently. That meant every
batch resolve cloned the entire `SettingsLayer` (including hooks, MCPs,
sandbox config, etc.) and merged the static defaults layer once per call.
The worst offender, `fabro_workflow::operations::create::resolve_settings_tree`,
ran that pipeline four times back-to-back per `create_run` request.

Add `fabro_config::Resolver`, which applies builtin defaults exactly once
on construction and exposes per-namespace methods (`server`, `cli`,
`features`, `project`, `run`, `workflow`, `storage_root`) plus low-level
`*_into(&mut errors)` variants for callers that want to merge errors
across multiple namespaces. The standalone `resolve_*_from_file` helpers
and `resolve_storage_root` remain on the public API, but each is now a
one-liner that delegates to `Resolver::from_file(...)` so single-namespace
callers see no behavior change.

Migrate the multi-namespace consumers:
- `ServerSettings::from_layer` and `UserSettings::from_layer` build one
  `Resolver` and call the `*_into` pair, preserving the original
  "surface all errors from both namespaces" semantics.
- `resolve_settings_tree` builds one `Resolver` and pulls all four
  namespaces from it, dropping three redundant defaulting+clone passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:18:20 -04:00
Bryan Helmkamp
2dfefe36e9
simplify: dedupe render_resolve_errors across crates
Three byte-identical copies of `render_resolve_errors` had drifted into
`fabro-server/src/run_manifest.rs`, `fabro-workflow/src/operations/start.rs`,
and `fabro-workflow/src/operations/create.rs`. Each one folded a
`&[ResolveError]` into a semicolon-separated string for surfacing through
`anyhow!` / `Error::Precondition` envelopes.

Promote the helper to `fabro_config::render_resolve_errors` (it lives next
to `ResolveError`, the type it acts on) and rewrite the four call sites
in workflow ops plus the one in run_manifest to call the shared version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:54:05 -04:00
Bryan Helmkamp
a6e755c200
simplify: dedupe storage-root override + cache demo settings
- Promote `apply_storage_dir_override` to `fabro_config::user` so the
  serve startup path stops carrying its own copy of the storage-root
  mutation that already lived in `fabro-cli/user_config.rs`.
- Inline the `load_settings` and `router_web_enabled` one-liner wrappers
  in `fabro-server/src/serve.rs` and drop the dead
  `let _ = CliLayer::default()` marker.
- Cache the demo `server_settings()` JSON in a `OnceLock` so the demo
  mode stops re-parsing TOML, re-resolving, and re-serializing the same
  static fixture on every `GET /api/v1/settings` request.
- Standardize the four `state.settings.read().unwrap()` callsites in
  `fabro-server/src/server.rs` on `.expect("settings lock poisoned")`
  to match the existing convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:47:00 -04:00
Bryan Helmkamp
28a9f036d8
fix: server-side settings authority + unit tests that never hit live S3
Two related correctness bugs surfaced by the failing test suite:

1. Server-owned settings didn't flow into run settings, and the few
   server-only fields that did leak in made run snapshots bulky and let
   callers re-resolve server state from the run layer.

   - effective_settings::materialize_settings_layer now treats the
     server's run/features stanzas as base defaults (client layers
     still win where set), and enforce_server_authority keeps the
     original cherry-pick of storage/scheduler/artifacts/web/api but
     no longer lets the rest of the server namespace propagate. auth,
     listen, ip_allowlist, slatedb, logging, and integrations stay on
     the server, where AppState::server_settings() already has them.

   - run_preflight, the scheduler start-path, and operations::start
     now read GitHub integrations from state.server_settings() (or
     StartServices::github_permissions, which the server populates)
     instead of re-resolving the server namespace from the run's
     settings layer.

   - create_app_state{_with_options,_with_env_lookup,_with_options_and_registry_factory}
     and create_app_state_with_store_and_env_lookup all route through
     ensure_test_auth_methods so the strict resolver accepts
     SettingsLayer::default() in tests.

   - Fixed the start_run_persists_full_settings_snapshot assertion
     that expected server.integrations.github.app_id in the run's
     persisted settings — the new design deliberately omits it.

2. Unit and integration tests were hitting live AWS S3.

   - Added a NoProxyReqwestConnector (behind a dedicated reqwest 0.12
     dep aliased as object_store_reqwest) and wired it through
     AmazonS3Builder::with_http_connector. macOS SystemConfiguration
     proxy discovery in the default reqwest client was blowing past
     nextest's 20s kill timeout on serve.rs's S3 builder unit tests;
     the no-proxy connector brings them under 15ms.

   - InstallAppState::for_test_with_paths now sets
     FABRO_TEST_IN_MEMORY_STORE=1 so /install/finish's artifact-metadata
     sentinel write short-circuits to the in-memory object store and
     never contacts AWS. The install integration tests verify
     persistence/redaction, not S3 reachability.

`cargo nextest run --workspace`: 4495/4495 passing.
`cargo +nightly-2026-04-14 fmt --check --all`: clean.
`cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings`: clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:15:56 -04:00
Bryan Helmkamp
2ddbe49cb8
lint: fix clippy absolute_paths & disallowed_methods after merge
- Import serde:🇩🇪:Error trait so the `custom` fn pointer uses `D::Error`
  instead of the absolute `serde:🇩🇪:Error::custom` path.
- Import `fabro_api::types::ServerSettings` / `fabro_config::UserSettings`
  directly rather than through absolute paths.
- Gate sync `std::fs::write` fixture setup in new config resolver tests
  with a file-level `#![expect(clippy::disallowed_methods, …)]`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:48:20 -04:00
Bryan Helmkamp
fa62da5d9d
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-api/build.rs
#	lib/crates/fabro-server/src/install.rs
#	lib/crates/fabro-server/src/serve.rs
#	lib/packages/fabro-api-client/src/.openapi-generator/FILES
#	lib/packages/fabro-api-client/src/models/index.ts
2026-04-22 21:18:50 -04:00
Bryan Helmkamp
93b6577cd3
simplify: drop duplicate settings plumbing from cli/server refactor
- Remove CommandContext::cli_settings and cascade through 11 functions
  whose only use of `cli: &CliNamespace` was constructing it; dispatchers
  now forward only cli_layer.
- Drop `ServerSettings as CurrentServerSettings` /
  `ServerNamespace as ResolvedServerSettings` rename aliases; use the
  canonical type names in fabro-server.
- Inline `local_server::server_settings` and `user_config::{resolve_user_settings,
  resolve_cli_settings}` wrappers; callers use `ServerSettings::from_layer`
  / `UserSettings::from_layer` directly (anyhow converts via `?`).
- Trim narrative module doc in fabro-config/src/lib.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:02:37 -04:00