Commit graph

3107 commits

Author SHA1 Message Date
Bryan Helmkamp
cf80fe567a
test(harness): scrub ambient creds from spawned fabro CLI
CLI integration tests spawned the real fabro binary while letting the
parent process's env pass through. The pr_view "no credentials" snapshot
failed in CI because the Nightly workflow's minted GITHUB_TOKEN was
inherited by the child and turned the expected "credentials required"
error into a real GitHub API call (404 / 401). On developer laptops the
same leak occurs whenever gh auth login is active.

Introduce apply_test_isolation(cmd, home) in fabro-test: env_clear() +
re-populate PATH, HOME, NO_COLOR, and the FABRO_* test overrides. Route
TestContext::command(), the internal server bootstrap, and the four
ad-hoc spawners in tests/it/cmd/{attach,render_graph,runner,server_start}
through the same helper so the isolation is systemic instead of
per-callsite. Tests that deliberately need a credential (OPENAI_API_KEY,
GITHUB_APP_PRIVATE_KEY, etc.) continue to set it explicitly on the
returned Command; those survive the clear.

Add a regression test that sets sentinel GITHUB_TOKEN and
ANTHROPIC_API_KEY in the parent, spawns /usr/bin/env through the helper,
and asserts the child sees neither credential while still seeing PATH
and the harness's FABRO_NO_UPGRADE_CHECK override.

Verified: the full workspace (4022 tests) passes with GITHUB_TOKEN and
ANTHROPIC_API_KEY set in the parent, which previously broke the
pr_view_reads_pull_request_from_store_without_pull_request_json
snapshot. cargo fmt and nightly clippy are clean.
2026-04-18 01:55:01 -04:00
Bryan Helmkamp
eb3c6d5ce3
fix(docs): update billing endpoint reference in navigation
The billing refactor (6ca2833e7) renamed /api/v1/runs/{id}/usage to
/api/v1/runs/{id}/billing in the OpenAPI spec but left the stale path
in docs.json, which broke Mintlify deploys with "Failed to fetch
OpenAPI file for anchor or tab".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:35:59 -04:00
Bryan Helmkamp
31fa23eb6a
chore(ci): default workflows to no permissions
Start every workflow with permissions: {} and grant the minimum
required per job, following Astral's defense-in-depth pattern so a
newly added job can't silently inherit repo read access.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:30:43 -04:00
Bryan Helmkamp
72a7f2f753
chore: ignore .claude/scheduled_tasks.lock 2026-04-18 01:15:17 -04:00
Bryan Helmkamp
70d6f929d2
chore: update Cargo.lock for vendored openssl dep
Records openssl 0.10 + openssl-src 300.6.0 in the lockfile for the
target-specific musl dep added in the previous commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:14:54 -04:00
Bryan Helmkamp
b8ce415551
fix(musl): vendor openssl for musl targets
daytona-sdk transitively pulls native-tls via reqwest (its own
reqwest v0.12, separate from our rustls-configured workspace
reqwest v0.13). native-tls requires libssl headers at build time,
which musl-gcc cannot satisfy from the host's glibc libssl-dev.

Add a target-specific openssl dep with the vendored feature so
openssl-sys compiles openssl from source for musl builds. glibc
builds are unaffected — they continue to link against the system
libssl that CI runners already have.

Verified end-to-end: aarch64-unknown-linux-musl binary built locally
runs on Alpine 3.20 (pure musl userspace).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:14:02 -04:00
Bryan Helmkamp
2f2f14562d
fix(api): convert OpenAPI spec to valid 3.1 syntax
The spec declared openapi 3.1.0 but used nullable: true (3.0 idiom)
in 78 places, which Mintlify's parser rejected, breaking doc deploys.

Convert to proper 3.1 patterns (type arrays and oneOf with type: null),
switch the server conformance test from openapiv3 (3.0-only) to a
YAML-level walk so it accepts 3.1 input, and regenerate the typescript
client — it now correctly emits `| null` on nullable fields.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:11:19 -04:00
Bryan Helmkamp
828d686a6f
feat(release): add x86_64 and aarch64 musl Linux targets
Extend the release matrix to two statically-linked musl variants so
Alpine and other musl-based Linux hosts can install without glibc.
Homebrew and the Docker image remain glibc-only.

- release.yml: add x86_64-unknown-linux-musl (ubuntu-24.04) and
  aarch64-unknown-linux-musl (ubuntu-24.04-arm) matrix rows with
  musl-tools, CC_*_musl, CARGO_TARGET_*_LINKER, and LIBZ_SYS_STATIC
- Cargo.toml: enable git2 vendored-libgit2 so libgit2 compiles from
  source for every target (needed because musl cannot link against
  Ubuntu's glibc-built libgit2-dev)
- install.sh: check `ldd --version` for "musl" and rewrite the target
  from -gnu to -musl so Alpine users get the right tarball
- upgrade.rs: add detect_linux_libc() / parse_ldd_libc() helper and
  route detect_target() Linux arms through it, with unit tests
  covering glibc, musl, empty, and unknown output
- tests/it: extend target regex in the dry-run snapshot filter

Ubuntu 24.04 is required for the musl runner: 22.04 ships musl 1.2.2
which SIGSEGVs statically-linked x86_64 test binaries at startup.
Confirmed against graphviz-sys CI before landing here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:00:51 -04:00
Bryan Helmkamp
5335f8bcb4
feat(deploy): add Railway deploy path, honor $PORT in container
Teach the Dockerfile CMD to bind 0.0.0.0:${PORT:-32276} so PaaS providers
(Railway, Fly, Render, Cloud Run) route traffic without manual port
configuration. Default 32276 preserves local docker / docker-compose
behavior.

Ship railway.toml pointing Railway at the Dockerfile with on_failure
restarts. Replace the "coming soon" stub in docs/administration/deploy-
railway.mdx with a real guide: deploy button, Volume-at-/storage setup,
env vars, dev-token retrieval, and CLI pointing. Surface the Railway
deploy button in README.md under a new "Self-host the Fabro server"
section that also links to the other deploy guides.

Locally verified: PORT env override binds the chosen port, default
falls back to 32276, and tini signal propagation still gives clean
docker stop. End-to-end Railway verification still needs a live click-
through before the template URL is finalized.
2026-04-18 00:44:15 -04:00
Bryan Helmkamp
87f50ceb16
docs(docker): document FABRO_DOMAIN in .env.example
Used by the prod compose stack to tell Caddy which hostname to serve
and auto-provision a cert for.
2026-04-18 00:34:19 -04:00
Bryan Helmkamp
a00abd8970
feat(docker): reorganize compose, add Caddy reverse proxy for prod
Move docker-compose.yaml to the repo root and add docker-compose.prod.yaml
that stands up a Caddy 2 sidecar on 80/443 proxying to the fabro service
on 32276 (the CLI's default port). Auto-HTTPS is handled by Caddy when
FABRO_DOMAIN is set; certs persist in named volumes.

Switch the container's internal listener from 80 to 32276, which lets us
drop libcap2-bin and the CAP_NET_BIND_SERVICE file capability.
2026-04-18 00:33:11 -04:00
Bryan Helmkamp
e89192cf1b
chore: gitignore docker-context/
Build output from bin/dev/docker-build.sh; regenerated on every run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 00:19:56 -04:00
Bryan Helmkamp
7c80d9be9c
fix(docker): build fabro-cli inside rust:1-bookworm for local image
The host cargo build on macOS produced a Mach-O binary that the
Linux runtime image refused with "Exec format error". Run the
compile in rust:1-bookworm so the output matches the target
platform, and cache the registry plus target dir in named volumes
for incremental rebuilds. Also gitignore docker-context/ since it
is regenerated on every build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 00:19:46 -04:00
Bryan Helmkamp
db953c838b
fix(test): resolve clippy and fmt findings in upgrade test helper
Clippy flagged hard_link_or_copy's match as single_match_else;
rewrite as an early-return if. rustfmt reformatted the long
chained path join in brew_command and the multi-arg
hard_link_or_copy call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:39:51 -04:00
Bryan Helmkamp
d52e6829c2
feat(docker): publish multi-arch server image to GHCR
Replace the docker/Dockerfile-based api+web compose setup with a
single root Dockerfile that runs the fabro server with the embedded
web UI on port 80, persists state under /storage, and drops to a
non-root fabro user with CAP_NET_BIND_SERVICE.

The release workflow stages the prebuilt Linux binaries from the
compile job into a buildx context and publishes multi-arch images
to ghcr.io/fabro-sh/fabro as :<version> (always), :latest (stable
tags only), and :nightly (nightly tags only).

Also address zizmor findings in nightly.yml (pinned
create-github-app-token, persist-credentials: false with explicit
remote URL setup) and release.yml (no-cache on tag-triggered
setup-bun to close the cache-poisoning path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:39:10 -04:00
Bryan Helmkamp
e891cb3961
test(cli): cover Homebrew upgrade behavior end to end
Some checks are pending
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
Add process-level upgrade tests that invoke the real fabro binary from a
fake Homebrew Cellar path so current_exe() detection is exercised end to
end. Update the CLI reference and changelog to document the Homebrew-managed
upgrade path and the flags that remain self-managed-only.
2026-04-17 18:28:54 -04:00
Bryan Helmkamp
1530ba4e93
docs(readme): add CI build badge
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:53:15 -04:00
Bryan Helmkamp
d535edfda4
feat(cli): brew-aware upgrade check and gate
Detect Homebrew-managed installs from the canonicalized executable path
(Cellar/fabro[-nightly]/...) and branch both the background nag and
`fabro upgrade` accordingly.

- Background check fetches the tap's versions.json (raw.githubusercontent)
  for the matching channel instead of GitHub's latest release, so the nag
  tracks what `brew update` can satisfy.
- Cache payload gains an install_source tag; entries from a different
  source (or legacy entries without the field) are ignored, so users who
  switch between fabro/fabro-nightly/tarball don't see stale versions.
- `fabro upgrade` on a brew install refuses to overwrite the
  Homebrew-managed binary and prints `brew upgrade fabro[-nightly]`.
  --dry-run prints the command and exits 0; --version/--prerelease/--force
  are rejected with a clear Homebrew-managed error.
- Manifest/exe-resolve failures on brew installs skip the notice rather
  than falling back to GitHub latest (which would reintroduce the
  tap-lag false positives this change is meant to remove).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:46:55 -04:00
Bryan Helmkamp
c8efd5d2d1
Bump version to 0.205.0-nightly.1 2026-04-17 15:39:59 -04:00
Bryan Helmkamp
c1443ad3f3
fix(test): keep session locks outside session roots
Move the shared session lock file out of the deletable session root so
cleanup cannot unlink the lock another test process is relying on.
This hardens the nextest shared-server harness against dev-token startup
races and adds a regression test for the lock path.
2026-04-17 15:31:05 -04:00
Bryan Helmkamp
81d648a0b0
ci(release): run tests before build to avoid recompile
Nextest with --workspace pulls in dev-dependencies that enable extra
features, forcing Cargo to recompile the whole graph. Running tests
first warms the cache; the final release binary build for fabro-cli
reuses those artifacts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:32:21 -04:00
Bryan Helmkamp
72399ed1d3
Bump version to 0.205.0-nightly.0 2026-04-17 11:52:58 -04:00
Bryan Helmkamp
d525071d14
feat(ci): add automated nightly release workflow
New .github/workflows/nightly.yml that fires daily at 09:00 UTC (plus
on-demand via workflow_dispatch) and runs bin/dev/release.sh nightly to
tag a fresh pre-release. Tag shape: v0.X.Y-nightly.N. Skips cleanly when
HEAD is already the commit referenced by the newest v*-nightly.* tag.

The job runs in the `nightly` environment, which scopes the
`FABRO_RELEASES_APP_PRIVATE_KEY` secret and `FABRO_RELEASES_APP_ID`
variable to just this workflow and restricts deployments to `main`.
`actions/create-github-app-token` mints an installation token on the
`Fabro Releases` GitHub App; that token authenticates both the checkout
(so the bump commit + tag can push back to main) and any downstream git
operations release.sh performs. Commits are attributed to
`fabro-releases[bot]`.

Pre-tag testing stays in release.sh's verify_release_tests, so a broken
main fails the nightly workflow before a dud version bump commit lands.
The tag push then triggers the existing release.yml, which publishes
the GH prerelease and updates Formula/fabro-nightly.rb in the tap.

Prerequisites (all done manually):
- GitHub App `Fabro Releases` installed on fabro + homebrew-tap
- `nightly` environment with the app credentials

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 11:48:34 -04:00
Bryan Helmkamp
7bc3fe0dbc
fix: wrap propagated io errors with anyhow context across prod code
A recent CI flake surfaced as bare "error: No such file or directory
(os error 2)" with no chain, because the failing operation lived behind
a raw `?` on a `std::fs::` / `File::create` / `Command::spawn` call. The
error had no verb, no path, no hint at which step in server startup
broke. Retry loops were explicitly rejected -- the goal is to diagnose
the next occurrence, not mask it.

Wraps 50+ such sites across fabro-cli, fabro-server, fabro-workflow,
fabro-util, fabro-vault, fabro-telemetry, fabro-interview, fabro-llm,
and fabro-devcontainer with `.with_context(|| format!("<verb> {path}"))`
so anyhow's error chain carries both the operation and the path when
an io error escapes.

Where the enclosing function returns `io::Result` (fabro-util run_log,
fabro-interview recording, fabro-llm attachment loader), the error is
re-wrapped via `io::Error::new` to keep the signature stable. Where a
crate uses its own thiserror enum, either a new `io_context` helper
was added (fabro-vault) or the path was folded into the existing
`Error::Io(String)` message (fabro-workflow).

No retry loops. No behavior changes. Skipped sites documented:
`.ok()`-swallowed, `match ErrorKind::NotFound`, `let _ = ...`, typed
error variants that already carry the path, and test modules.

Verified: cargo build --workspace, cargo +nightly clippy --workspace
--all-targets -- -D warnings, cargo nextest run --workspace (3991/3991
pass).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 11:44:38 -04:00
Bryan Helmkamp
2d8d72717d
refactor(release): simplify pre-release channel to nightly only
Drops `alpha` / `beta` / `rc` as accepted pre-release labels in
bin/dev/release.sh. `nightly` is now the only pre-release descriptor,
in preparation for automated nightly tags.

Renames the Homebrew tap formula from `fabro-beta` to `fabro-nightly`:

- installer/fabro-beta.rb.template -> installer/fabro-nightly.rb.template
  (class renamed FabroBeta -> FabroNightly, desc updated).
- `update-homebrew-beta` job in release.yml is now
  `update-homebrew-nightly` with matching file paths and commit message.

Breaking for existing `brew install fabro-sh/tap/fabro-beta` users: the
old formula file stays in the tap for now (removed in a follow-up once
fabro-nightly is populated) and stops receiving updates. Users should
switch to `brew install fabro-sh/tap/fabro-nightly` once the new
formula is published by the next pre-release tag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 11:39:19 -04:00
Bryan Helmkamp
18a551f076
feat(release): smoke-test release mode before tagging
Adds a verify_release_tests step to bin/dev/release.sh that runs the
same nextest invocation the CI release workflow uses -- workspace,
--release, --profile ci -- with SEGMENT_WRITE_KEY baked in so
telemetry-active code paths are actually exercised. Runs before the
version bump/tag, so regressions that only show up under --release
plus a compiled-in write key (e.g. telemetry recreating ~/.fabro,
sender tests that assume no key) fail locally in ~5 min instead of
~60 min on a tagged release run.

`--skip-tests` for when you've already run it yourself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 10:14:10 -04:00
Bryan Helmkamp
3d2c586eda
Bump version to 0.205.0-beta.2 2026-04-17 10:12:06 -04:00
Bryan Helmkamp
a1776b7beb
fix(test): skip write-key sender assertions when CI bakes the key in
Two fabro-telemetry sender tests assert that upload/upload_blocking
return an error with "SEGMENT_WRITE_KEY not set" -- a claim that only
holds when SEGMENT_WRITE_KEY is absent at compile time. The release
workflow sets the secret at build time, so these tests now fail under
`cargo nextest run --workspace` in release CI (newly exercised after
switching the release workflow from `cargo test` to nextest).

Guard each assertion with an early return when SEGMENT_WRITE_KEY is
compiled in so the test passes in release CI while still verifying the
no-key path for every other build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 10:05:39 -04:00
Bryan Helmkamp
8ce451869f
Bump version to 0.205.0-beta.1 2026-04-17 09:21:20 -04:00
Bryan Helmkamp
7bf0c6678e
feat(cli): add fabro docs to landing Set up section
Surfaces the docs website shortcut alongside the other onboarding
commands so new users can find the web docs without hunting through
`fabro help`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 09:03:40 -04:00
Bryan Helmkamp
afcbb0628a
refactor(cli): tighten landing footer and drop sandbox cp/preview
- Replace the three-line "help along the way" trio with a Discord
  callout in the style of qlty's landing: one line pointing at per-
  command --help, one inviting users to the Fabro Discord.
- New final line uses qlty's dim/cyan split: "For a full list of
  commands, run `fabro help`."
- Drop `sandbox cp` and `sandbox preview` from the curated list;
  `sandbox ssh` stays. Both are still reachable via `fabro help`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 09:03:08 -04:00
Bryan Helmkamp
ae2efaabf9
refactor(cli): regroup landing output around lifecycle stages
Moves `server start` and `secret set` into Set up so the first section
covers everything a user does once before they have a working install.
Drops `secret list` from the landing — `fabro --help` still surfaces it.
Merges the run-inspection commands (`logs`, `sandbox ssh`, `sandbox
preview`, `sandbox cp`) under a single "Inspect runs" heading, since
they all answer "what happened in this run?".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 09:01:08 -04:00
Bryan Helmkamp
a4159f7bb6
feat(cli): show curated landing output for bare fabro
Running `fabro` with no subcommand now prints a short, colorized guide
highlighting the most important commands (install, doctor, repo init,
validate, preflight, run, logs, server start, secret set/list, sandbox
ssh/preview/cp) instead of clap's full --help dump.

`fabro --help` and `fabro help` still render clap's comprehensive
reference unchanged. The CLI makes the root subcommand optional and
intercepts the None case in main_inner before telemetry or logging
init; the empty command name also suppresses the "CLI Executed"
tracking event for this pseudo-command.

Includes an inline-snapshot IT test covering the full landing body and
updates four pre-existing usage-line snapshots (<COMMAND> → [COMMAND])
that reflect the now-optional subcommand.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:59:03 -04:00
Bryan Helmkamp
1e147c0d88
fix(cli): prevent telemetry from recreating ~/.fabro after uninstall
In release builds with SEGMENT_WRITE_KEY baked in (i.e. CI), the
post-command telemetry flush calls spawn_fabro_subcommand, which in turn
does create_dir_all(~/.fabro/tmp) and writes a JSONL event file. That
silently undoes the directory removal that `fabro uninstall --yes` just
performed — leaving a stray ~/.fabro/tmp/ behind and breaking the
uninstall integration tests on CI release runs.

Fixes:
- run_uninstall calls fabro_telemetry::shutdown() before removal so the
  buffered "CLI Executed" track in main() can't be queued or flushed,
  and the background thread can't spawn the sender subprocess.
- TestContext::command() exports FABRO_TELEMETRY=off so test subprocesses
  never initialise telemetry at all, as a belt-and-suspenders guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:40:04 -04:00
Bryan Helmkamp
dd49ec51fd
ci(release): run tests with nextest to match rust.yml
Aligns the release workflow's per-target test step with the regular CI
test workflow: uses cargo-nextest with --status-level slow and the ci
profile so release runs get the same timeout headroom and quieter output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:15:17 -04:00
Bryan Helmkamp
ae35cb114c
ci: publish fabro-beta Homebrew formula on pre-release tags
Adds a sibling Homebrew formula so users can opt into pre-releases with
`brew install fabro-sh/tap/fabro-beta`. Pre-release tags (v*-*) update
Formula/fabro-beta.rb in the tap; stable tags still only touch
Formula/fabro.rb. The two formulae declare conflicts_with each other
since they both install the fabro binary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:12:53 -04:00
Bryan Helmkamp
297a591fd2
ci: run nextest with --profile ci for looser timeouts on CI runners
Adds a ci nextest profile (30s slow-timeout, terminate-after 4, 2s leak-
timeout) and wires rust.yml's test and test-macos jobs to use it. Local
invocations keep using the tight default profile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:09:54 -04:00
Bryan Helmkamp
ad8db228db
ci: pass --status-level slow to nextest to cut log noise
Default nextest emits a PASS line per test, which scrolls thousands of
lines in CI. `slow` shows only slow/failing tests plus the summary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:04:40 -04:00
Bryan Helmkamp
bdc3e50a6c
ci: bump oven-sh/setup-bun to v2.2.0 for Node 24 runtime
The previous pin (v2 @ 3d267786...) runs on Node 20, which GitHub Actions
is deprecating on Sept 16, 2026. v2.2.0 switches to Node 24.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 07:57:53 -04:00
Bryan Helmkamp
5946047202
deps: bump rand 0.8 → 0.9 (#163)
## Summary
- Bumps `rand` from 0.8 to 0.9 to resolve Dependabot alert #16 (low
severity: "Rand is unsound with a custom logger using rand::rng()",
fixed in 0.9.3).
- Migrates call sites to the renamed 0.9 APIs.

## API changes applied
- `rand::thread_rng()` → `rand::rng()`
- `Rng::gen_range(..)` → `Rng::random_range(..)`
- `Rng::gen::<T>()` → `Rng::random::<T>()`
- `OsRng.fill_bytes(..)` → `OsRng.try_fill_bytes(..).expect("OS RNG")` —
in 0.9 `OsRng` implements `TryRngCore` instead of `RngCore` directly.

## Test plan
- [x] `cargo build --workspace`
- [x] `cargo nextest run -p fabro-util -p fabro-server -p fabro-workflow
-p fabro-oauth` (1270 passed)
- [x] `cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D
warnings`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 07:57:10 -04:00
Bryan Helmkamp
31b4bd801e
Bump version to 0.205.0-beta.0 2026-04-17 07:55:47 -04:00
Bryan Helmkamp
4c835c95b0
fix(test): make release-mode unit tests pass workspace-wide
- server_start::help: correct --watch-web description indent from 14 to 10 spaces
  in the stripping regex so the filter matches in debug builds where the flag
  is present in --help output.
- fabro-telemetry: split telemetry_level default test into debug/release
  variants. The function's default depends on cfg!(debug_assertions), so the
  prior single test panicked under cargo test --release.

Verified: cargo nextest run --workspace (debug) → 3990 passed; cargo test
--workspace --release → all 69 test binaries pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 07:48:08 -04:00
Bryan Helmkamp
7fda2ee25b
fix(test): update snapshots for version and --prerelease flag
- Update VERSION filter regex to handle prerelease suffixes (e.g., 0.204.0-beta.1)
- Add VERSION filter to JSON snapshots in fabro_json_snapshot macro
- Fix attach test to use [VERSION] placeholder instead of hardcoded version
- Update upgrade help snapshot to include new --prerelease flag
- Change fake version in upgrade test from v0.176.3 to v999.0.0 to avoid collision
- Strip --watch-web from server start help (debug-only flag, varies by build)
- Gate test_panic module with #[cfg(debug_assertions)] (debug-only command)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 07:31:40 -04:00
Bryan Helmkamp
0b16993b30
Bump version to 0.204.0-beta.1
Some checks are pending
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
Rust / Format (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
2026-04-16 20:20:37 -04:00
Bryan Helmkamp
0b77a3efa2
feat(cli): add --prerelease to fabro upgrade
Widens the candidate set to include prereleases, picks max semver across
stable + prereleases. Falls back to /releases/latest if no parseable
non-draft tag is returned. Conflicts with --version. Background
auto-upgrade notice remains stable-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:20:14 -04:00
Bryan Helmkamp
60cbdc97c2
ci: bump GitHub Actions to Node 24 runtimes
actions/checkout v4 → v6.0.2, actions/upload-artifact v4 → v7.0.1,
actions/download-artifact v4 → v8.0.1. Silences the Node 20 deprecation
warnings ahead of the June 2026 forced cutover. All pins are full
commit SHAs with version comments.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:11:25 -04:00
Bryan Helmkamp
fa0c1616f2
Bump version to 0.204.0-beta.0 2026-04-16 20:02:45 -04:00
Bryan Helmkamp
4c1d2e44f7
cleanup 2026-04-16 20:02:24 -04:00
Bryan Helmkamp
3ed65d3728
fix(test): consume stdin in render_graph RENDER_ERROR fake subprocess
The fake /bin/sh script in the render_error protocol test printed and
exited without reading stdin, which raced the parent's write_all on
Linux — EPIPE would surface as ChildCrashed (500) instead of the
RenderFailed path (400) the test asserts. macOS pipe buffering masked
the race. Adding `cat >/dev/null` mirrors the sibling
protocol_violation test and makes the child consume the DOT input
before printing the RENDER_ERROR line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 19:51:59 -04:00
Bryan Helmkamp
4e7026413a
deps: bump aws-lc-rs 1.16.1 → 1.16.3 (pulls aws-lc-sys 0.40.0)
Resolves Dependabot alerts #4, #5 (aws-lc-sys CRL scope check and X.509
name-constraint bypass; both fixed in 0.39.0+).

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