mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-08 03:10:26 +00:00
Configure implement-plan sandbox tooling (#377)
Fixes implement-plan runs failing at verify time when cloned sandboxes lack Git identity, and prevents the verify forbidden-pattern scan from being silently skipped when `rg` is unavailable. ## Changes - Install `ripgrep` in the Fabro Daytona image and bump the snapshot ref to `fabro-v12` so Daytona rebuilds it. - Configure repository-local Git `user.name` and `user.email` from `run.git.author` during workflow initialization before lifecycle setup commands or workflow stages run. - Make the implement-plan verify stage fail explicitly if `rg` is missing. ## Validation - `cargo test -p fabro-workflow configure_sandbox_git_identity_uses_run_author --quiet` - `cargo +nightly-2026-04-14 fmt --check --all` - `cargo +nightly-2026-04-14 clippy -p fabro-workflow --all-targets -- -D warnings` - `cargo run -p fabro-cli -- validate .fabro/workflows/implement-plan/workflow.fabro` --- [](https://github.com/EveryInc/compound-engineering-plugin) 🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
This commit is contained in:
parent
bad8c0baf5
commit
1c2abbb2f5
4 changed files with 51 additions and 4 deletions
|
|
@ -1,7 +1,7 @@
|
|||
FROM ubuntu:24.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl git ca-certificates build-essential pkg-config libssl-dev unzip python3 \
|
||||
curl git ripgrep ca-certificates build-essential pkg-config libssl-dev unzip python3 \
|
||||
xvfb xfce4 xfce4-terminal x11vnc novnc dbus-x11 \
|
||||
libx11-6 libxrandr2 libxext6 libxrender1 libxfixes3 libxss1 libxtst6 libxi6 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ auto_stop = "30m"
|
|||
repo = "fabro-sh/fabro"
|
||||
|
||||
[environments.fabro-dev.image]
|
||||
ref = "fabro-v11"
|
||||
ref = "fabro-v12"
|
||||
dockerfile = { path = "Dockerfile" }
|
||||
|
||||
[environments.fabro-dev.resources]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ digraph ImplementPlan {
|
|||
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD.", model="gpt-55", reasoning_effort="xhigh"]
|
||||
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
|
||||
simplify_gpt [label="Simplify (GPT-55)", prompt="@prompts/simplify.md", model="gpt-55"]
|
||||
verify [label="Verify", shape=parallelogram, script="git fetch origin main 2>&1 && git merge --no-edit --no-stat origin/main 2>&1 && cargo +nightly-2026-04-14 fmt --all 2>&1 && cargo dev docs refresh 2>&1 && cargo +nightly-2026-04-14 fmt --check --all 2>&1 && ! rg -n 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\bActorRef\b|\bActorKind\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\s*==\s*\"disabled\"' lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml 2>&1 && cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --workspace --status-level slow --profile ci 2>&1 && cargo dev docs check 2>&1 && bun install --frozen-lockfile 2>&1 && (cd apps/fabro-web && bun run typecheck) 2>&1 && (cd apps/fabro-web && bun run test) 2>&1 && (cd lib/packages/fabro-api-client && bun run typecheck) 2>&1 && cargo dev build -- -p fabro-cli --release 2>&1", goal_gate=true, retry_target="fixup"]
|
||||
verify [label="Verify", shape=parallelogram, script="git fetch origin main 2>&1 && git merge --no-edit --no-stat origin/main 2>&1 && cargo +nightly-2026-04-14 fmt --all 2>&1 && cargo dev docs refresh 2>&1 && cargo +nightly-2026-04-14 fmt --check --all 2>&1 && { command -v rg >/dev/null 2>&1 || { echo 'rg is required for verify'; exit 127; }; } && ! rg -n 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\bActorRef\b|\bActorKind\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\s*==\s*\"disabled\"' lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml 2>&1 && cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --workspace --status-level slow --profile ci 2>&1 && cargo dev docs check 2>&1 && bun install --frozen-lockfile 2>&1 && (cd apps/fabro-web && bun run typecheck) 2>&1 && (cd apps/fabro-web && bun run test) 2>&1 && (cd lib/packages/fabro-api-client && bun run typecheck) 2>&1 && cargo dev build -- -p fabro-cli --release 2>&1", goal_gate=true, retry_target="fixup"]
|
||||
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all format, clippy, Rust test, docs, TypeScript typecheck/test, and build failures.", max_visits=3]
|
||||
|
||||
start -> toolchain
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use fabro_hooks::{HookContext, HookDecision, HookEvent, HookExecutionContext, Ho
|
|||
use fabro_model::Catalog;
|
||||
use fabro_sandbox::{
|
||||
GitSetupIntent, ReadBeforeWriteSandbox, SandboxEventCallback, SandboxSpec,
|
||||
reconnect_for_run_with_callback,
|
||||
reconnect_for_run_with_callback, shell_quote,
|
||||
};
|
||||
use fabro_static::EnvVars;
|
||||
use fabro_vault::Vault;
|
||||
|
|
@ -27,6 +27,7 @@ use super::types::{InitOptions, Initialized, LlmSpec, Persisted, SandboxEnvSpec}
|
|||
use crate::devcontainer_bridge::{devcontainer_to_snapshot_config, run_devcontainer_lifecycle};
|
||||
use crate::error::Error;
|
||||
use crate::event::{Event, RunNoticeCode, RunNoticeLevel};
|
||||
use crate::git::GitAuthor;
|
||||
use crate::github_token_source::{AppIatMinter, GitHubTokenSource};
|
||||
use crate::handler::llm::{AgentAcpBackend, AgentApiBackend, BackendRouter, routing};
|
||||
use crate::handler::{HandlerRegistry, default_registry};
|
||||
|
|
@ -66,6 +67,25 @@ fn git_setup_intent(run_options: &RunOptions) -> GitSetupIntent {
|
|||
}
|
||||
}
|
||||
|
||||
async fn configure_sandbox_git_identity(
|
||||
sandbox: &dyn Sandbox,
|
||||
author: &GitAuthor,
|
||||
) -> Result<(), Error> {
|
||||
let command = format!(
|
||||
"git config --local user.name {} && git config --local user.email {}",
|
||||
shell_quote(&author.name),
|
||||
shell_quote(&author.email)
|
||||
);
|
||||
sandbox
|
||||
.exec_command(&command, 10_000, None, None, None)
|
||||
.await
|
||||
.map_err(|err| Error::engine_with_source("Sandbox git identity setup failed", err))?
|
||||
.into_result("git config user identity")
|
||||
.map_err(|err| Error::engine_with_source("Sandbox git identity setup failed", err))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_sandbox_env(
|
||||
spec: &SandboxEnvSpec,
|
||||
github_app: Option<&fabro_github::GitHubCredentials>,
|
||||
|
|
@ -574,6 +594,10 @@ pub async fn initialize(
|
|||
}
|
||||
}
|
||||
}
|
||||
if sandbox.origin_url().is_some() {
|
||||
let git_author = options.run_options.git_author();
|
||||
configure_sandbox_git_identity(sandbox.as_ref(), &git_author).await?;
|
||||
}
|
||||
|
||||
if !options.lifecycle.setup_commands.is_empty() {
|
||||
options.emitter.emit(&Event::SetupStarted {
|
||||
|
|
@ -915,6 +939,29 @@ mod tests {
|
|||
(result, events)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn configure_sandbox_git_identity_uses_run_author() {
|
||||
let sandbox = fabro_sandbox::test_support::MockSandbox::linux();
|
||||
let author = GitAuthor::from_options(
|
||||
Some("Fabro Bot".to_string()),
|
||||
Some("fabro-bot@example.com".to_string()),
|
||||
);
|
||||
|
||||
configure_sandbox_git_identity(&sandbox, &author)
|
||||
.await
|
||||
.expect("git identity should configure");
|
||||
|
||||
let commands = sandbox
|
||||
.captured_commands
|
||||
.lock()
|
||||
.expect("captured_commands lock poisoned")
|
||||
.clone();
|
||||
assert_eq!(commands, vec![
|
||||
"git config --local user.name 'Fabro Bot' && git config --local user.email \
|
||||
fabro-bot@example.com"
|
||||
]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn initialize_prepares_sandbox_and_uses_persisted_run_dir() {
|
||||
let temp = tempfile::tempdir().unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue