mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
lint(clippy): disallow blocking std::fs on Tokio paths
Phase 2/3 of the std::fs lint initiative (Phase 1 refactors landed in
commit 9d1c0d98c).
clippy.toml additions (appended to disallowed-methods):
std::fs::read, read_to_string, write, read_dir, copy, canonicalize
std::fs::File::open, File::create, File::create_new
std::fs::OpenOptions::open
File::options was deliberately excluded — it returns an OpenOptions
builder with no syscall. OpenOptions::open is where the block happens.
Non-blocking std::fs items (metadata, exists, create_dir_all, remove_*,
rename, and all std::fs types) remain legal.
Annotation policy (per updated plan):
- Mixed async/sync production source: function- or statement-scoped
#[expect(...)] so future accidental Tokio-path regressions in the
same file still fire.
- Fully-sync production source, test modules, integration tests,
build.rs: file-level #![expect(...)].
- Every #[expect] has a specific reason identifying the sync context.
Annotations added in ~90 files across the workspace. Notable narrow
placements: fabro-server server.rs current_server_target,
build_disk_usage_response, create_test_app_state_with_session_key;
fabro-server install.rs read_to_string rollback snapshot;
fabro-sandbox local.rs list_recursive; fabro-agent cli.rs FOLLOW-UP on
the JSON-stdout writer; fabro-llm providers/common.rs FOLLOW-UP for
load_file_as_base64 (7 translator call sites; revisit if file:// URL
usage grows).
build.rs blanket allows: fabro-api/build.rs, fabro-util/build.rs.
Pre-existing unrelated nightly-clippy warnings fixed under scope:
fabro-sandbox sandbox_spec.rs (unused_imports, unused_async),
reconnect.rs (unused_variables, unused_async).
Verified: cargo +nightly-2026-04-14 clippy --workspace --all-targets
-- -D warnings passes; fmt clean; 4129/4131 tests pass (two known
flakes under parallel nextest load, both pass individually and are
unrelated to this change).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9d1c0d98c7
commit
19939c5f07
91 changed files with 465 additions and 13 deletions
10
clippy.toml
10
clippy.toml
|
|
@ -8,6 +8,16 @@ disallowed-methods = [
|
|||
{ path = "std::io::stdin", reason = "Returns a blocking handle; prefer tokio::io::stdin on Tokio paths. Document intentional sync stdin with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::io::stdout", reason = "Returns a blocking handle; prefer tokio::io::stdout on Tokio paths. Document intentional sync stdout with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::io::stderr", reason = "Returns a blocking handle; prefer tokio::io::stderr on Tokio paths. Document intentional sync stderr with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::read", reason = "Blocking disk read; prefer tokio::fs::read on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::read_to_string", reason = "Blocking disk read; prefer tokio::fs::read_to_string on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::write", reason = "Blocking disk write; prefer tokio::fs::write on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::read_dir", reason = "Blocking directory enumeration; prefer tokio::fs::read_dir on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::copy", reason = "Blocking disk copy; prefer tokio::fs::copy on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::canonicalize", reason = "Blocking path resolution; prefer tokio::fs::canonicalize on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::File::open", reason = "Blocking open; prefer tokio::fs::File::open on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::File::create", reason = "Blocking open; prefer tokio::fs::File::create on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::File::create_new", reason = "Blocking open; prefer tokio::fs::File::create_new on Tokio paths. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "std::fs::OpenOptions::open", reason = "Blocking open; prefer tokio::fs::OpenOptions::open on Tokio paths. OS file-lock semantics may require spawn_blocking instead. Document intentional sync I/O with #[expect(clippy::disallowed_methods, reason = \"...\")]" },
|
||||
{ path = "reqwest::Client::new", reason = "Use fabro_http::http_client() or fabro_http::test_http_client()", allow-invalid = true },
|
||||
{ path = "reqwest::Client::builder", reason = "Use fabro_http::HttpClientBuilder::new()", allow-invalid = true },
|
||||
{ path = "reqwest::blocking::Client::new", reason = "Use fabro_http::blocking_http_client() or fabro_http::blocking_test_http_client()", allow-invalid = true },
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "agent parity test harness: sync std::fs for staging fixture trees and reading captured outputs"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write as _;
|
||||
use std::path::Path;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "build script: runs at compile time outside any runtime"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs};
|
||||
|
||||
|
|
|
|||
|
|
@ -586,6 +586,11 @@ mod tests {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration-style test: writes and reads a fake codex script via sync std::fs to \
|
||||
verify the login_command string passes stdin correctly"
|
||||
)]
|
||||
async fn openai_api_key_cli_login_command_executes_codex_from_local_bin() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let local_bin = dir.path().join(".local/bin");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync git2 operations dominate this module; std::fs usage is part of the same blocking path and not on a Tokio hot path"
|
||||
)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `artifact cp` command: sync file I/O in command handler; not on a Tokio hot path"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `doctor` command: sync directory scan in command handler"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `install` command: sync file I/O in install command handler; not on a Tokio hot path"
|
||||
)]
|
||||
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::Path;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI server record helpers: sync read/write of local server record file"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `server start` command: sync config/record file I/O in startup command; acquire_lock uses spawn_blocking"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
@ -14,6 +19,7 @@ use fabro_util::terminal::Styles;
|
|||
use fabro_util::{Home, dev_token, session_secret};
|
||||
use tokio::net::{TcpStream, UnixStream};
|
||||
use tokio::process::Command as TokioCommand;
|
||||
use tokio::task::spawn_blocking;
|
||||
use tokio::time;
|
||||
|
||||
use super::record;
|
||||
|
|
@ -514,7 +520,12 @@ async fn acquire_lock(storage_dir: &Path) -> Result<std::fs::File> {
|
|||
.with_context(|| format!("creating server lock directory {}", parent.display()))?;
|
||||
}
|
||||
let lock_path_for_open = lock_path.clone();
|
||||
let lock_file = tokio::task::spawn_blocking(move || {
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "OpenOptions::open inside spawn_blocking; file-lock semantics need a real \
|
||||
std::fs::File handle for fabro_proc::try_flock_exclusive"
|
||||
)]
|
||||
let lock_file = spawn_blocking(move || {
|
||||
std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `store dump` command: sync file I/O for dump outputs"
|
||||
)]
|
||||
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
clippy::disallowed_types,
|
||||
reason = "sync CLI `uninstall` command: blocking std::io::Write is the intended output mechanism"
|
||||
)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `uninstall` command: sync file I/O in command handler"
|
||||
)]
|
||||
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI `workflow create` command: sync file I/O creating workflow scaffolding"
|
||||
)]
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI logging setup: sync directory scan during startup"
|
||||
)]
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI manifest builder: sync file I/O building install manifests"
|
||||
)]
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
|
|
|
|||
|
|
@ -1138,6 +1138,10 @@ fn non_zero_u64_from_usize(value: usize) -> Option<NonZeroU64> {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "server-client tests stage local dev-token fixtures with sync std::fs::write"
|
||||
)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "CLI user config: sync file I/O loading user config"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use fabro_config::parse_settings_layer;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
#![allow(clippy::absolute_paths)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::process::Output;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_config::{Storage, envfile};
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
use fabro_vault::{SecretType, Vault};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
use httpmock::MockServer;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
use insta::assert_snapshot;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
|
||||
use super::support::{git_stdout, output_stderr, setup_git_backed_changed_run};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_auth::{AuthCredential, AuthDetails};
|
||||
use fabro_config::Storage;
|
||||
use fabro_model::Provider;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
|
||||
use super::support::{read_text, setup_created_dry_run, setup_local_sandbox_run, text_tree};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
reason = "integration test: occupies a fixed TCP port via sync std::net::TcpListener to \
|
||||
verify the server-start fallback path when the default port is unavailable"
|
||||
)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration test stages server-start fixtures with sync std::fs::write"
|
||||
)]
|
||||
|
||||
use std::process::Stdio;
|
||||
use std::sync::{Arc, Barrier};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::fs;
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
use serde_json::Value;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::fs;
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use assert_cmd::Command;
|
||||
use fabro_test::{TestContext, fabro_snapshot, test_context};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
use insta::assert_snapshot;
|
||||
use serde_json::Value;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use fabro_test::test_context;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
#![allow(clippy::absolute_paths)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::test_context;
|
||||
use serde_json::Value;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::test_context;
|
||||
|
||||
use super::{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::test_context;
|
||||
|
||||
use super::{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use fabro_test::test_context;
|
||||
|
||||
use super::{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
clippy::needless_borrow,
|
||||
clippy::needless_borrows_for_generic_args
|
||||
)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::process::Output;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync env-file load/save used at CLI and server startup; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync config loading utilities used at startup; not on a Tokio path"
|
||||
)]
|
||||
|
||||
extern crate self as fabro_config;
|
||||
|
||||
mod defaults;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync config file load used at startup; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fabro_types::settings::run::RunGoalLayer;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
//! tree in `fabro_types::settings::v2`. This module keeps the workflow
|
||||
//! discovery helpers and re-exports resolved project settings.
|
||||
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync project-level config discovery and workflow listing; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
//! that used to be re-exported from here live under
|
||||
//! `fabro_types::settings::run` now.
|
||||
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync run-config loading helpers; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fabro_types::settings::SettingsLayer;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync parse of docker-compose.yml files during devcontainer resolution; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
|
|||
|
|
@ -731,6 +731,10 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "test fixture setup uses sync std::fs::write to create a fake feature directory"
|
||||
)]
|
||||
async fn fetch_feature_local_integration() {
|
||||
let tmp_src = tempfile::tempdir().unwrap();
|
||||
let feature_dir = tmp_src.path().join("my-feature");
|
||||
|
|
|
|||
|
|
@ -161,6 +161,12 @@ pub struct DevcontainerResolver;
|
|||
|
||||
impl DevcontainerResolver {
|
||||
/// path: repo root (or explicit .devcontainer/ path)
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: DevcontainerResolver::resolve does sync std::fs::read_to_string / \
|
||||
read_dir across several devcontainer.json lookups. One-shot per workflow run \
|
||||
(not per-request); acceptable today but should migrate to tokio::fs."
|
||||
)]
|
||||
pub async fn resolve(path: &Path) -> Result<DevcontainerSpec> {
|
||||
let (json_path, devcontainer) = Self::find_and_parse(path)?;
|
||||
let repo_root = Self::repo_root_from_json_path(&json_path, path);
|
||||
|
|
@ -409,6 +415,11 @@ impl DevcontainerResolver {
|
|||
})
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: sync std::fs helpers for devcontainer.json lookup; called once at \
|
||||
workflow startup via resolve(). Should migrate to tokio::fs with resolve()."
|
||||
)]
|
||||
fn find_and_parse(path: &Path) -> Result<(PathBuf, DevcontainerJson)> {
|
||||
// Check standard locations
|
||||
let candidates = [
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "fabro-install: sync CLI install/uninstall bookkeeping; not on a Tokio hot path"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ impl RecordingInterviewer {
|
|||
///
|
||||
/// # Errors
|
||||
/// Returns an error if serialization or file writing fails.
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync helper for test-mode interview recording storage; not on a Tokio path"
|
||||
)]
|
||||
pub fn save_to_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
let json = self.to_json()?;
|
||||
std::fs::write(path, json).map_err(|err| {
|
||||
|
|
@ -66,6 +70,10 @@ impl RecordingInterviewer {
|
|||
///
|
||||
/// # Errors
|
||||
/// Returns an error if file reading or deserialization fails.
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync helper for test-mode interview recording storage; not on a Tokio path"
|
||||
)]
|
||||
pub fn load_from_file(path: &Path) -> std::io::Result<Vec<(Question, Answer)>> {
|
||||
let json = std::fs::read_to_string(path).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
|
|
|
|||
|
|
@ -92,6 +92,13 @@ pub fn mime_from_extension(path: &str) -> &str {
|
|||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the file cannot be read.
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: sync std::fs::read for file:// attachments, invoked from sync \
|
||||
translators (translate_input/translate_messages) across all providers. Pre-existing; \
|
||||
7 call sites in sync translators would need restructuring to wrap in spawn_blocking \
|
||||
at each async chokepoint. file:// URLs are rare in practice; revisit if usage grows."
|
||||
)]
|
||||
pub fn load_file_as_base64(path: &str) -> Result<(String, String), std::io::Error> {
|
||||
let expanded = path.strip_prefix("~/").map_or_else(
|
||||
|| path.to_string(),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ pub fn flock_unlock(file: &File) -> io::Result<()> {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tests exercise sync flock semantics on real temp files; uses std::fs::File directly"
|
||||
)]
|
||||
mod tests {
|
||||
use std::fs::File;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::time::Instant;
|
|||
use async_trait::async_trait;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::process::{Child, Command};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tokio::{fs, time};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
|
|
@ -156,6 +157,10 @@ impl Sandbox for LocalSandbox {
|
|||
path: &str,
|
||||
depth: Option<usize>,
|
||||
) -> Result<Vec<DirEntry>, String> {
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync recursive read_dir; caller wraps invocation in tokio::task::spawn_blocking"
|
||||
)]
|
||||
fn list_recursive(
|
||||
base: &std::path::Path,
|
||||
prefix: &str,
|
||||
|
|
@ -197,7 +202,7 @@ impl Sandbox for LocalSandbox {
|
|||
|
||||
let full_path = self.resolve_path(path);
|
||||
let max_depth = depth.unwrap_or(1);
|
||||
tokio::task::spawn_blocking(move || {
|
||||
spawn_blocking(move || {
|
||||
let mut entries = Vec::new();
|
||||
list_recursive(&full_path, "", 0, max_depth, &mut entries)?;
|
||||
Ok(entries)
|
||||
|
|
@ -537,6 +542,10 @@ async fn sigterm_then_kill(child: &mut Child) {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sandbox tests stage fixtures with sync std::fs writes/reads"
|
||||
)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use crate::sandbox_record::SandboxRecord;
|
|||
///
|
||||
/// `daytona_api_key` is forwarded to the Daytona SDK when the provider is
|
||||
/// `"daytona"`. Pass `None` to fall back to the `DAYTONA_API_KEY` env var.
|
||||
#[allow(clippy::unused_async, unused_variables)]
|
||||
pub async fn reconnect(
|
||||
record: &SandboxRecord,
|
||||
daytona_api_key: Option<String>,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use std::sync::Arc;
|
|||
use anyhow::anyhow;
|
||||
#[cfg(feature = "daytona")]
|
||||
use fabro_github::GitHubCredentials;
|
||||
#[allow(unused_imports)]
|
||||
use fabro_types::RunId;
|
||||
|
||||
use crate::config::WorktreeMode;
|
||||
|
|
@ -142,6 +143,7 @@ impl SandboxSpec {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_async)]
|
||||
pub async fn build(
|
||||
&self,
|
||||
event_callback: Option<SandboxEventCallback>,
|
||||
|
|
|
|||
|
|
@ -358,6 +358,10 @@ impl Sandbox for WorktreeSandbox {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "worktree tests stage fixtures with sync std::fs writes in temp dirs"
|
||||
)]
|
||||
mod tests {
|
||||
use std::sync::Mutex;
|
||||
|
||||
|
|
|
|||
|
|
@ -891,6 +891,11 @@ async fn post_install_finish(
|
|||
("FABRO_DEV_TOKEN".to_string(), dev_token.clone()),
|
||||
]);
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "install-finish handler: reads current settings file once to produce a rollback \
|
||||
snapshot before writing the new settings; one-shot per install-finish request"
|
||||
)]
|
||||
let previous_settings = std::fs::read_to_string(state.config_path.as_ref()).ok();
|
||||
|
||||
if let Err(err) = persist_install_outputs_direct(
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use fabro_types::settings::server::{
|
|||
};
|
||||
use ipnet::IpNet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::fs;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::ApiError;
|
||||
|
|
@ -130,7 +131,7 @@ impl GitHubMetaResolver {
|
|||
}
|
||||
|
||||
async fn load_cache(&self) -> Result<Option<GitHubMetaCache>> {
|
||||
match tokio::fs::read(&self.cache_path).await {
|
||||
match fs::read(&self.cache_path).await {
|
||||
Ok(contents) => match serde_json::from_slice(&contents) {
|
||||
Ok(cache) => Ok(Some(cache)),
|
||||
Err(error) => {
|
||||
|
|
@ -151,13 +152,13 @@ impl GitHubMetaResolver {
|
|||
|
||||
async fn store_cache(&self, cache: &GitHubMetaCache) -> Result<()> {
|
||||
if let Some(parent) = self.cache_path.parent() {
|
||||
tokio::fs::create_dir_all(parent)
|
||||
fs::create_dir_all(parent)
|
||||
.await
|
||||
.with_context(|| format!("creating {}", parent.display()))?;
|
||||
}
|
||||
|
||||
let contents = serde_json::to_vec(cache).context("serializing GitHub meta cache")?;
|
||||
tokio::fs::write(&self.cache_path, contents)
|
||||
fs::write(&self.cache_path, contents)
|
||||
.await
|
||||
.with_context(|| format!("writing {}", self.cache_path.display()))?;
|
||||
Ok(())
|
||||
|
|
@ -322,6 +323,10 @@ pub fn github_meta_cache_path(cache_dir: &Path) -> PathBuf {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tests stage IP allowlist fixtures with sync std::fs::write"
|
||||
)]
|
||||
mod tests {
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
|
|
|
|||
|
|
@ -1420,6 +1420,10 @@ struct PrunePlan {
|
|||
total_size_bytes: u64,
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync helper invoked from async handler via spawn_blocking (see callers at :1301 / :1341)"
|
||||
)]
|
||||
fn build_disk_usage_response(
|
||||
summaries: &[fabro_store::RunSummary],
|
||||
storage_dir: &std::path::Path,
|
||||
|
|
@ -2392,6 +2396,10 @@ pub fn create_app_state_with_env_lookup(
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "test helper writes a fixture server.env with sync std::fs::write"
|
||||
)]
|
||||
pub(crate) fn create_test_app_state_with_session_key(
|
||||
settings: SettingsLayer,
|
||||
session_secret: Option<&str>,
|
||||
|
|
@ -3535,6 +3543,11 @@ struct WorkerServerRecord {
|
|||
|
||||
fn current_server_target(storage_dir: &std::path::Path) -> anyhow::Result<String> {
|
||||
let record_path = Storage::new(storage_dir).server_state().record_path();
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync helper invoked from worker_command (sync) via spawn_blocking at the async \
|
||||
boundary in execute_run_subprocess; see commit 9d1c0d98c"
|
||||
)]
|
||||
let content = std::fs::read_to_string(&record_path)
|
||||
.map_err(|err| anyhow::anyhow!("failed to read {}: {err}", record_path.display()))?;
|
||||
let record: WorkerServerRecord = serde_json::from_str(&content).map_err(|err| {
|
||||
|
|
@ -4462,7 +4475,7 @@ async fn execute_run_subprocess(state: Arc<AppState>, run_id: RunId) {
|
|||
|
||||
let state_for_build = Arc::clone(&state);
|
||||
let run_dir_for_build = run_dir.clone();
|
||||
let build_cmd_result = tokio::task::spawn_blocking(move || {
|
||||
let build_cmd_result = spawn_blocking(move || {
|
||||
worker_command(
|
||||
state_for_build.as_ref(),
|
||||
run_id,
|
||||
|
|
@ -6894,6 +6907,10 @@ async fn get_graph(
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "server unit tests stage fixtures with sync std::fs writes"
|
||||
)]
|
||||
mod tests {
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::sync::OnceLock;
|
|||
use axum::body::Body;
|
||||
use axum::http::{HeaderMap, HeaderValue, StatusCode, header};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use tokio::fs;
|
||||
|
||||
const INSTALL_MODE_MARKER: &str = "__FABRO_MODE__ = \"install\"";
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ async fn read_disk_asset(path: &str) -> Option<Vec<u8>> {
|
|||
async fn read_disk_asset_from_root(root: &Path, path: &str) -> Option<Vec<u8>> {
|
||||
let candidate = root.join(path);
|
||||
if candidate.is_file() {
|
||||
tokio::fs::read(candidate).await.ok()
|
||||
fs::read(candidate).await.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -197,6 +198,10 @@ fn is_source_map(path: &str) -> bool {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tests stage static asset fixtures with sync std::fs::write"
|
||||
)]
|
||||
mod tests {
|
||||
use axum::http::{HeaderMap, HeaderValue, header};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn read_doc(relative_path: &str) -> String {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@
|
|||
clippy::manual_assert,
|
||||
clippy::manual_let_else
|
||||
)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests stage fixtures with sync std::fs; test infrastructure, not Tokio-hot path"
|
||||
)]
|
||||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Method, Request, StatusCode};
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ pub fn get(path: &str) -> Option<AssetBytes> {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "test walks the assets/ directory with sync std::fs::read_dir to enforce a build invariant"
|
||||
)]
|
||||
mod tests {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync read/write of the anonymous-id cache file; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync read of the panic log at telemetry startup; not on a Tokio path"
|
||||
)]
|
||||
|
||||
use std::panic::PanicHookInfo;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,11 @@ pub async fn upload(path: &Path) -> anyhow::Result<()> {
|
|||
let write_key = SEGMENT_WRITE_KEY
|
||||
.ok_or_else(|| anyhow::anyhow!("SEGMENT_WRITE_KEY not set at compile time"))?;
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "telemetry uploader invoked via detached subprocess (__send_analytics); runs \
|
||||
outside the main Tokio runtime as a standalone process, so sync read is fine"
|
||||
)]
|
||||
let content = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("read telemetry batch {}", path.display()))?;
|
||||
let Some(payload) = build_segment_batch(&content) else {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync pre-fork filesystem interaction; the whole module runs before fork/exec"
|
||||
)]
|
||||
|
||||
/// Spawn a fully detached subprocess that survives parent exit and terminal
|
||||
/// close.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "fabro-test: shared test infrastructure; sync std::fs throughout is intentional for \
|
||||
test fixtures, snapshots, and scratch directories. Tokio-path code under test sits \
|
||||
in other crates."
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "build script: runs at compile time outside any runtime"
|
||||
)]
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
use std::{env, fs};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync atomic read/write of the local dev token file; not on a Tokio hot path. \
|
||||
OpenOptions::open is used for setting 0o600 mode on unix"
|
||||
)]
|
||||
|
||||
use std::fs;
|
||||
#[expect(
|
||||
clippy::disallowed_types,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
reason = "file-backed tracing sink: sync BufWriter<File> is intentional; writes happen on a \
|
||||
dedicated per-event guard and are not in an async hot path"
|
||||
)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync File::create and read_to_string for the on-disk run-log file; not on Tokio path"
|
||||
)]
|
||||
|
||||
use std::io::{self, BufWriter, Write};
|
||||
use std::path::Path;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "integration tests that exercise sync dev-token file operations"
|
||||
)]
|
||||
|
||||
use std::fs;
|
||||
|
||||
use fabro_util::Home;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "fabro-vault: sync secret-file storage; not used on a Tokio hot path"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
use std::{fmt, io};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: mixed async/sync workflow artifact lifecycle. Sync std::fs::write remains at per-stage persistence points; the Tokio-path hot reads were migrated to tokio::fs in commit 9d1c0d98c. Remaining writes should follow."
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
@ -9,6 +14,7 @@ use fabro_types::{
|
|||
};
|
||||
use futures::future::BoxFuture;
|
||||
use serde_json::Value;
|
||||
use tokio::fs;
|
||||
|
||||
use crate::context::{self, Context};
|
||||
use crate::error::{Error, Result};
|
||||
|
|
@ -174,7 +180,7 @@ pub async fn sync_artifacts_to_env(
|
|||
}
|
||||
}
|
||||
|
||||
let content = tokio::fs::read_to_string(&local_path).await.map_err(|e| {
|
||||
let content = fs::read_to_string(&local_path).await.map_err(|e| {
|
||||
Error::engine(format!("failed to read local artifact {local_path}: {e}"))
|
||||
})?;
|
||||
|
||||
|
|
@ -325,7 +331,7 @@ async fn resolve_explicit_file_ref(value: &str, env: &dyn Sandbox) -> Result<Str
|
|||
return Ok(value.to_string());
|
||||
}
|
||||
|
||||
let content = tokio::fs::read_to_string(local_path)
|
||||
let content = fs::read_to_string(local_path)
|
||||
.await
|
||||
.map_err(|e| Error::engine(format!("failed to read local artifact {local_path}: {e}")))?;
|
||||
let filename = Path::new(local_path)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use fabro_agent::Sandbox;
|
|||
use fabro_sandbox::shell_quote;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tokio::fs;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
/// A file discovered by the find command.
|
||||
|
|
@ -264,7 +265,7 @@ async fn compute_artifact_info(
|
|||
let mime = mime_guess::from_path(relative_path)
|
||||
.first_or_octet_stream()
|
||||
.to_string();
|
||||
let data = tokio::fs::read(local_path)
|
||||
let data = fs::read(local_path)
|
||||
.await
|
||||
.map_err(|e| format!("failed to read {}: {e}", local_path.display()))?;
|
||||
let bytes = u64::try_from(data.len()).unwrap_or(u64::MAX);
|
||||
|
|
@ -353,6 +354,7 @@ pub async fn collect_artifacts(
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::disallowed_methods, reason = "tests write fixtures to disk")]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
|
@ -442,11 +444,11 @@ mod tests {
|
|||
.get(remote_path)
|
||||
.ok_or_else(|| format!("File not found: {remote_path}"))?;
|
||||
if let Some(parent) = local_path.parent() {
|
||||
tokio::fs::create_dir_all(parent)
|
||||
fs::create_dir_all(parent)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to create dirs: {e}"))?;
|
||||
}
|
||||
tokio::fs::write(local_path, content.as_bytes())
|
||||
fs::write(local_path, content.as_bytes())
|
||||
.await
|
||||
.map_err(|e| format!("Failed to write: {e}"))?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync workflow file resolver invoked at stage setup; not on a Tokio hot path"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
|
|
|
|||
|
|
@ -314,6 +314,10 @@ pub fn sanitize_ref_component(s: &str) -> String {
|
|||
|
||||
/// Filenames allowed in per-node directories on the shadow branch.
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tests write git state fixtures to disk"
|
||||
)]
|
||||
mod tests {
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -395,6 +395,10 @@ impl Handler for AgentHandler {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tests persist per-iteration state fixtures"
|
||||
)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
|
|
|||
|
|
@ -348,6 +348,10 @@ impl Handler for SubWorkflowHandler {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tests persist manager-loop state fixtures"
|
||||
)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: per-run `workflow create` operation; writes .fabro/ scaffolding to disk via sync std::fs"
|
||||
)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: rebuild metadata uses sync std::fs::canonicalize during async checkpoint rebuild; per-run, not per-request"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use std::path::PathBuf;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "sync workflow operation loader; runs at workflow-load time"
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ pub(crate) async fn load_from_store(
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::disallowed_methods, reason = "tests stage pipeline fixtures")]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ pub fn transform(parsed: Parsed, options: &TransformOptions) -> Result<Transform
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::disallowed_methods, reason = "tests stage pipeline fixtures")]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: run dump writes serialized run contents to disk; invoked from sync CLI command handlers"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
#[expect(
|
||||
clippy::disallowed_types,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "FOLLOW-UP: run lookup walks the runs directory; invoked from sync CLI and async server paths"
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ pub async fn git_replace_worktree(sandbox: &dyn Sandbox, path: &str, branch: &st
|
|||
mod tests {
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "These unit tests use the real git CLI to construct sandbox-git fixture repositories."
|
||||
reason = "These unit tests use the real git CLI to construct sandbox-git fixture repositories and sync-write fixtures to disk."
|
||||
)]
|
||||
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -615,6 +615,7 @@ impl Transform for ImportTransform {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::disallowed_methods, reason = "tests stage transform fixtures")]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
#![allow(clippy::absolute_paths)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "workflow attractor compat test: reads fixture files with sync std::fs"
|
||||
)]
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@
|
|||
//! cp_integration -- --ignored`
|
||||
|
||||
#![allow(clippy::ignore_without_reason)]
|
||||
#![expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "workflow cp integration test: stages sandbox fixtures with sync std::fs"
|
||||
)]
|
||||
|
||||
use fabro_sandbox::SandboxRecord;
|
||||
use fabro_sandbox::reconnect::reconnect;
|
||||
|
|
|
|||
|
|
@ -170,6 +170,10 @@ pub struct FixtureWebhookOptions {
|
|||
impl FixtureState {
|
||||
pub fn load_from_path(path: impl AsRef<Path>) -> Result<Self, String> {
|
||||
let path = path.as_ref();
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "twin test harness: sync fixture load from disk; not on a Tokio hot path"
|
||||
)]
|
||||
let contents = fs::read_to_string(path)
|
||||
.map_err(|err| format!("failed to read fixture {}: {err}", path.display()))?;
|
||||
serde_json::from_str(&contents)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue