Commit Graph

71 Commits

Author SHA1 Message Date
Colin McDonnell 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.
2026-05-14 02:12:38 +00:00
Colin McDonnell 60cc8772a6 fix(log-audit): kill 404 noise from /api/github/installation-token at source (#693) (#708)
* fix(log-audit): kill 404 noise from `/api/github/installation-token` at source (#693)

Closes #693. Issue diagnosed a surface symptom (`log.error` on expected
404s) but missed the actual root causes. Investigation revealed two
distinct populations producing identical 3-call 404 bursts:

1. **Fork-CI on `pullfrog/pullfrog`**: `test-token.yml` and
   `trigger-sync.yml` ship with `on: push: main`, so every fork inherits
   them and 404s our token endpoint on first push. Self-inflicted noise
   that scales with fork count.
2. **Real users hitting the full action without installing the App**:
   `/api/repo/.../run-context` uses the caller's `GITHUB_TOKEN` to read
   the repo from GitHub and then unconditionally lazy-provisions
   Account+Repo rows via `fetchOrCreateRepo`, even when the App isn't
   installed. Generates phantom DB rows and false `new account created`
   team@ alerts. (Confirmed via Prisma: `ezcorp-org` has an Account row
   with `installerLogin: null`, never installed our App.)

Both populations then trip the client retry loop in
`acquireTokenViaOIDC`, which matched `"Token exchange failed"` and
retried 3× on terminal 4xx — tripling log volume and wasting CI time.

## Changes

- `action/.github/workflows/{test-token,trigger-sync}.yml`: gate jobs
  with `if: github.repository == 'pullfrog/pullfrog'`. Forks inherit
  the files but the jobs no-op.
- `app/api/repo/[owner]/[repo]/run-context/route.ts`: call
  `getRepoInstallation` first; return 404 with install URL if the App
  isn't installed, before any DB writes or GitHub repo fetch.
- `action/utils/github.ts`: introduce `TokenExchangeError` for non-2xx
  server responses; `acquireNewToken` no longer retries it. Retry now
  fires only on genuine network/timeout failures. 404 surfaces a
  user-actionable error pointing at the install URL.
- `app/api/github/installation-token/route.ts`: move `log.error` inside
  the 500 branch only. 404 branch is silent (expected user-state) and
  returns the same install URL message for consistency.

## Effect

- Better Stack `level=error` lines from this path: 6/day → 0.
- Failed user-trial CI time: 3 wasted token requests → 1.
- User-facing error: opaque `Token exchange failed: 404` → actionable
  install URL.
- No more phantom Account rows from never-installed callers.

Skipped per design discussion: phantom-account cleanup (conservative —
stop the bleed, leave history), `AGENTS.md` rule (overgeneralized).

* review: address oracle leak + per-env install URL + retryable 5xx

Addresses pullfrog[bot] (IMPORTANT) and Copilot review findings on #708:

- **Install-status oracle in `run-context`** [pullfrog, Copilot]:
  `getRepoInstallation` runs with our App's JWT, *before* the caller's
  bearer token is validated against the repo. Pre-PR the route was
  uniformly bad-token-shaped; the new install-specific 404 turned it
  into an unauthenticated oracle distinguishing "Pullfrog installed
  here" from "not installed". Collapsed the 404 message to match the
  outer catch's ambiguous "repository not found or token lacks access".
  Legit runners still get the actionable install URL from
  `/api/github/installation-token`, which IS gated by OIDC.

- **Hardcoded `github.com/apps/pullfrog`** [Copilot]: server-side
  `installation-token` now uses `GITHUB_APP_INSTALL_URL` from
  `app/globals.ts`, so dev/staging deployments with a different
  `GITHUB_APP_SLUG` direct users to the correct app. Action-side
  echoes the server's `error` body when present (single source of
  truth) and falls back to a generic message only if the body isn't
  JSON.

- **Transient 5xx/429 made terminal** [Copilot]: `shouldRetry` now
  returns `true` for `TokenExchangeError` with `status >= 500` or
  `status === 429`. 4xx remains terminal (the actual #693 fix). Real
  outages no longer fail the workflow immediately.

- **Stale comment** [pullfrog, Copilot]: reworded the comment at
  `installation-token/route.ts:141` to reflect the new retry policy
  ("the action surfaces this once (no retry)" instead of "the action
  retries on this").

* review: restore caller-token-first auth in run-context

Pre-PR, `getEnrichedRepo({owner, repo, token})` used the caller's
token as the auth boundary — `getRepo({token})` succeeding was the
proof-of-access check. My initial install-gate inverted the order
and ran the App-credentialed `getRepoInstallation` first, which is
how it became:

- an install-status oracle (pullfrog bot, addressed previously by
  matching the outer-catch wording), and
- an outbound amplifier against our App JWT for arbitrary `owner/repo`
  (pullfrog bot, this commit).

Reordered so `getRepo({token})` runs first. Garbage / unauthorized
bearers get rejected by github (mapped to 403 by the outer catch)
before any App-credentialed call fires. `getRepo` is cached 5min,
so `getEnrichedRepo` below remains a free re-hit.
2026-05-13 17:47:13 +00:00
Colin McDonnell f87e0f878c action: minimize pullfrog.yml permissions and drop actions:read (#594)
* action: minimize pullfrog.yml permissions and drop actions:read

The recommended pullfrog.yml workflow asked for a permissions block that's
broader than what the action actually uses with the workflow GITHUB_TOKEN —
all real work (git push, PR comments, reviews) goes through installation
tokens that the action mints via OIDC. Customer security scanners flagged
the workflow-level block as too permissive.

- Move permissions to the job level and reduce to id-token: write,
  pull-requests: write, issues: write. contents:read is the implicit default
  and covers actions/checkout; contents:write, checks:read are unused by
  any GITHUB_TOKEN consumer; actions:read was only used by post-cleanup's
  listJobsForWorkflowRun call.
- Replace listJobsForWorkflowRun with a SIGTERM/SIGINT handler in main.ts
  that calls core.saveState("cancelled", "true"); post-cleanup reads it
  back via core.getState. Same cancel-vs-failure UX, no extra scope needed.
- Sync the docs (headless-action, getting-started, action/README) and the
  two dogfood pullfrog.yml workflows to the new minimal block. Update the
  post-cleanup wiki to describe the saveState approach.

* action: drop pull-requests/issues from required workflow scopes

Switch postCleanup.ts to mint its own short-lived installation token via OIDC
(acquireNewToken with issues:write + pull_requests:write) instead of using the
workflow GITHUB_TOKEN. Same comment-update behavior, but the workflow no longer
needs those scopes — the only permissions Pullfrog ever asks for are id-token:write
(OIDC exchange) and contents:read (actions/checkout).

Also fixes a bug from the previous commit: setting an explicit permissions block
drops every unlisted scope to none (with metadata as the only exception), so
omitting contents would have broken actions/checkout. Restored at both workflow
and job level.

* action: scope id-token:write to pullfrog job, not workflow level

id-token:write is the powerful one — it lets a job mint OIDC tokens that can
be exchanged for cloud credentials or our installation tokens. Keeping it at
workflow level means any future job added to this file silently inherits it.
Move it to the job level where it's actually used; leave only contents:read
at workflow level as a safe baseline for any future jobs.

* action: move stuck-comment cleanup server-side, drop write perms entirely

The action's post-cleanup step lived inside the runner and used the workflow
GITHUB_TOKEN to update the "Leaping into action…" progress comment when a run
failed/cancelled, requiring pull-requests:write + issues:write at the workflow
level. Move that responsibility to the workflow_run.completed webhook handler:
it already has installation-token access via the GitHub App, runs server-side
(no Pullfrog API dependency loop on failure), and lets us drop both write perms.

Recommended workflow permissions block is now truly minimal:

  permissions:
    contents: read
  jobs:
    pullfrog:
      permissions:
        id-token: write
        contents: read

Server side
- handleWorkflowRunCompleted: when conclusion != "success" and the WorkflowRun
  has progressCommentId, mint installation octokit and update the stuck comment
  in place. Try issues.getComment first, fall back to pulls.getReviewComment on
  404 (we don't store comment type — one wasted GET on the rarer review case).
- Reuses buildPullfrogFooter and updateProgressComment from pullfrog/internal,
  matching the wording the action used to write client-side.

Client side
- Delete action/utils/postCleanup.ts and action/post.ts.
- Remove post: + post-if: from action/action.yml.
- Drop runPostCleanup wiring from action/commands/gha.ts and action/play.ts.
- Remove the SIGTERM/saveState handler I added in main.ts in the previous commit
  (no longer needed; cancel/fail signal comes from the webhook hook payload).

Plumbing
- Extract isLeapingIntoActionCommentBody into action/utils/leapingComment.ts so
  the predicate can be re-exported via pullfrog/internal without dragging the
  MCP server's transitive type graph into the Next.js app's typecheck.
- mcp/comment.ts re-exports from the new location for backward compat.

Wiki
- Delete wiki/post-cleanup.md (obsolete; cleanup is now a one-liner branch in
  the workflow_run webhook handler).

* chore: ignore .worktrees in biome config

Recently-added pnpm worktree feature creates nested git worktrees under
.worktrees/, each with their own biome.jsonc declaring root. Biome's
recursive scan trips on the nested config and fails pnpm lint. Excluding
the directory matches the existing .gitignore entry.

* fix: address PR #594 review findings

Two real bugs caught by code review:

1. handleWorkflowRunWebhook.ts:323 — drop the /m flag on the stuck-comment
   detection regex. With /m, ^ matches any line start, so any finalized
   progress comment that embeds a task list (report_progress writes
   `- [x]`/`- [ ]` lines via todoTracking.ts) would be flagged as "stuck"
   and silently overwritten with the "This run croaked" boilerplate
   whenever the workflow concluded non-success after the agent's final
   summary already landed. Restores the body-start anchoring the original
   in-process postCleanup.ts:90 had.

2. action/scripts/check-entrypoint-imports.ts — drop ../post.ts from the
   esbuild entry-point list (the file was deleted in aa43b9af). The
   `pnpm check:entrypoints` step in test.yml would have failed on every
   run with an unresolvable-entry-point error.

Plus three small follow-ups:
- main.ts:580 — comment said "post-cleanup has its own verify-retry loop"
  but post-cleanup is gone. Updated to describe the new server-side path.
- mcp/comment.ts:443 — comment said "so post script doesn't think the run
  failed". Updated to describe the actual current consumers of wasUpdated.
- commands/gha.ts:84 — `--post` help text said "run post-cleanup flow" but
  with the post-cleanup path removed, --post is only valid alongside the
  `token` subcommand for installation-token revocation. Updated wording.

* fix(action): scope --post help text to gha token subcommand

Root gha help text was documenting --post, but --post only makes sense
paired with the token subcommand (it's how the post step revokes the
installation token previously acquired in the main step). Move it to a
dedicated gha token help section and add a parser layer that rejects
--post on the bare gha command.

  $ pullfrog gha --help
  usage: pullfrog gha [subcommand]
  ...
  options:
    -h, --help   show help

  $ pullfrog gha token --help
  usage: pullfrog gha token [--post]
  ...
  options:
    -h, --help   show help
    --post       revoke the previously-acquired token (post-step usage only)

* webhook: artifact-aware cleanup of stranded leaping comments on success

Previously the workflow_run.completed cleanup only handled non-success
conclusions. Extend it to also catch the rare case where a successful
run leaves a "Leaping into action…" comment stuck (in-process cleanup at
action/main.ts:723 normally handles this, but can be skipped on SIGKILL,
runner host crash, or any exit path that bypasses main()'s finally block).

New behavior in cleanupStuckProgressComment:

  - cancelled       → update with "cancelled 🛑" body  (unchanged)
  - failure (other) → update with "croaked 😵" body    (unchanged)
  - success + artifact recorded → delete the comment (the artifact is the
                                  user-facing surface; the leaping comment
                                  is just stale UI noise at this point)
  - success + no artifact recorded → delete the comment AND alert
                                     team@pullfrog.com via emailAlert

The "success + no artifact" path is "should never happen" territory: the
run claims success but produced no review, PR, issue, plan, or summary
comment. The team alert helps us catch in-process cleanup regressions or
artifact-tracking gaps. hasRecordedArtifact reads {review,pr,issue,
planComment,summaryComment}NodeId off the WorkflowRun row to make the call.

* webhook: narrow stuck-comment detection to leaping prefix only

Drop the stranded-todo-pattern branch from cleanupStuckProgressComment.
The leaping prefix is highly specific and impossible to confuse with a
legitimate summary; a leading todo line is not — the agent's
error-reporting paths can produce useful explanatory comments whose
body leads with a checklist (e.g. "here's what I was working on" + the
incomplete todo list), and we don't want to silently overwrite those
with the generic "croaked" boilerplate.

In-process cleanup at action/main.ts:723 still handles the stranded-todo
case in the common path (gated on !finalSummaryWritten with full access
to the in-memory tool state). Missing the rare runner-died-mid-todo case
server-side is a worthwhile trade vs. the false-positive risk on real
explanatory comments.
2026-05-07 18:59:52 +00:00
Colin McDonnell 4b3c5ca905 rename agent key to opencode and add skill invocation coverage (#541)
* rename agent key to opencode and add skill invocation coverage.

add skill-invoke tests for claude and opencode with local play-based validation signals, update CI matrices, and include the current tracked refactors in this branch for review.

Made-with: Cursor

* exclude agent-specific skill-invoke tests from wrong agent in CI matrix

* address review follow-up and preserve workflow run UI tweak.

switch changed-agents ci coverage to exercise the opentoad implementation path while keeping the opencode expectation, and include the local workflow run client interaction updates requested on this branch.

Made-with: Cursor

* remove opentoad agent filename from runtime.

rename the opencode harness implementation file from opentoad.ts to opencode.ts and update ci coverage input accordingly so action code no longer carries the old filename.

Made-with: Cursor

* ensure security prompt bypass is set on every test fixture.

this keeps adversarial and permissions harnesses from being blocked by the default prompt-injection refusal path during CI security tests.

Made-with: Cursor

---------

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
2026-04-15 19:38:36 +00:00
Colin McDonnell 3c2f3722ff fix action package exports and build ESM library entrypoints.
emit real ESM runtime + declaration outputs for programmatic imports, align package exports/types with built files, and add a no-cjs policy note.

Made-with: Cursor
2026-04-12 19:49:21 +00:00
Colin McDonnell 6541bdc4f4 test-token: use auth-only endpoint to actually verify the token
Made-with: Cursor
2026-04-12 19:44:03 +00:00
Colin McDonnell 1393ffb7b8 fix test-token workflow: use full action ref so runCli takes local path
Made-with: Cursor
2026-04-12 19:37:24 +00:00
Colin McDonnell f663d5e34d add workflow_dispatch test for get-installation-token action
Made-with: Cursor
2026-04-12 19:34:53 +00:00
Colin McDonnell ed90735ba0 drop redundant NODE_AUTH_TOKEN="" from publish step
Made-with: Cursor
2026-04-12 19:03:22 +00:00
Colin McDonnell bbcf91a06e fix publish workflow: add build step, use OIDC trusted publishing, bump 0.0.196
publish was missing a build step so the npm tarball had no dist/.
switch from NPM_TOKEN to OIDC trusted publishing — explicitly unset
NODE_AUTH_TOKEN so setup-node's .npmrc doesn't override the OIDC flow.
bump version since v0.0.195 tag exists from the failed publish attempt.

Made-with: Cursor
2026-04-12 19:02:32 +00:00
Colin McDonnell 421607cf97 fix push-to-action: use CLI direct invocation for token acquisition
the inline `node -e` + `TOKEN=$(...)` approach broke because
`core.getIDToken()` in @actions/core writes `::debug::` and
`::add-mask::` to stdout, polluting the captured value.

`node cli.ts gha token` uses `core.setOutput()` which writes to
the $GITHUB_OUTPUT file instead of stdout.

Made-with: Cursor
2026-04-12 00:47:41 +00:00
Colin McDonnell 8cd36d221a sandbox native filesystem tools to prevent /proc/self/environ exfiltration (#509)
* sandbox native filesystem tools to prevent /proc/self/environ exfiltration

the agent's native Read/Grep/Edit tools can bypass the shell sandbox by
reading /proc/self/environ directly. this adds agent-native filesystem
restrictions using the highest-precedence, non-overridable config for each CLI:

OpenCode: OPENCODE_PERMISSION env var with external_directory deny-all + /tmp allow,
plus deletion of untrusted .opencode/plugins/ and .opencode/tools/ before launch.

Claude Code: managed-settings.json at /etc/claude-code/ with denyRead, permissions.deny,
allowManagedPermissionRulesOnly, allowManagedHooksOnly. also --setting-sources user and
--disallowedTools path patterns as belt-and-suspenders.

Made-with: Cursor

* add Glob to Claude Code /proc and /sys deny lists

closes gap identified in review — Glob can enumerate /proc entries.
added to both managed-settings.json permissions.deny and --disallowedTools.

Made-with: Cursor

* run token-exfil test with both agents, hint at native /proc reads

changed tag from "agnostic" (opentoad-only) to "security" so the test
runs with both opentoad and claude. updated prompt to explicitly instruct
the agent to try reading /proc/self/environ via native Read tool.
added API keys to action-agnostic CI job for claude support.

Made-with: Cursor

* move token-exfil to crossagent matrix, remove redundant permissions.deny

- moved token-exfil from agnostic/ to crossagent/ so it runs via the
  agent matrix (claude + opentoad in parallel) instead of sequentially
- removed permissions.deny per-tool rules from managed-settings.json;
  sandbox.filesystem.denyRead is the single enforcement mechanism
- reverted action-agnostic env vars to minimal set
- updated wiki to match

Made-with: Cursor

* document post-spawn API key deletion analysis in security wiki

evaluated whether API key env vars can be deleted from agent processes
after spawn. OpenCode snapshots env at startup (safe to delete), but
Claude Code re-reads process.env per request (not viable). documented
as further exploration item with per-agent breakdown and caveats.

Made-with: Cursor

* fix stale tokenExfil path references in wiki docs

moved from test/agnostic/ to test/crossagent/ in directory tree
and adversarial test example.

Made-with: Cursor

* revert accidental prisma.config.ts changes

Made-with: Cursor

* hardcode PULLFROG_MODEL per agent in test runner to avoid DB model mismatch

when PULLFROG_AGENT forces a specific agent, the DB-configured model may
belong to a different provider (e.g. openai model with claude agent).
PULLFROG_MODEL short-circuits the DB slug resolution entirely.

Made-with: Cursor
2026-04-02 22:31:41 +00:00
Colin McDonnell 0055aef618 feat: add Claude Code agent for Anthropic model users (#502)
* feat: add Claude Code agent for Anthropic model users

Re-adds Claude Code support (removed in #478) so users with Anthropic API
keys or Claude Code OAuth tokens can use their Claude subscriptions directly.

When an Anthropic model is selected and Claude Code credentials are available,
the system auto-selects the Claude agent instead of OpenCode. The harness
mirrors opentoad's security model: native Bash blocked via --disallowedTools,
MCP ShellTool for restricted shell, ASKPASS for git auth. Includes NDJSON
streaming, provider error detection, cache/cost tracking, browser skill,
and todo progress tracking.

Key changes:
- action/agents/claude.ts: full Claude Code harness
- action/utils/agent.ts: auto-select Claude for anthropic/* models
- action/utils/providerErrors.ts: extracted shared provider error detection
- action/utils/skills.ts: extracted shared skill installation (agent-aware)
- action/models.ts: add CLAUDE_CODE_OAUTH_TOKEN to anthropic envVars
- action/utils/docker.ts: add CLAUDE_CODE_OAUTH_TOKEN to test env allowlist
- CI: add claude to test matrix, pass CLAUDE_CODE_OAUTH_TOKEN secret

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove unused toolId variable, fix apiKeys test env cleanup

The apiKeys test cleanup stripped *_API_KEY vars but missed
CLAUDE_CODE_OAUTH_TOKEN which doesn't match that pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: strip provider prefix from PULLFROG_MODEL in Claude agent

the env override path was returning the raw value (e.g.
"anthropic/claude-sonnet-4-5") without stripping the provider prefix,
causing the Claude CLI to receive an invalid model ID.

Made-with: Cursor

* fix: remove dead cliPath field, add CLAUDE_CODE_OAUTH_TOKEN to workflows

remove unused cliPath from Claude agent RunParams, and pass
CLAUDE_CODE_OAUTH_TOKEN through all pullfrog.yml workflow templates
so users with Claude Pro/Team subscriptions can use their membership.

Made-with: Cursor

* fix: block Bash subagent in Claude Code disallowedTools

Made-with: Cursor

* chore: update model snapshot (opencode/openrouter latest → qwen3.6-plus-free)

Made-with: Cursor

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 03:29:54 +00:00
Colin McDonnell 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
2026-03-25 17:19:55 +00:00
Mateusz Burzyński cccf1775d6 Update actions/setup-node 2026-03-18 12:55:52 +00:00
Colin McDonnell cbbcb64859 restructure docs: split triggers into usage pages, add model resolution docs
- split triggers.mdx into direct-prompting, pr-reviews, issue-enrichment, coding-tasks
- rename manual-setup.mdx to headless-action.mdx (CI integration)
- reorganize sidebar into Getting started / Usage / Reference groups
- add redirects for /triggers and /manual-setup
- add PULLFROG_MODEL env var support across action, workflows, and docs
- rewrite models.mdx with aliases, free models, resolution chain, routers
- update all cross-references in app, components, and docs

Made-with: Cursor
2026-03-12 17:45:15 +00:00
Colin McDonnell 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
2026-03-12 05:22:51 +00:00
Colin McDonnell b472aa1ba9 fix(opencode): add effort-aware model overrides and OpenRouter guidance (#354)
* chore: create empty commit for PR

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(action): trigger preview repo creation workflow

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(opencode): merge repo opencode config and log provider key presence

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(opencode): add effort-aware model override precedence

Add OPENCODE_MODEL_MINI and OPENCODE_MODEL_MAX support with fallback to OPENCODE_MODEL and auto-selection, and keep provider resolution aligned via inline OpenCode config when overrides are used. Update workflow env wiring, test allowlists, and docs (including OpenRouter setup guidance and sidebar ordering) to document the new behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(effort): clarify OpenCode precedence and add section link

Add a concise OpenCode precedence callout in the summary area and link directly to the OpenCode section for full details and examples.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Restructure dash (#372)

* Restructure dash

* WIP

* WIP

* refactor trigger UI: extract PR summary card, add mentions section, rename labels

Co-authored-by: Cursor <cursoragent@cursor.com>

* clean up console UI: remove info icons from section descriptions, rename mentions trigger

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix review feedback: layout, terminology, form scope

- extract console sidebar sections to module-level constant
- align three-column layout breakpoints to xl (match sidebar visibility)
- fix mixed shell/bash terminology in beta page
- scope FormProvider to trigger sections only, restore autoComplete="off"

Co-authored-by: Cursor <cursoragent@cursor.com>

* Bump

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: create empty commit for PR

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(opencode): merge repo opencode config and log provider key presence

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(opencode): add effort-aware model override precedence

Add OPENCODE_MODEL_MINI and OPENCODE_MODEL_MAX support with fallback to OPENCODE_MODEL and auto-selection, and keep provider resolution aligned via inline OpenCode config when overrides are used. Update workflow env wiring, test allowlists, and docs (including OpenRouter setup guidance and sidebar ordering) to document the new behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: update agent rules and OpenCode config docs

Align AGENTS guidance with current preferences and apply review-driven wording updates in OpenCode-related files.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-24 02:05:26 +00:00
Mateusz Burzyński 185ca7a832 Avoid using --ignore-workspace (#353) 2026-02-19 14:41:21 +00:00
Colin McDonnell 0e1f1ccbb7 pass GEMINI_MODEL and OPENCODE_MODEL vars through CI and Docker
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 02:33:00 +00:00
Colin McDonnell 8a64742ddf sync action workflow fail-fast to match root workflow
the root workflow was updated to fail-fast: true but the action
workflow wasn't updated to match. the ci consistency test enforces
they stay in sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 02:10:18 +00:00
Colin McDonnell 6f108237d4 Deployment protection bypass (#298)
* test preview bypass 2

Co-authored-by: Cursor <cursoragent@cursor.com>

* add apiFetch wrapper with Vercel bypass via query param + header

the template workflow was missing VERCEL_AUTOMATION_BYPASS_SECRET,
so all action API calls to preview deployments hit Vercel's
deployment protection without bypass. this also consolidates the
bypass logic into a single fetch wrapper that applies the secret
as both a query parameter (matching server-side forwarding) and
a header for belt-and-suspenders reliability.

Co-authored-by: Cursor <cursoragent@cursor.com>

* security hardening for Vercel bypass

- redact bypass token from webhook forwarder logs and response body
- remove dead x-preview-api-forward header
- refactor getAllSecrets() to use SENSITIVE_PATTERNS instead of hardcoded list
- enforce https:// on API_URL (localhost exempt for local dev)

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 20:01:48 +00:00
David Blass 9071c0ae6c refactor mode selection into delegate tool that spawns subagents (#265) 2026-02-12 19:34:47 +00:00
David Blass bc28c658f2 harden sandbox escape vectors for bash disabled/restricted modes (#257)
* harden sandbox escape vectors for bash disabled/restricted modes

block git config injection (-c flag as subcommand), dangerous subcommands
(config, submodule, rebase, bisect), code-executing arg flags (--exec,
--extcmd), .gitattributes/.gitmodules writes, and package lifecycle scripts.
add retry logic to test runner for transient failures. add security unit
tests and adhoc attack tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* only filter subcommands in nobash, remove nobash from ui

* use regex matching

* iterate on tests

* simplify githooks

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 02:02:41 +00:00
David Blass 19df8372cd add file_read/file_write tools, sandbox tests, CI improvements (#239)
* migrate to flags

* init

* iterate on file write lockdown tests

* improve ci

* fix lockfile

* fix typecheck

* fix lint

* improve pushRestricted

* ok

* fix more

* ok

* remove process.env spreading rule

Co-authored-by: Cursor <cursoragent@cursor.com>

* enhanced fs rw tools

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
2026-02-10 06:35:47 +00:00
Colin McDonnell 102417f442 Add post hooks for cleanup (#193)
* Add post hooks for cleanup

* Switch to signal-based cleanup

* Better exit handling
2026-01-28 01:59:15 +00:00
pullfrog[bot] 90945a9481 chore: update pullfrog.yml workflow 2026-01-28 00:51:37 +00:00
pullfrog[bot] a200d07370 feat: Immediate Leaping into action (#146)
* feat: post "Leaping..." comment immediately without polling GitHub API

This change makes the initial comment response much faster by avoiding
the expensive GitHub API polling that was waiting for workflows to
dequeue (up to 12s+ in some cases).

New architecture:
1. Create WorkflowRun record BEFORE dispatching (no runId yet)
2. Post "Leaping into action..." comment with shortlink URL immediately
3. Dispatch workflow and return
4. workflow_run.requested webhook fills in runId when GitHub dequeues

Shortlink redirect at /api/workflow-run/[id]/logs:
- If runId available: redirects to GitHub workflow run
- If runId null: shows polling page that checks DB every 1.5s

Changes:
- Make `runId` optional on WorkflowRun model (filled in via webhook)
- Add `workflow_run` to expected webhook events
- Add handler for workflow_run.requested to update DB with runId
- Create /api/workflow-run/[id]/logs shortlink redirect route
- Refactor triggerWorkflow.ts to use eager comment pattern
- Update trigger page to use new pattern

Closes #141

* chore: add migration for nullable runId in WorkflowRun

* fix: rm dead code.

* fix: Adjusting the issueNumber prop usage comment.

* fix: shortening and JSDoc for createWorkflowRunRecord.

* fix: Reducing diff, reducing confusion on naming the id.

* Revert "fix: Adjusting the issueNumber prop usage comment."

This reverts commit 34d87c2f8bc58782a53ce5eb14a40935232a4924.

* refactor: reuse buildShortlinkUrl in trigger page

* fix: Reducing confusion on param naming.

* fix: shorter JSDoc.

* Apply suggestion from @RobinTail

* chore: remove unnecessary JSDoc comment from buildShortlinkUrl

* Revert "chore: remove unnecessary JSDoc comment from buildShortlinkUrl"

This reverts commit 491ba6ba3f31c874c9f391871739efa50adb0446.

* fix: confusing naming of var.

* fix: redundant 'let'.

* refactor: move route from `/api/workflow-run/[id]/logs` to `/api/workflow-run-logs/[id]`

Avoids confusion with existing `/api/workflow-run/[runId]` route which uses
GitHub's runId, whereas this new route uses the internal WorkflowRun record id.

* chore: remove old route directory

* refactor: reuse `buildShortlinkUrl()` with `shouldPoll` param

* refactor: add script prop to generateLeapingLoaderHtml

Instead of string-replacing to inject scripts, the function now
accepts an optional script prop that gets wrapped in <script> tags.

* mv script into new LeapingLoaderHtmlProps.

* refactor: extract `buildGithubUrl` helper to avoid repetition

* fix: shorening.

* fix: More clear subtitle.

* refactor: reuse `WORKFLOW_FILENAME` from `app/globals.ts`

* fix: shortening.

* feat: add integrity_id for reliable workflow matching

Pass WorkflowRun record id as integrity_id when dispatching workflows.
The webhook handler parses integrity_id from display_title (via run-name)
for reliable matching, with fallback to repo/owner lookup when missing.

Note: workflow template changes (.github/workflows/pullfrog.yml) need to be
applied manually as the GitHub App lacks workflows permission.

* Revert "feat: add integrity_id for reliable workflow matching"

This reverts commit dbc601233a0dd85ac5f0d608a221e7015e265aaa.

* Add todo for consideration later.

* docs: add plan for action-initiated workflow run correlation

Addresses review feedback requesting research into secure alternatives
to exposing HOOKDECK_API_KEY. Proposes leveraging existing OIDC token
exchange to pass WorkflowRun record ID and correlate with run_id.

* Revert "docs: add plan for action-initiated workflow run correlation"

This reverts commit b9279d0e99db4d85e4144675634afa941858333a.

* FEAT: Add optional integrity_id input, used by run-name, set with partial record id, read by handler for lookup.

* Add integrity_id to app/trigger/[owner]/[repo]/[number]/page.tsx

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>

* feat: Extracting INTEGRITY_ID_LENGTH.

* Add integrity_id to the workflow files of the repo.

* fix: Use Vercel Preview deployment URL into account in buildShortlinkUrl().

* fix: add missing `.rest` prefix in Octokit API call

* revert: remove unnecessary escaping of backticks in comment

* fix: add polling timeout and wrap DB update in try-catch

- Add 3-minute timeout to polling page to prevent indefinite polling
- Wrap updateWorkflowRunComment in try-catch to prevent orphaned comments

* feat: restore job-level deep linking for workflow runs

Adds jobId to WorkflowRun model and captures the first job ID via
listJobsForWorkflowRun() when the workflow_run_in_progress event fires.
The shortlink redirect now appends /job/{jobId} when available, providing
a direct link to the job rather than just the workflow run.

* fix: handle only `workflow_run.in_progress` to avoid race condition

Combine the handling of `runId` and `jobId` into a single update when
`workflow_run.in_progress` fires, avoiding the race condition where
`in_progress` could arrive before `requested` was processed.

* Renae integrity_id -> name

* Clean up

* Clean up

* Shorter timeout

* Add fallback

---------

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
Co-authored-by: Robin Tail <robin_tail@me.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
2026-01-28 00:40:56 +00:00
David Blass 9a8db3e07c add restricted tests, refactor test infrastructure (#150) 2026-01-22 21:06:19 +00:00
Colin McDonnell c6dfe4fa10 Update workflows 2026-01-21 03:27:12 +00:00
Colin McDonnell df4e7a9a4a Update workflows 2026-01-21 03:25:32 +00:00
Colin McDonnell 6af0c721ba Update workflows 2026-01-21 03:24:35 +00:00
David Blass 4e19178c81 fix CI (#111) 2026-01-20 17:25:06 +00:00
David Blass 410b11db71 test CI 2026-01-16 20:21:54 +00:00
David Blass 02a498e0cb update workflows 2026-01-16 16:00:27 +00:00
David Blass e4b086938e iterate on CI 2026-01-16 15:52:37 +00:00
Mateusz Burzyński 332ef73b87 Remove invalid working-directory setting (#105) 2026-01-16 10:56:28 +00:00
Mateusz Burzyński cd16ba67a6 Get rid of incorrect cache-dependency-path in an /action workflow (#104) 2026-01-16 10:47:52 +00:00
Anna Bocharova 9432a5b737 Revert 4c5cf44 2026-01-16 11:31:38 +01:00
Anna Bocharova 4c5cf444a2 Fix cache-dependency-path in test workflow 2026-01-16 11:28:45 +01:00
David Blass f34379415e add per-agent smoke tests (#100) 2026-01-16 08:00:16 +00:00
Colin McDonnell 5c60791b34 Update workflow 2026-01-15 23:47:40 +00:00
Colin McDonnell 3fa309853b Fix repo slug 2026-01-14 01:44:30 +00:00
Mateusz Burzyński e839fbeacd Perform repository dispatch using the builtin CLI (#65) 2026-01-13 19:54:57 +00:00
David Blass b3e1cf6de3 Update pullfrog.yml to new template with env-based API keys 2026-01-13 11:29:53 -05:00
Anna Bocharova 0aa97f4fd0 fix(CI): Changing the API keys to uppercase and moving to env (#26)
* fix(CI): Changing the API keys to uppercase

Due to c335032
See diff https://github.com/pullfrog/action/commit/c335032c37b5aa957ee3d9f7d37a937ed3ece150#diff-35ec9ad6938f4a0788911257499ca3ccf99c80cca56a22e86706f2c17f636835

* fix: Moving the keys to env
2026-01-13 12:22:35 +01:00
Colin McDonnell 79344c653d Fix CI 2026-01-12 23:19:35 -08:00
Colin McDonnell 20b4f683e5 Two way sync attempt 2026-01-13 07:13:47 +00:00
Robin Tail c5d201ce60 Add CI workflow for testing. 2026-01-12 15:10:06 +01:00
Colin McDonnell 78c22085bf 0.0.156 2026-01-08 15:05:05 -08:00