refactor(ashby): align tools, block, and triggers with Ashby API#4288
refactor(ashby): align tools, block, and triggers with Ashby API#4288waleedlatif1 merged 9 commits intostagingfrom
Conversation
Audit-driven refactor to destructure rich fields per Ashby's API docs, centralize output shapes via shared mappers in tools/ashby/utils.ts, and align webhook provider handler with trigger IDs via a shared action map. Removes stale block outputs left over from prior flat response shapes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Updates the Ashby block UI and parameter mapping to remove the Improves webhook handling by implementing explicit Ashby signature verification with clearer 401 errors, adding Reviewed by Cursor Bugbot for commit 611a1f7. Configure here. |
Greptile SummaryThis PR is a comprehensive audit-driven refactoring of the Ashby integration that centralizes output shapes and mappers into a new shared All three previously-flagged concerns from the review thread (stale Confidence Score: 5/5Safe to merge — all previously flagged issues are resolved, no new P0/P1 defects found. All three review-thread concerns (stale noteId descriptor, ping-event bypass, missing data key) were fixed in the final commit. The refactoring is well-scoped: the centralized utils.ts eliminates output drift, the trigger action map is a single source of truth, and subblock migrations correctly tombstone the removed filterCandidateId field. Intentional breaking changes (offer latestVersion nesting, tag/application/note output enrichment) are documented and accepted. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Inbound Ashby Webhook] --> B[verifyAuth\nHMAC sha256 validation]
B -->|Invalid signature| C[401 Unauthorized]
B -->|Valid| D[matchEvent]
D -->|action == 'ping'| E[return false\nSkip execution]
D -->|no triggerId| F[return true\nAllow all]
D -->|triggerId present| G[isAshbyEventMatch\nASHBY_TRIGGER_ACTION_MAP lookup]
G -->|mismatch| H[return false\nSkip execution]
G -->|match| I[formatInput\nspread data + keep data key]
I --> J[Workflow Execution\ninput.application.* ✓\ninput.data.application.* ✓]
subgraph Tools
K[get_candidate / list_candidates / search_candidates\ncreate_candidate / update_candidate\nadd_candidate_tag / remove_candidate_tag] --> L[mapCandidate + CANDIDATE_OUTPUTS]
M[get_application / list_applications\ncreate_application / change_application_stage] --> N[mapApplication + APPLICATION_OUTPUTS]
O[get_offer / list_offers] --> P[mapOffer + OFFER_OUTPUTS]
Q[get_job / list_jobs] --> R[mapJob + JOB_OUTPUTS]
end
subgraph SharedUtils["tools/ashby/utils.ts"]
L
N
P
R
end
Reviews (3): Last reviewed commit: "fix(ashby): preserve input.data path in ..." | Re-trigger Greptile |
- Remove stale `noteId` output descriptor from block (create_note now returns `id` at the top level via the shared note mapper). - Explicitly reject `ping` events in the webhook matchEvent before falling back to the generic triggerId check, so webhook records missing triggerId cannot execute workflows on Ashby ping probes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Optional ID params in create_application, change_application_stage, and update_candidate were passed through to the request body without .trim(), unlike their required ID siblings. Normalize to prevent copy-paste whitespace errors. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add SUBBLOCK_ID_MIGRATIONS entry so deployed workflows that previously used the `filterCandidateId` subBlock on `list_applications` don't break after the field was removed (Ashby's application.list doesn't filter by candidateId). Also regenerate docs to sync noteId removal. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
- create_candidate: email is optional per Ashby docs (only name is required); tool, types, and block all made non-required. - list_applications: guard NaN when createdAfter can't be parsed so we don't send a bad value to Ashby's API. - webhook provider: replace createHmacVerifier with explicit fail-closed verifyAuth that 401s when secretToken, signature header, or signature match is missing (was previously fail-open on missing secret). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Restore the explicit `data` key alongside the spread so deployed workflows that reference `input.data.application.*`, `input.data.candidate.*`, etc. keep working. The spread alone dropped those paths. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 611a1f7. Configure here.
Keep formatInput aligned with the advertised trigger outputs schema (flat top-level entities) and drop the legacy input.data.* compat path. Every field declared in each trigger's outputs is now populated 1:1 by the data spread plus the explicit action key — no undeclared keys. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add .trim() on sourceId (create_candidate), jobId (list_applications), applicationId and interviewStageId (list_interviews) to match the trim-on-IDs pattern used across the rest of the Ashby tools and guard against copy-paste whitespace. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
tools/ashby/utils.tsvia mappers +*_OUTPUTSconstants, eliminating drift between tools and block outputs.ASHBY_TRIGGER_ACTION_MAPsource of truth, and filters Ashby's ping events inmatchEvent.Notable changes
tools/ashby/utils.ts(new) — shared mappers (mapCandidate,mapJob,mapApplication,mapOffer,mapOpenings, etc.) and output constants.tools/ashby/*— 28 tool files refactored to use shared mappers; ID fields.trim()-ed; body keys aligned with Ashby API (idfor get_candidate/get_job, single-stringstatusfor list_applications).blocks/blocks/ashby.ts— advanced-mode switches added (syncToken,includeArchived,expandApplicationFormDefinition,expandSurveyFormDefinitions); stale top-level outputs removed.lib/webhooks/providers/ashby.ts—matchEventadded to filter ping events; uses sharedASHBY_TRIGGER_ACTION_MAP.triggers/ashby/utils.ts—ASHBY_TRIGGER_ACTION_MAP+isAshbyEventMatchhelper;candidateHireoutputs expanded with accepted offer details.Breaking (intentional, API-accurate)
add_candidate_tag/remove_candidate_tagreturn full candidate (was{ success: true }).create_application/change_application_stagereturn full application (was{ applicationId, stageId? }).create_notereturns full note (was{ noteId }).get_offer/list_offersneststartDate,salary,openingId,createdAtunderlatestVersionper Ashby's response shape.Test plan
bun run type-checkpasses