5abb3072c739d634fe4f4312f32f6665a3f30a69
11 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d495f0b984 |
surface BYOK failures + chronic-failures card + WorkflowRunStatus mirrors GitHub conclusions (#722)
- Migrates `WorkflowRunStatus` from `running | completed | cancelled` to a 9-state mirror of `workflow_run.conclusion`. Backfill: old `completed → success`, `cancelled → failure`. New rows write `hook.workflow_run.conclusion` verbatim via `statusFromConclusion`. - Adds Discord links to `formatApiKeyErrorSummary` (both missing-key and 401 invalid-key shapes). - Repo console: `<ChronicFailuresCard>` fires when the last 3 terminal-state runs are all `failure`. Pure DB read; latest-run button hidden for pre-dispatch failures (`runId: null`). - `StatusIcon` distinguishes `cancelled` (gray X, intentional stop) from `failure` (red X) so the visual matches the chronic-card threshold. - Pre-dispatch failures (workflow lookup miss, dispatch API error) write `failure` instead of `cancelled` so they feed the card. - Cascade: every `status: "completed"` filter in billing routes / cron / cohort queries / analyzer becomes `status: "success"`. Verified end-to-end on `pullfrog/preview-722-failure-surfaces` — Better Stack logs confirm webhooks reached the preview deploy and all three e2e runs got `marked as failure (conclusion=failure)` via the new mapper. Closes #679, #702. |
||
|
|
8f9208bd3f |
feat: Amazon Bedrock support via routing slug (#720)
* add Amazon Bedrock as a routing slug introduces a single `bedrock/byok` catalog entry that the harness translates to the appropriate Bedrock model ID at run time via `BEDROCK_MODEL_ID`. routes Anthropic IDs through claude-code (with `CLAUDE_CODE_USE_BEDROCK=1`) and everything else through opencode's `amazon-bedrock` provider — keeps the catalog flat for an audience that needs version pinning rather than aliasing. accepts either `AWS_BEARER_TOKEN_BEDROCK` or `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` for auth; both validated alongside `AWS_REGION` and `BEDROCK_MODEL_ID` in `validateAgentApiKey`. catalog drift tests, the bumps cron, and per-alias smoke scripts all skip routing slugs since there's no fixed `resolve` to validate. docs/bedrock.mdx walks through setup; wiki/model-resolution.md has a section explaining why bedrock breaks the usual alias pattern. closes pullfrog/pullfrog#40 * ci: add bedrock env vars to test workflows mirrors the new bedrock provider's required env vars (AWS_BEARER_TOKEN_BEDROCK inherited from org secret + AWS_REGION + BEDROCK_MODEL_ID hardcoded) into both .github/workflows/test.yml files so the ci.test "env vars cover all provider API keys" assertion passes. * docs(bedrock): clearer setup flow + screenshot of model selector restructures the setup section into three concrete steps in execution order: select Bedrock from the dropdown, store the bearer token as a secret (Pullfrog or GitHub — links to keys.mdx for the trade-off), then add region + model id directly in pullfrog.yml since neither is sensitive. enable-model-access in the Bedrock console moved to step 4 (only required once per model and only when AWS rejects the call, not blocking on first run). adds a screenshot of the console model selector with Amazon Bedrock selected so readers can recognize the UI state they're aiming for. * fix(bedrock): tolerate raw Bedrock model IDs in validateAgentApiKey main.ts passes the resolved model into validateAgentApiKey (`payload.proxyModel ?? resolvedModel ?? payload.model`). For Bedrock, `resolveModel` translates `bedrock/byok` into the raw AWS model ID (e.g. `us.anthropic.claude-opus-4-6-v1`), which has no `/` and so trips parseModel inside getModelEnvVars. Detect the no-slash case and re-run the bedrock setup check (auth + region; BEDROCK_MODEL_ID is already enforced upstream by resolveModel). Caught by PR #720 e2e dispatch on pullfrog/preview-720-bedrock — "invalid model slug 'us.anthropic.claude-opus-4-6-v1' — expected 'provider/model'". Two regression tests cover the raw-ID path. * fix(bedrock): always prepend amazon-bedrock/ prefix when bedrock-routed opencode.ts was gating the prefix-injection on `!isBedrockAnthropicId(rawModel)`, on the theory that Anthropic Bedrock IDs always go through claude-code. But `PULLFROG_AGENT=opencode` is a documented escape hatch — when it forces opencode for an Anthropic Bedrock model, the prefix still has to be added or opencode fails with 'Model not found: <modelId>/.'. The Anthropic-vs-other discriminant only belongs in resolveAgent. Once an agent is selected, it should consistently honor the bedrock route. Caught by the PULLFROG_AGENT=opencode + Opus 4.6 e2e on pullfrog/preview-720-bedrock — run 25823437606. * ui+docs(bedrock): bespoke setup callout + clearer docs UI: - BedrockSetupCallout in components/AgentSettings.tsx covers both the Model costs section and the onboarding card. Detects bedrock via resolveDisplayAlias().routing === "bedrock", shows a dedicated message ("store AWS_BEARER_TOKEN_BEDROCK as a secret, then put AWS_REGION + BEDROCK_MODEL_ID directly in pullfrog.yml") + link to the setup guide. Replaces the generic "X, Y, or Z is required" prompt that misrepresented the three values as three separate secrets to add (and used the wrong "or" connector for what's actually an AND). - OnboardingCard re-uses the same callout with the gradient-card variant. Docs: - Drop the obsolete "Enable model access" step. AWS retired the manual enrollment page; foundation models auto-enable on first invocation. Anthropic models still need a one-time use-case form for first-time users — surfaced under the AccessDenied troubleshooting entry. - Drop the "Testing a different model in one run" PULLFROG_MODEL note. It introduced the secrets-vs-vars distinction we want to keep out of the bedrock setup story. - Step 3 already recommends hardcoding region + model id in pullfrog.yml. Workflow template: - The default pullfrog.yml customers receive (utils/github/pullfrog.yml.ts) now references AWS_BEARER_TOKEN_BEDROCK from secrets but inlines AWS_REGION and BEDROCK_MODEL_ID as plain values. Matches the docs. * fix(bedrock): three review-caught edges in routing + UI copy Addresses three real issues from PR #720 review: 1. agent.ts: PULLFROG_MODEL=bedrock/byok no longer leaks the literal sentinel "bedrock" downstream. resolveCliModel returns the alias's resolve field verbatim, which for routing entries IS the sentinel. Refactored both the env-override and slug-lookup paths through a shared resolveSlug() that recognizes routing aliases and defers to their backing env var (BEDROCK_MODEL_ID). 2. models.ts: isBedrockAnthropicId() now anchors on a discrete dot/slash/colon-segment match (case-insensitive) instead of a substring contains. The substring check was fragile in both directions for inference-profile ARNs (BEDROCK_MODEL_ID accepts ARNs per AWS docs) — a non-Anthropic profile whose user-chosen name contained "anthropic" would mis-route to claude-code, and an Anthropic profile whose name omitted it would miss CLAUDE_CODE_USE_BEDROCK=1. 3. AgentSettings.tsx: BedrockSetupCallout's configured-state copy showed "AWS_BEARER_TOKEN_BEDROCK configured" even when the user satisfied the gate via AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY, gaslighting access-key users about a secret they never set. Detect which auth method is actually present and name the right secret(s) in the success message. Regression tests in models.test.ts (5 new isBedrockAnthropicId cases including positive and negative ARN forms) and agent.test.ts (2 new PULLFROG_MODEL=bedrock/byok cases). 171/171 action tests pass. * yml template: add commented AWS access-key alternative for Bedrock auth Mirrors the IAM access-key path verified end-to-end on PR #720 e2e run 25830764987. Bearer token stays as the primary nudge; the access-key pair is the fallback for users who can't mint Bedrock API keys. * yml template: drop redundant 'or, alternatively' annotation * ui+docs(bedrock): rewrite callout copy + refresh screenshot Reframes the BedrockSetupCallout away from generic BYOK language to a Bedrock-specific message: leads with "Amazon Bedrock is configured entirely via environment variables", lists all four (auth, region, model id), and ends with the requested CTA sentence ("click below to learn more about Bedrock support in Pullfrog"). Promotes the "Bedrock setup guide" docs link from an inline anchor to a prominent button (always visible, regardless of auth state). The "Add AWS_BEARER_TOKEN_BEDROCK" affordance is now a secondary chip shown only when no auth secret is configured. Refreshes docs/images/model-selector-bedrock.png to capture the new callout — the prior screenshot still showed the old generic "BYOK / X, Y, or Z required" wording. |
||
|
|
868576a474 |
audit: format byok auth errors actionably + tighten audit prompt
- `action/utils/apiKeys.ts`: rewrite the missing-key body as Markdown with linked CTAs (repo secrets / model settings / docs). add `isApiKeyAuthError` + `formatApiKeyErrorSummary` covering both shapes: missing key (#679) and revoked/invalid 401 key (#702). - `action/main.ts`: reclassify in the result-failure branch and the catch block so the PR progress comment surfaces the actionable CTA instead of the raw `Invalid API key · Fix external API key` / numbered-list dump. - `scripts/analyze-logs.ts`: split `failure:user-misconfig` into `:no-key` and `:invalid-key` so both buckets are visible separately and the audit can ignore them as user-correctable. - `.github/workflows/run-audit.yml`: add three explicit prompt rules — cross-customer signal required (≥3 distinct accounts; single-customer concentration is not enough), recovered failures are not actionable, user misconfig is out of scope. closes the loop on #679 / #702 being filed in the first place. |
||
|
|
e6d34ee01b |
add OpenRouter proxy for managed model routing and OSS program (#488)
* add OpenRouter proxy for managed model routing and OSS program proxy layer that mints ephemeral OpenRouter keys for users without BYOK API keys. two paths: pro plan users get their selected model proxied via OpenRouter; OSS program repos (hard-coded allowlist in config.ts) get free Claude Opus. BYOK env vars (PULLFROG_MODEL/OPENCODE_MODEL) always take precedence. frontend: OSS repos see a static "Opus (Free)" badge with the model dropdown disabled and no API key requirement. all models now carry openRouterResolve metadata for proxy target resolution. Made-with: Cursor * implement OSS program: proxy infrastructure for free model credits server-side OSS allowlist determines eligible repos. action mints ephemeral OpenRouter keys via OIDC-authenticated /api/proxy-token endpoint (idempotent on runId, $10 per-key safety limit). keys are disabled on workflow completion when no running refs remain. HWM-based usage sync tracks cumulative spend per account. schema: ProxyKey model, Account.usageUsd/activeKeyId, WorkflowRun.proxyKeyId action: OIDC credential stashing, resolveProxyModel uses server oss flag frontend: isOss flows from server page to components (no client allowlist) Made-with: Cursor * address PR review: repo cross-check, key retirement lifecycle, dead code removal - proxy-token: verify runId belongs to OIDC-authenticated repo via repo relation - add retireKey() shared primitive: disable in OpenRouter first, then mark disabled in DB - rotateKey: retire old active key after swap to prevent orphans - webhook: replace inline cleanupProxyKey with retireKey calls - syncAccountUsage: skip disabled keys - remove vestigial AccountPlan/plan field from action types - add disabled field to ProxyKey schema + migration Made-with: Cursor * replace deprecated opencode/mimo-v2-flash-free with mimo-v2-pro-free Made-with: Cursor * fix migration ordering: rename disabled migration to sort after table creation Made-with: Cursor * squash proxy key migrations into single migration Made-with: Cursor * add preview repo to OSS allowlist for testing Made-with: Cursor * populate OSS allowlist from oss-program-invitees.json Made-with: Cursor * format oss-program-invitees.json Made-with: Cursor * add installed public repos to OSS allowlist split ossRepos into three provenance-tracked lists: - internalRepos (pullfrog, colinhacks, RobinTail) - installedPublicRepos (external public non-fork repos with active installs) - invitees (from oss-program-invitees.json) also adds scripts/list-oss-candidates.ts to regenerate the installed list Made-with: Cursor * fix: resolve tokens before clearing OIDC env vars resolveTokens → acquireNewToken → isOIDCAvailable() checks ACTIONS_ID_TOKEN_REQUEST_URL/TOKEN env vars. The new OIDC stashing code was deleting them in restricted shell mode before resolveTokens ran, causing it to fall through to the GitHub App path which requires GITHUB_APP_ID/GITHUB_PRIVATE_KEY. Made-with: Cursor * derive proxy-token auth from OIDC claims, add ensureWorkflowRun upsert - proxy-token no longer requires body.runId; uses claims.run_id + claims.repository - shared ensureWorkflowRun upsert called from both webhook and proxy-token - workflow_run_requested handler now eagerly creates WorkflowRun records - eliminates race condition between webhook and action proxy-token call Made-with: Cursor * hardcode PULLFROG_ACCOUNT_ID, document preview debugging lessons GitHub node IDs are constant — no reason for this to be an env var. Removes the trailing-newline bug that caused P2025 errors. Adds wiki docs on workflow testing, Vercel env gotchas, and Neon preview branch discovery. Made-with: Cursor * fix: parse OpenRouter create-key response correctly the API returns `key` at the top level, not inside `data` Made-with: Cursor * onboarding cards, unlock OSS model selection, simplify console - add OnboardingCard component with two states: workflow install and model+test (dispatches "Tell me a joke" for test run) - replace PromptBox overlay gates with dedicated onboarding cards; PromptBox is now just the form, always enabled - use hasWorkflowRuns DB check to decide onboarding vs promptbox - unlock ModelSelector for OSS repos (was locked to Opus badge); resolve proxyModel from repo's selected model alias in run-context - rename "API key" row to "Model costs" with pure client-side states: OSS covered, auto-resolve, free model, BYOK with env var names - add "(Recommended)" badge to model aliases with recommended: true - remove OSS_MODEL_DISPLAY_NAME constant and secrets-fetching logic Made-with: Cursor * update stale xai model snapshot Made-with: Cursor * rename Permissions to Security, hide git push toggle, add shell isolation toggle with disabled state for public repos, remove opentoad agent name from logs Made-with: Cursor * chevron hover states, sidebar hooks/security entries Made-with: Cursor * address PR review feedback: rename recommended→preferred, fix dispatch orphan, update wiki docs - rename `recommended` to `preferred` in model alias registry to distinguish from the UI "Recommended" badge (which is hardcoded for opus + codex only) - cancel precreated WorkflowRun when workflow lookup fails in dispatch-workflow - replace run_sql/vercel env pull in wiki docs with neonctl + Prisma pattern - extend scripts/neon-branch.ts to output DATABASE_URL via neonctl - add Recommended badge to GPT Codex alongside Claude Opus in ModelSelector Made-with: Cursor |
||
|
|
3a1ffde545 |
update model snapshot (opencode latest → gpt-5.4-nano)
Made-with: Cursor |
||
|
|
30d68e53a7 |
fix: skip API key validation for free opencode models
free models (big-pickle, gpt-5-nano, etc.) define envVars: [] and isFree: true but validateAgentApiKey always required at least one provider key. now the validation is model-aware: free models bypass the check, keyed models validate their specific vars, and auto-select still requires at least one known key. closes #483 Made-with: Cursor |
||
|
|
6d25adfd1a |
Agent & model refactor (#478)
* agent & model refactor with ASKPASS git auth, UI restructure, clerk v7 Made-with: Cursor * fix stale agent/effort refs, add tests for askpass + model resolution - reviewCleanup.ts: payload.agent -> payload.model, remove effort - selectMode.ts PlanEdit: remove delegation/subagent/effort references - pullfrog.yml.ts: update env vars (drop GOOGLE_API_KEY/CURSOR_API_KEY, add GOOGLE_GENERATIVE_AI_API_KEY/XAI_API_KEY/MOONSHOT_API_KEY/OPENCODE_API_KEY) - FlagsSettings/RepoInstructionsSection: remove stale effort/timeout copy - new: gitAuthServer.test.ts (10 tests — lifecycle, token delivery, tamper detection, script gen) - new: agent.test.ts (4 tests — default opentoad, AGENT_OVERRIDE, invalid override) - new: models.test.ts (19 tests — parseModel, resolution, registry invariants) - update models.dev snapshot Made-with: Cursor * fix changed-agents.sh to filter legacy agent files from CI matrix legacy agent files (claude.ts, codex.ts, etc.) are @ts-nocheck and not exported from index.ts. changed-agents.sh now reads index.ts imports to build the active agent set and treats changes to inactive files as non-agent changes (opentoad canary only). Made-with: Cursor * remove MCP file tools, old agent harnesses, and obsolete security tests ASKPASS-based git auth makes the old MCP file tool security layer unnecessary: - token never in subprocess env, so symlink/gitattributes/hook attacks can't exfiltrate it - agents now use native file tools (OpenCode builtin read/edit) deleted: - action/mcp/file.ts (file_read, file_write, file_edit, file_delete, list_directory) - action/mcp/index.ts (dead re-export) - agent harnesses: claude.ts, codex.ts, cursor.ts, gemini.ts, opencode.ts - opencode-runner.ts (inlined into opentoad.ts) - security tests that validated MCP file tool restrictions - commented-out three-step review flow (~300 lines) - sanitizeSchema/wrapSchema dead code from mcp/shared.ts - OPENCODE_MODEL_MINI/MAX env vars (effort-level model overrides removed) updated test prompts to use generic file ops instead of MCP tool names. restored pkg-json-scripts + requirements-txt-attack (test --ignore-scripts defense). Made-with: Cursor * bump actions/checkout v4 → v6 (node 24) node 20 actions deprecated june 2, 2026. Made-with: Cursor * temporarily disable fail-fast on agnostic tests to debug checkout@v6 Made-with: Cursor * re-enable fail-fast on agnostic tests Made-with: Cursor * fix test token mismatch: mint OIDC tokens scoped to target repo CI tests override GITHUB_REPOSITORY to pullfrog/test-repo but inherit the runner's GITHUB_TOKEN (scoped to pullfrog/app), causing 401s on every run-context fetch. Clear GITHUB_TOKEN in the test subprocess so ensureGitHubToken() mints a properly scoped token via OIDC. Also centralizes the default GITHUB_REPOSITORY in runAgentStreaming instead of repeating it in every test file, and fixes preview-cleanup to remove workers from all queues (not just name-matching ones). Made-with: Cursor * fix ensureGitHubToken to try OIDC when app credentials are absent ensureGitHubToken only attempted token minting when GITHUB_APP_ID and GITHUB_PRIVATE_KEY were set. In CI, OIDC is available but app creds aren't exposed — so the guard prevented minting entirely. Made-with: Cursor * dead code cleanup: remove remnants of deleted agents, file tools, effort system remove unused @anthropic-ai/claude-agent-sdk and @openai/codex-sdk deps, orphaned file-tool security tests, dead GEMINI_MODEL passthrough, stale opencode-runner wiki refs, deleted test file references, and MCP file tool docs. rename docs/effort → docs/models. fix vitest setup: move dotenv to globalSetup (runs once before forks instead of per-file, 19s → 200ms). Made-with: Cursor * address review feedback: remove dead code, update stale references - remove AGENT_OVERRIDE (only opentoad exists) - remove shellToolName plumbing (always restricted shell) - bump action version to 0.0.179 - remove CURSOR_API_KEY from all workflows/configs - remove OPENCODE_MODEL_MINI/MAX from workflows/docs - delete wiki/effort.md, rewrite docs/effort.mdx as "Models" - rewrite wiki/modes.md: orchestrator/subagent → single agent - simplify flag system: drop builtin flag extraction (debug, effort, timeout, agent), keep custom flag replacement only - reserve all legacy flag names to prevent custom flag conflicts Made-with: Cursor * regenerate lockfile after removing claude-agent-sdk and codex-sdk Made-with: Cursor * fix import ordering, add lockfile check to pre-push hook Made-with: Cursor * remove dead debug payload field, stale packageExtensions Made-with: Cursor * merge proc-sandbox and token-exfil into a single test proc-sandbox and token-exfil were duplicative — both tested that SANDBOX_TEST_TOKEN couldn't be exfiltrated. consolidated into token-exfil with shell:restricted (which actually exercises filterEnv) and the /proc attack vector hints from proc-sandbox. Made-with: Cursor * fix wiki adversarial.md to match actual tokenExfil validator Made-with: Cursor |
||
|
|
78cf05f111 | Clean up url resolution | ||
|
|
071e885d63 |
Add upload tool and related APIs (#187)
* Add utils for r2 upload * Add the tool and new routes * fix auth issue * sign headers * add comment * use our own API key to auth signed uploads * Restructure things slightly * tweak * tweak * add comments * tweak * revert a thing * twaek * drop mime type filtering * new incarnation of mime type filtering * jsut allow all octet-streams * simplify further * tweak * update lockfile --------- Co-authored-by: Colin McDonnell <colinmcd94@gmail.com> |
||
|
|
69b9b96ddd | Refactor (#109) | ||
|
|
9e019d89d2 |
Clean up actions and payloads (#98)
* Clean up actions and payloads * Clean up action * Cleanup |