turnstile-spin: pivot SKILL to canonical siteverify#73
Merged
thomasgauvin merged 5 commits intoJul 13, 2026
Conversation
added 2 commits
June 17, 2026 16:24
This skill stays as the v1 agent-led path; the dashboard's 'Set up with Spin' button is the v2 parallel path. Two small SKILL.md prose edits so the agent does the right thing when it encounters a v2-created widget: - Recovery flow: dashboard's Deployment column flips on either v1 or v2 marker. If the user is recovering a dashboard-created widget, a Worker is likely already deployed in the account; confirm before redeploying, or skip to Step 10 to wire the frontend against the existing Worker URL. - Telemetry marker: this skill always writes v1, but preserve v2 if you encounter it on an existing widget. Both feed the same account-level activation telemetry. No changes to scripts, references, templates, or tests. Fresh widgets created via this skill keep the turnstile-spin-v1 marker.
Drop the Worker deploy step from the wizard. Spin's job is now widget creation plus a curated agent prompt that wires canonical server-side siteverify into the customer's existing backend. Changes: - SKILL.md rewritten end-to-end (167 -> 211 lines) - worker-deploy.sh deleted - templates/worker/ deleted (14 files) - auth-probe.sh drops Workers Scripts scope check - validate.sh rewritten to dummy-token siteverify + optional hostname check - All 6 framework references rewritten for canonical siteverify - README.md + tests/validation.md updated Pairs with cloudflare/cloudflare-docs and cloudflare/fe/stratus !39261.
5 tasks
juleslemee
pushed a commit
to juleslemee/workers-sdk
that referenced
this pull request
Jul 1, 2026
Adds `wrangler turnstile widget create | list | get | update | delete` so developers and AI coding agents can provision Cloudflare Turnstile widgets from the CLI instead of dashboard-only. Modelled on the hyperdrive command structure (createNamespace + createCommand, single-purpose files per subcommand, cfetch client layer). Requests the existing `challenge-widgets.write` OAuth scope during `wrangler login`; the scope was added to wrangler's prod OAuth client allowlist via cloudflare/iam/terraform-internal-oauth-clients !137 (already applied). Behaviour notes: - `create` prints sitekey + secret + a backend-agnostic siteverify pointer (does not prescribe Workers as the backend). - `update` does GET-then-merge-then-PUT since Turnstile's PUT requires the full body; strips `secret` from output to avoid an incidental leak when the user only intended to rename. - `delete` prompts for confirmation (`--skip-confirmation`/`-y` bypasses); `fallbackValue: false` in non-interactive contexts. - `create`/`list`/`update` accept `--json`; `get` is always JSON. Banner is suppressed with `--json` and in CI so output is pipeable. - `--domain` accepts comma-separated values in addition to repeated flags. - No new Cloudflare TypeScript SDK dependency (matches the hyperdrive pattern in the same repo); the surface can be migrated later. 19 unit tests via msw. Live-verified end to end against the API using both an API token and the OAuth flow with the newly-allowlisted scope. Companion changes (out of scope here): - cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin - cloudflare/cloudflare-docs#31517 - public docs page - stratus !39261 - dashboard Spin Lite dialog Bach and OAuth-client sides: - `challenge-widgets.write` OAuth scope was already registered in bach (derived from the `challenge_widgets_write` api_tokens role); no bach change was needed. - cloudflare/iam/terraform-internal-oauth-clients !137 added `challenge-widgets.write` to the wrangler prod client's scopes list (applied + merged).
juleslemee
pushed a commit
to juleslemee/workers-sdk
that referenced
this pull request
Jul 1, 2026
Adds `wrangler turnstile widget create | list | get | update | delete` so developers and AI coding agents can provision Cloudflare Turnstile widgets from the CLI instead of dashboard-only. Modelled on the hyperdrive command structure (createNamespace + createCommand, single-purpose files per subcommand, cfetch client layer). Requests the existing `challenge-widgets.write` OAuth scope during `wrangler login`; the scope was added to wrangler's prod OAuth client allowlist via cloudflare/iam/terraform-internal-oauth-clients !137 (already applied). Behaviour notes: - `create` prints sitekey + secret + a backend-agnostic siteverify pointer (does not prescribe Workers as the backend). - `update` does GET-then-merge-then-PUT since Turnstile's PUT requires the full body; strips `secret` from output to avoid an incidental leak when the user only intended to rename. - `delete` prompts for confirmation (`--skip-confirmation`/`-y` bypasses); `fallbackValue: false` in non-interactive contexts. - `create`/`list`/`update` accept `--json`; `get` is always JSON. Banner is suppressed with `--json` and in CI so output is pipeable. - `--domain` accepts comma-separated values in addition to repeated flags. - No new Cloudflare TypeScript SDK dependency (matches the hyperdrive pattern in the same repo); the surface can be migrated later. 19 unit tests via msw. Live-verified end to end against the API using both an API token and the OAuth flow with the newly-allowlisted scope. Companion changes (out of scope here): - cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin - cloudflare/cloudflare-docs#31517 - public docs page - stratus !39261 - dashboard Spin Lite dialog Bach and OAuth-client sides: - `challenge-widgets.write` OAuth scope was already registered in bach (derived from the `challenge_widgets_write` api_tokens role); no bach change was needed. - cloudflare/iam/terraform-internal-oauth-clients !137 added `challenge-widgets.write` to the wrangler prod client's scopes list (applied + merged).
juleslemee
pushed a commit
to juleslemee/workers-sdk
that referenced
this pull request
Jul 1, 2026
Adds `wrangler turnstile widget create | list | get | update | delete` so developers and AI coding agents can provision Cloudflare Turnstile widgets from the CLI instead of dashboard-only. Modelled on the hyperdrive command structure (createNamespace + createCommand, single-purpose files per subcommand, cfetch client layer). Requests the existing `challenge-widgets.write` OAuth scope during `wrangler login`; the scope was added to wrangler's prod OAuth client allowlist via cloudflare/iam/terraform-internal-oauth-clients !137 (already applied). Behaviour notes: - `create` prints sitekey + secret + a backend-agnostic siteverify pointer (does not prescribe Workers as the backend). - `update` does GET-then-merge-then-PUT since Turnstile's PUT requires the full body; strips `secret` from output to avoid an incidental leak when the user only intended to rename. - `delete` prompts for confirmation (`--skip-confirmation`/`-y` bypasses); `fallbackValue: false` in non-interactive contexts. - `create`/`list`/`update` accept `--json`; `get` is always JSON. Banner is suppressed with `--json` and in CI so output is pipeable. - `--domain` accepts comma-separated values in addition to repeated flags. - No new Cloudflare TypeScript SDK dependency (matches the hyperdrive pattern in the same repo); the surface can be migrated later. 19 unit tests via msw. Live-verified end to end against the API using both an API token and the OAuth flow with the newly-allowlisted scope. Companion changes (out of scope here): - cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin - cloudflare/cloudflare-docs#31517 - public docs page - stratus !39261 - dashboard Spin Lite dialog Bach and OAuth-client sides: - `challenge-widgets.write` OAuth scope was already registered in bach (derived from the `challenge_widgets_write` api_tokens role); no bach change was needed. - cloudflare/iam/terraform-internal-oauth-clients !137 added `challenge-widgets.write` to the wrangler prod client's scopes list (applied + merged).
juleslemee
pushed a commit
to juleslemee/workers-sdk
that referenced
this pull request
Jul 2, 2026
Adds `wrangler turnstile widget create | list | get | update | delete` so developers and AI coding agents can provision Cloudflare Turnstile widgets from the CLI instead of dashboard-only. Modelled on the hyperdrive command structure (createNamespace + createCommand, single-purpose files per subcommand, cfetch client layer). Requests the existing `challenge-widgets.write` OAuth scope during `wrangler login`; the scope was added to wrangler's prod OAuth client allowlist via cloudflare/iam/terraform-internal-oauth-clients !137 (already applied). Behaviour notes: - `create` prints sitekey + secret + a backend-agnostic siteverify pointer (does not prescribe Workers as the backend). - `update` does GET-then-merge-then-PUT since Turnstile's PUT requires the full body; strips `secret` from output to avoid an incidental leak when the user only intended to rename. - `delete` prompts for confirmation (`--skip-confirmation`/`-y` bypasses); `fallbackValue: false` in non-interactive contexts. - `create`/`list`/`update` accept `--json`; `get` is always JSON. Banner is suppressed with `--json` and in CI so output is pipeable. - `--domain` accepts comma-separated values in addition to repeated flags. - No new Cloudflare TypeScript SDK dependency (matches the hyperdrive pattern in the same repo); the surface can be migrated later. 19 unit tests via msw. Live-verified end to end against the API using both an API token and the OAuth flow with the newly-allowlisted scope. Companion changes (out of scope here): - cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin - cloudflare/cloudflare-docs#31517 - public docs page - stratus !39261 - dashboard Spin Lite dialog Bach and OAuth-client sides: - `challenge-widgets.write` OAuth scope was already registered in bach (derived from the `challenge_widgets_write` api_tokens role); no bach change was needed. - cloudflare/iam/terraform-internal-oauth-clients !137 added `challenge-widgets.write` to the wrangler prod client's scopes list (applied + merged).
added 2 commits
July 9, 2026 11:48
Wrangler 4.109 ships an alpha 'turnstile widget create/list/get/update/ delete' subcommand tree that talks to the same Cloudflare API as the bundled widget-create.sh helper. When wrangler is installed with the turnstile subcommand available, use it directly; otherwise fall back to the curl-based script. Also updates Step 2 (CLI check) to name the preference explicitly. Server-side, dashboard-created widgets tag deployed_via=dashboard, wrangler-created widgets tag deployed_via=wrangler, and curl-script widgets tag deployed_via=api. The agent only needs to write the turnstile-spin-v2 marker; the deployment channel is inferred from the User-Agent/host on the create call.
nayaknandkishor216-source
approved these changes
Jul 10, 2026
…ompat # Conflicts: # skills/turnstile-spin/SKILL.md
marinaelmore
approved these changes
Jul 13, 2026
thomasgauvin
approved these changes
Jul 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Spin skill pivots from "deploy a managed siteverify Worker" to "wire canonical server-side siteverify in the customer's existing backend." This matches the design review on the V2 stratus MR (the deployed Worker reintroduces every problem it claimed to solve: URL-as-credential, CORS=* on the proxy, custom auth model on top of a system that already has one). Spin's job is now widget creation plus a curated agent prompt that points at
https://challenges.cloudflare.com/turnstile/v0/siteverifydirectly.What changes
SKILL.md is rewritten end-to-end. The 13-step wizard becomes a 12-step wizard: Step 9 (Worker deploy) collapses into the new Step 9 (wire widget + canonical siteverify in existing backend). The "things you must NOT do" list adds "do not deploy any extra infrastructure"; the recovery flow drops worker deploy and just fetches the secret to wire siteverify against the existing widget.
scripts/:
worker-deploy.sh— deleted. No Worker to deploy.auth-probe.sh— drops theAccount.Workers Scripts:Editprobe. OnlyAccount.Turnstile:Editis required now.validate.sh— rewritten. Drops the Worker/healthand_workermetadata checks. Runs a dummy-token siteverify directly againstchallenges.cloudflare.comusing the captured secret. Hostname check is now optional (skipped whenCLOUDFLARE_API_TOKENisn't set, so the dashboard-success-card flow can validate without manually creating a token).widget-create.sh,fetch-secret.sh,persist-skill.sh— unchanged.templates/worker/ — deleted in full (14 files, ~1,500 lines). No Worker template anymore.
references/ — all six framework references (vanilla-html, nextjs-app, nextjs-pages, astro, sveltekit, hugo) rewritten. Frontend snippet stays (widget embed via
cf-turnstilediv); backend snippet switches from "POST to YOUR_WORKER_URL" to canonical siteverify inside the customer's existing handler. Each reference now includes platform-specific siteverify patterns (Server Actions, Astro Actions, SvelteKit form actions, Pages Functions for static-site backends).tests/validation.md — rewritten. Drops Worker URL probes; tests dummy-token siteverify + widget-domains check.
README.md — file-layout table updated; dropped the
cloudflare/turnstile-siteverifyreference (the managed Worker repo Spin used to deploy from).What does not change
turnstile-spin-v2(set on everycf-turnstilediv the skill writes). Older widgets stampedturnstile-spin-v1from the legacy V1 agent flow stay tagged; the skill explicitly tells the agent to preserve that marker if encountered.fetch-secret.sh). Unchanged..claude/skills/,.cursor/rules/, etc. so the agent can re-load it on follow-up tasks).What is intentionally not yet in this MR
Two forward-direction tracks are scoped but not landed:
wrangler turnstilesubcommands — would replace the agent's manual API-token setup withwrangler login's OAuth token. Needs Workers SDK team buy-in. SKILL.md will get a wrangler branch in Step 2 once shipped.env.TURNSTILE.verifybinding — would replace the canonical fetch idiom inside a Worker backend with a typed call. Needs Workers Runtime team RFC. SKILL.md will get a Workers-backend variant in Step 9 once shipped.Both are absent from this MR by design: the docs should not reference features that don't exist yet.
Related MRs
cloudflare/cloudflare-docs#31517— pairs with this change; rewrites the user-facingdevelopers.cloudflare.com/turnstile/spinpage.cloudflare/fe/stratus!39261— pivots the V2 dashboard dialog to consume this skill.Diff stats
30 files changed, +431 / -2,192. Net −1,761 lines.
Verification
references/*.mdandtests/validation.mdre-read end-to-end; no remaining mentions of "Worker URL", "deploy", or "worker-deploy.sh".scripts/*.shfor correct shell escaping.