feat(data-warehouse): implement skyvern import source - #70043
Conversation
|
Hey @Gilbert09! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
|
Reviews (1): Last reviewed commit: "feat(data-warehouse): implement skyvern ..." | Re-trigger Greptile |
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
estefaniarabadan
left a comment
There was a problem hiding this comment.
Isolated new data-warehouse source scaffold — self-contained under its own source directory with only the expected shared-registry additions (SOURCES.md, generated_configs.py, icon), tests included, CI green. Reviewed as part of a batch. LGTM 👍
Fill in the scaffolded Skyvern data warehouse source end-to-end: workflows, runs (incremental via per-workflow created_at fan-out), schedules, browser profiles, and credential metadata. Adds transport, endpoint settings, canonical descriptions, and source-class + transport tests. Kept behind unreleasedSource with releaseStatus=alpha. Generated-By: PostHog Code Task-Id: e9f63ce3-69e1-4a46-a24a-9478933e4b3f
…ting and SSRF - Add connection_host_fields=["base_url"] so editing the destination host requires re-entering the API key, preventing exfiltration of the preserved secret to an attacker-controlled host. - Pin allow_redirects=False on the tracked sessions used for credential validation and row fetching, as an SSRF boundary for the user-supplied base_url. - Page through all runs on a full refresh so a workflow with more than the per-workflow page cap is not permanently truncated; the cap now only guards runaway on incremental syncs. - Fix mypy errors in the test files. Generated-By: PostHog Code Task-Id: bfe33e80-ec80-46c6-8517-36baab701988
c4d7db7 to
fa31fa6
Compare
🤖 CI report
|
| File | Patch | Uncovered changed lines |
|---|---|---|
products/warehouse_sources/backend/temporal/data_imports/sources/skyvern/skyvern.py |
81.8% | 62–69, 86, 112–113, 115–116, 118–120, 122, 131, 145–146, 167, 174, 194, 225, 252, 258–259, 263 |
products/warehouse_sources/backend/temporal/data_imports/sources/skyvern/source.py |
97.4% | 158 |
🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 29260131859 -n patch-coverage), or the coverage-data block at the end of this comment.
Per-product line coverage (touched products)
| Product | Coverage | Lines |
|---|---|---|
warehouse_sources |
███████████████████░ 96.0% |
205,295 / 213,794 |
Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.
Problem
Skyvern (an open-source AI browser-automation agent with a managed cloud) was scaffolded as a data warehouse source but had no sync logic. Users who run browser-automation tasks and workflows on Skyvern couldn't pull that history into PostHog to analyze run outcomes, failures, and credit spend alongside the rest of their data.
Changes
Fills in the scaffolded
skyvernsource end-to-end. It talks to Skyvern's FastAPI REST surface (https://api.skyvern.com, configurable for self-hosted) with anx-api-keyheader, all through the tracked HTTP transport (make_tracked_session).Five tables:
workflows/v1/agents?only_workflows=trueruns/v1/agents/{workflow_permanent_id}/runscreated_atschedules/v1/schedulesbrowser_profiles/v1/browser_profilescredentials/v1/credentialsArchitecture follows the
source.py/settings.py/skyvern.pysplit. It's aResumableSource: page-number pagination with resume state saved after each yielded page.Key design decisions:
/v1/runsendpoint caps at page 100 (~10k newest runs) and has no timestamp filter, so it can't do complete history or incremental. The per-workflow/v1/agents/{workflow_permanent_id}/runsendpoint acceptscreated_at_start, sorunsenumerates workflows via/v1/agentsand fans out per workflow, bounding each with the incremental watermark. That gives both full history and cheap incremental syncs.workflow_run_idis globally unique, so it's a sufficient primary key.created_at_start/created_at_end. Every other list endpoint is page/page_size with no time filter, so they ship full-refresh only rather than pretending to be incremental.credits_used,finished_at) until terminal, but the only server-side filter is on the immutablecreated_at. A 3-day lookback re-pulls a trailing window each run so merge picks up late status changes for recently-created runs.created_at), never mutable fields.credentialscarries no timestamp, so it has no partition key.sort_mode="desc"because Skyvern list endpoints return newest-first and expose no sort param; in desc mode the pipeline checkpoints the incremental watermark at successful job end, which is correct for the fan-out.Note
I could not curl the live API (no Skyvern key in this environment), so endpoint behavior is verified against the published OpenAPI 3 spec rather than live responses. The main uncertainty is that
{workflow_id}in the runs path is documented as a bare string with no description; I pass the stableworkflow_permanent_idsince that's the identifier runs are grouped by. This is noted in a code comment.The source stays behind
unreleasedSource=TruewithreleaseStatus=alpha.Not included
frontend/public/services/skyvern.svgexists yet and I don't have a Logo.dev key to fetch one legitimately, so no icon was committed (no placeholder, no hardcoded key).iconPathstays as scaffolded. The source is hidden (unreleasedSource) so this doesn't surface to users yet.contents/docs/cdp/sources/skyvern.md(matching thedocsUrl). Draft content, written per the/documenting-warehouse-sourcesskill, is in the collapsed block below.Draft posthog.com doc —
contents/docs/cdp/sources/skyvern.mdHow did you test this code?
Automated tests only (I'm an agent and could not exercise the live Skyvern API):
tests/test_skyvern.py(transport) —created_at_startlookback + future-clamp (guards that incremental doesn't refetch all history and doesn't build a filter that drops every row), bare-array vs wrapped-response extraction (guardsschedulessyncing zero rows), page-number termination + resume checkpoint, the runs fan-out passingcreated_at_startper workflow and resuming from a workflow bookmark, credential status mapping, andSourceResponseshape per endpoint.tests/test_skyvern_source.py(source class) — per-endpoint incremental/append/primary-key capabilities, auth errors being non-retryable, credential plumbing, resumable-manager binding, config field requirements, and that the public-docs table catalog renders from the credential-free placeholder config.All 36 pass. Ran
ruff check/ruff format(clean) andhogli ci:preflight --fix(0 failures).Automatic notifications
🤖 Agent context
Autonomy: Fully autonomous
Authored by Claude (Opus 4.8) via a PostHog Code cloud task. Skills invoked:
/implementing-warehouse-sources(followed for the architecture split, base-class choice, incremental rules, and tracked-transport requirement),/writing-tests(ran the value gate before writing tests), and/documenting-warehouse-sources(shaped the draft doc above).Notable decisions while building:
created_at_start(the basis for incrementalruns) and revealed a global/v1/schedulesendpoint worth syncing, while confirming no other list endpoint has a server-side time filter. Chose full-refresh for those rather than a fake client-side "incremental"./v1/runsfor the runs table but rejected it: it's capped at ~10k newest runs with no time filter, so the per-workflow fan-out is the only path to complete history and incremental.generated_configs.pychange was produced by hand to exactly match the generator's deterministic output for the two fields, then verified the diff was limited to those lines.Created with PostHog Code