⚒️ Generated with [Fabro](https://fabro.sh)
This commit is contained in:
Fabro 2026-03-19 11:03:46 -04:00
parent 0626e52abe
commit 0b72db684f
3 changed files with 56 additions and 0 deletions

38
graph.fabro Normal file
View file

@ -0,0 +1,38 @@
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
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."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 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 clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}

13
manifest.json Normal file
View file

@ -0,0 +1,13 @@
{
"run_id": "01KM39Z9DVCBB36GZMYAA6P0FJ",
"workflow_name": "ImplementAndSimplify",
"goal": "# Detect GitHub App visibility mismatch during `repo init`\n\n## Context\n\nWhen `fabro repo init` detects the GitHub App is not installed for a repo, it shows a generic \"install at\" URL. But if the repo owner differs from the app owner, the app must be **public** to be installable. Users currently get no guidance about this, leading to confusion when the install link doesn't work.\n\n## Changes\n\n### 1. Add `get_authenticated_app()` to fabro-github\n\n**File:** `lib/crates/fabro-github/src/lib.rs`\n\nAdd two public structs near the existing response types (around line 40):\n\n```rust\npub struct AppOwner {\n pub login: String,\n}\n\npub struct AppInfo {\n pub slug: String,\n pub owner: AppOwner,\n}\n```\n\nAdd function after `check_app_installed` (after line 525):\n\n- `pub async fn get_authenticated_app(client, jwt, base_url) -> Result<AppInfo, String>`\n- Calls `GET {base_url}/app` with Bearer JWT auth\n- Returns `AppInfo` on 200, errors on 401/other\n\n### 2. Add `is_app_public()` to fabro-github\n\n**File:** `lib/crates/fabro-github/src/lib.rs`\n\nAdd function after `get_authenticated_app`:\n\n- `pub async fn is_app_public(client, slug, base_url) -> Result<bool, String>`\n- Calls `GET {base_url}/apps/{slug}` **without** auth (public apps are visible to unauthenticated requests)\n- Returns `Ok(true)` on 200, `Ok(false)` on 404, error on other status\n\n### 3. Update `check_github_app_installation` in init.rs\n\n**File:** `lib/crates/fabro-cli/src/init.rs`\n\nIn the `Ok(false)` branch (line 250), before showing the install URL:\n\n1. Call `get_authenticated_app()` to get the app's owner\n2. Compare `app_info.owner.login` with the repo `owner` (case-insensitive)\n3. If they differ, call `is_app_public()` to check visibility\n4. If the app is private and owners differ, show a targeted warning:\n\n```\n ! GitHub App \"{slug}\" is private but this repo belongs to a different owner ({repo_owner}).\n The app must be made public before it can be installed outside {app_owner}.\n Update visibility at: https://github.com/settings/apps/{slug}\n```\n\nAll new checks are best-effort — failures are silently ignored (the existing generic warning still shows).\n\n### 4. Tests\n\n**File:** `lib/crates/fabro-github/src/lib.rs` (test module)\n\nAdd tests using existing `mockito` patterns:\n\n- `get_authenticated_app_success` — 200 returns parsed `AppInfo`\n- `get_authenticated_app_auth_failure` — 401 returns error\n- `is_app_public_returns_true_on_200` — public app\n- `is_app_public_returns_false_on_404` — private app\n- `is_app_public_no_auth_header` — verify no Authorization header is sent\n\n## Verification\n\n1. `cargo test -p fabro-github` — new unit tests pass\n2. `cargo build --workspace` — compiles cleanly\n3. `cargo clippy --workspace -- -D warnings` — no warnings\n4. Manual: run `fabro repo init` in a repo owned by a different org than the app to verify the warning appears\n",
"start_time": "2026-03-19T15:03:46.300185Z",
"node_count": 13,
"edge_count": 16,
"run_branch": "fabro/run/01KM39Z9DVCBB36GZMYAA6P0FJ",
"base_sha": "74d32e39583f346bdbceb8e6da04759c5c9118c1",
"base_branch": "main",
"workflow_slug": "implement",
"host_repo_path": "/Users/bhelmkamp/p/fabro-sh/fabro"
}

5
sandbox.json Normal file
View file

@ -0,0 +1,5 @@
{
"provider": "daytona",
"working_directory": "/home/daytona/workspace",
"identifier": "fabro-01KM39Z9DVCBB36GZMYAA6P0FJ"
}