Tighten CLI loopback target classification to use literal host checks,
update explicit local TCP auth coverage to match the remote-target
contract, and align server CSP assertions with the current external-script
SPA bundle. Also enable reqwest cookies in fabro-http so package-scoped
server tests compile without relying on workspace feature unification.
Consolidate three copies of `normalized_http_base_url` and
`build_public_http_client` into shared helpers in `user_config`,
add `Display for ServerTarget`, drop stale `#[allow(dead_code)]`
markers now that login/logout/JWT are wired, remove dead
`LOGIN_SUCCESSFUL` and `_error_description` field, and gate
test-only helpers behind `#[cfg(test)]`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the dark-only refactor the embedded SPA no longer contains an
inline theme-bootstrap script, so the two tests that asserted "embedded
index has >= 1 inline <script>" and "CSP header contains 'sha256-'" now
fail. The guards existed to catch accidental loss of the bootstrap
script; that loss was intentional. The rest of the CSP machinery (hash
extraction, policy assembly, external-script handling) is still
exercised by the remaining unit tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop dead http_client() accessor and its allow(dead_code).
- Scope map_api_error to module-private; all call sites are in-file.
- Rename test helper test_api_client to test_client to match what it returns.
- Run system df's two independent server GETs concurrently with try_join!.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Harden the CLI browser auth flow by moving auth-code issuance behind
an explicit same-origin confirmation step, and update the real-browser
test harness to submit the confirmation page.
Removes unused annotateRunningNodes from run-graph and inlines the
const gt = graphTheme / const theme = graphTheme shims left over from
the dark-mode-only refactor. Template strings reference graphTheme
directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends handleLifecycleToastResult to cover the cancel intent and
switches cancel's effect onto the shared helper. lastProcessed is now
keyed per intent so the three effects don't clobber each other's dedup
state, and cancel picks up the same replay guard that archive and
unarchive already had.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the remaining CLI server API calls in server_client::Client,
remove the api/connect_api_client escape hatches, and migrate
model/install/tests to the new facade.
Adds expect(disallowed_types) at the tests module for the intentional
sync BufReader usage in the zombie-process-group helper, and drops the
absolute-path call site by bringing pre_exec_setpgid into scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the light/dark toggle infrastructure in favor of a single dark
theme. Deletes the theme context, boot script, light-mode CSS overrides,
logotype-light asset, and the pierre-light diff theme. Collapses
graph-theme into a single constant. Adds scheme-only-dark on <html> so
native controls and the server-injected Graphviz @media query render
dark.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merges handleArchiveToastResult and handleUnarchiveToastResult into a
single helper. Replaces the content-hash dedup key with object identity
on fetcher.data and collapses the two "last key" fields into one
lastProcessed. Tests now import the exported helper directly instead of
casting through Record<string, unknown>.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Split raw PID existence from actual process liveness in fabro-proc and
switch the server shutdown paths to the running-process predicate. This
avoids waiting out stop timeouts for unreaped zombie children while
keeping process-group behavior covered by measured regression tests.
Add the missing refresh transport guard, actionable auth-store lock errors
for unsupported filesystems, explicit OAuth state expiry, and the remaining
CLI auth regression coverage around replay revocation, HTML headers, and
secret-safe logging.
The CLI façade is the primary type callers reach for, so it deserves
the bare `Client` name (per `reqwest::Client`, `hyper::Client`
convention). The raw generated HTTP binding is secondary and is more
accurately named `ApiClient`. "Store" in `ServerStoreClient` was
leftover from the SlateDB-ownership refactor and no longer describes
the type.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expose cancel, archive, and unarchive from the run detail view,
surface blocked-question context, and route run-detail and run-files
notifications through a single shared toast provider.
This also refreshes the embedded SPA bundle and marks the lifecycle
actions plan complete.
- Move the GitHub App webhook config update to fabro-github as
update_app_webhook_config, matching the crate's existing HttpClient +
Result<_, String> conventions. Server-side callers go through the new
symbol.
- Add Bind::tcp_port() on the enum itself and drop the free function.
- Collapse the six near-identical "webhook strategy configured but ...;
skipping webhook startup" warn branches into resolve_webhook_preconditions
returning a Ready/Skip enum, with one warn! at the call site.
- Replace the per-file test-helper wrappers (assert_status, checked_response,
response_json, response_bytes) with local macro_rules! macros so
file!()/line!() expand at the caller. Panic context now identifies the
failing assertion's source line instead of the wrapper's definition.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Distinguish the two GitHub webhook auth-failure warn messages (missing
signature header vs. HMAC mismatch) so logs can tell them apart.
- Route update_github_app_webhook through fabro_github::github_api_base_url()
so GITHUB_BASE_URL overrides the webhook config endpoint too.
- Drop a narrative shutdown comment that restated the next two lines.
- Replace concat!(file!(), ":", line!()) inside local test-helper wrappers;
those macros expand at the wrapper definition site, so every panic
reported the same phantom location. Pass the wrapper name instead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the real CLI auth integration harness into shared test support so
scenario/auth.rs keeps only the scenario cases and mock-browser helpers.
This makes the real-server auth setup reusable for future CLI integration
tests without duplicating the bootstrap code.
Add shared axum/reqwest response assertion helpers in fabro-test,
migrate the Rust HTTP test surface to use them, and document the
new rule in the testing strategy.
CI's TypeScript Build job upgraded bun to 1.3.13 (via setup-bun@v2.2.0
pulling the latest release), which produces a different content-hashed
entry CSS than the bundle committed under bun 1.3.10. The drift was
caught by the widened path filter in c8b807f30 and failed the
git diff --exit-code check on lib/crates/fabro-spa/assets.
Rebuilds with bun 1.3.13 so the embedded SPA matches the build CI
reproduces.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Retry CLI API calls once after a 401 access_token_expired response by
refreshing the stored OAuth session and rebuilding the generated API
client. Clear local auth when the refresh chain is expired or revoked,
and add end-to-end CLI scenarios covering login, authenticated use,
refresh, and logout.
- Capture webhook secret at route mount time via Arc<[u8]> router
state so the handler drops its per-request server_secret lookup
and the dead NOT_FOUND fallback.
- Extract WEBHOOK_ROUTE and WEBHOOK_SECRET_ENV constants; apply
across serve.rs, server.rs, and TailscaleFunnelManager so the
mounted route and the URLs pushed to GitHub cannot drift.
- Flatten the seven-level nested webhook startup match in serve.rs
into a single start_webhook_strategy helper with early returns,
short-circuiting when the secret is absent and replacing the
server.api.url .expect with a propagated error.
- Share compute_signature and a new read_repo_file helper across
tests; delete the duplicated webhook_signature, TestHmacSha256,
and read_doc/repo_root copies.
- Replace the nested for-loops in the new webhook auth tests with
five flat #[tokio::test] cases per CLAUDE.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Model the GitHub webhook request body as JSON so the generated TypeScript
client exposes a coherent request shape, and add explicit conformance
coverage for the secret-gated webhook route.
Add the server-side CLI OAuth endpoints and token persistence needed to
mint JWT access tokens and rotating refresh tokens from the existing
GitHub web auth flow.
Add CLI auth storage plus `fabro auth login`, `logout`, and `status`, and
prefer stored OAuth access tokens when building target clients.
Move GitHub webhook intake onto the main API router, add explicit
server_url and tailscale_funnel strategies, and validate strategy
requirements at config resolution. This also updates the API contract,
generated client, and operator docs to match the new webhook model.
Enable clippy's unwrap_used lint at warn level, document the long-term
policy carveouts for tests and LockResult, and localize the generated
OpenAPI client exemption so the remaining warning surface is real repo
code.
Enable clippy::allow_attributes_without_reason at the workspace level.
Add concise, callsite-specific reasons to existing allow attributes, including generated code paths.
Resolve rm/archive/unarchive selectors through the server-owned
runs/resolve endpoint instead of CLI-side summary matching, and move
active-run delete force semantics into DELETE /runs/{id}.
Two follow-ups the workspace lint now catches:
- fabro-server tests/it/api/install.rs: a newer install-router integration
test was missing the `.await` after `build_install_router(...)` -- the
fn became async when the devcontainer/install-mode resolver was
converted to tokio::fs in commit 19939c5f0.
- fabro-cli main.rs: add #[expect(clippy::disallowed_methods)] to the
#[cfg(test)] module whose write_test_settings helper uses sync
std::fs::write to stage CLI settings fixtures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>