8 Commits
Author SHA1 Message Date
Juan DenisandClaude Fable 5 665d6775e4 cutover(cloudflare-ops): the last in-place flagship leaves the tree (plan 52 Phase 2)
builtin-extensions/serverkit-cloudflare-ops + the tracked frontend live
copy removed; FLAGSHIP_SLUGS is now empty (machinery kept);
plugins-manifest.json empties; the bundled registry entry flips to
bundled:false with the local zip's sha256. cloudflare_ops_bridge resolves
the copy-installed package FIRST so a registry install works without the
builtin registration path.

Tests: new conftest.mount_sibling_extension mirrors a real install from
the sibling checkout (the _wp_support.ensure_plugin analogue) and a
cf_extension fixture forces a private app; the zone-settings and round2
suites mount it autouse (74/74 green), the extraction suite pins the
lean-panel shape, and the flagship-era onboarding tests prove the
machinery with a fabricated member instead.

OPERATOR: publish jhd3197/serverkit-cloudflare-ops, sign,
sync-registry-index.sh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 14:51:17 -04:00
Juan DenisandClaude Opus 4.8 8dba586b0e feat(extensions): Phase 5 — extract Cloudflare zone-ops into serverkit-cloudflare-ops
Moves the Cloudflare per-zone control panel (zone settings, cache purge, WAF,
Workers, Tunnels, R2/KV/D1 storage) out of core into the bundled, default-installed
`serverkit-cloudflare-ops` extension (#36). Much cleaner than WordPress:

- Backend: only 2 files move — `api/cloudflare.py` + `cloudflare_service.py` →
  `builtin-extensions/serverkit-cloudflare-ops/backend/` (blueprint keeps
  /api/v1/cloudflare, D9; the one intra-extension import made relative). ZERO core
  callers (the service's only importer was its own blueprint), so no bridge
  accessors are needed for core — `cloudflare_ops_bridge.py` exists only so the
  moved test can reach the service by a dash-safe importlib path.
- No duplicate Cloudflare client (the hard constraint): the moved CloudflareService
  still borrows the single core CloudflareClient via DNSZoneService._resolve_credential.
  The whole DNS layer (dns/cloudflare.py, dns_zone_service, dns_provider_service,
  DNSProviderConfig) and the CloudflareWorker/CloudflareTunnel models (FK into
  dns_provider_configs) STAY core.
- Flagship (default-installed, uninstallable): added to FLAGSHIP_SLUGS — zero nav
  footprint, and the core Domains "Open in Cloudflare" button depends on the route.
- Frontend: a single plain route `cloudflare/zones/:zoneId` contributed via the
  manifest + a re-export shim; the page/panels/api-client/SCSS stay in core
  (Pattern A). Core App.jsx import + route removed.
- Retired the core blueprint registration; the plugin status guard is the gate.

Verified: 80 tests green (new tests/test_cloudflare_extraction.py + the moved
test_cloudflare_zone_settings.py + the 4 DNS-layer tests that stay core and still
exercise the shared client); npm run lint + build clean; the backend serves the
`cloudflare/zones/:zoneId` route contribution from the seeded flagship row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 01:04:03 -04:00
Juan DenisandClaude Opus 4.8 5836294c4d feat(cloudflare): R2 / KV / D1 developer platform (Phase 6)
Add a Storage tab listing and managing Cloudflare's account-scoped storage
primitives — R2 buckets, KV namespaces, and D1 databases. Management only
(list/create/delete); the object/key/row data planes are out of scope.

- CloudflareClient: r2/buckets, storage/kv/namespaces, d1/database list+create
  +delete.
- CloudflareService: combined list_storage (each product fetched independently so
  a missing token scope degrades to a per-product error, not a dead tab),
  validated create/delete for each. R2 bucket names validated S3-style.
- /api/v1/cloudflare/zones/:id/storage* routes (read any user; writes admin).
- StoragePanel (three generic create/list/delete sections; R2 notes its
  S3-compatibility for future backup targeting); api methods; SCSS.

No new tables — wiring an R2 bucket as an S3 backup backend (minting scoped R2
keys) is a deliberate follow-up, noted in the UI.

Tests: aggregate listing + per-product error degradation, R2 name validation,
create/delete, KV/D1 required-field guards (6).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:39:12 -04:00
Juan DenisandClaude Opus 4.8 2f1999018d feat(cloudflare): Cloudflare Tunnels (Phase 5)
Add a Tunnels tab for creating and managing Cloudflare Tunnels (cloudflared) —
exposing a local/private service through Cloudflare's edge with no public IP.
Clearly distinct from ServerKit's WireGuard remote-access tunnels (always
labelled "Cloudflare Tunnel" in the UI). Account-scoped; account resolved from
the zone.

- CloudflareTunnel model: records the connector token (encrypted at rest) and
  owning connection per (account, tunnel_id).
- CloudflareClient: cfd_tunnel create (config_src=cloudflare) / list
  (is_deleted=false) / delete / token / connections / configurations get+put.
- CloudflareService: create (returns + stores the one-time token, yields the
  cloudflared install command), list (managed-flagged), delete, fetch install,
  and public-hostname routing — sets the ingress config (always re-appends the
  required http_status:404 catch-all) and best-effort upserts the proxied CNAME
  hostname→<id>.cfargotunnel.com via the shared ownership-guarded DNS path.
- /api/v1/cloudflare/zones/:id/tunnels* routes (read any user; writes admin).
- TunnelsPanel (create form + one-time install box w/ copy, tunnel list with
  per-tunnel install reveal and public-hostname add/remove); api methods; SCSS.

Tests: list is_deleted param, create config_src, name required, token stored
encrypted + install string, managed-flagging, delete prunes local row, ingress
built with catch-all last (7).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:34:32 -04:00
Juan DenisandClaude Opus 4.8 02774f741e feat(cloudflare): Workers edge hosting (Phase 4)
Add a Workers tab to the Cloudflare Zone Settings page for deploying edge
scripts and managing Worker routes. Workers are account-scoped, so the owning
account is resolved from the zone — the whole feature reuses the existing
Cloudflare DNS connection (no new credential).

- CloudflareWorker model: records the source ServerKit uploaded per (account,
  name) so a worker can be tracked and re-deployed (created via create_all).
- CloudflareClient: zone→account lookup, list/delete scripts, and a stable
  multipart PUT /scripts/{name} module upload (the still-beta resource-oriented
  Workers API is deliberately avoided per the roadmap's fallback note), plus
  zone Worker routes list/add/delete.
- CloudflareService: list (live scripts flagged when ServerKit-managed + routes),
  deploy (validated lowercase name, records source, optional route attach),
  delete, route add/delete.
- /api/v1/cloudflare/zones/:id/workers* routes (read any user; writes admin).
- WorkersPanel component (deploy form with a starter script, worker list, routes
  list); api methods; SCSS.

Tests: multipart upload shape, name validation, deploy records source, list
managed-flagging, delete prunes the local row (5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:27:36 -04:00
Juan DenisandClaude Opus 4.8 5ec5be4b31 feat(cloudflare): WAF custom rules (Phase 3)
Add a WAF tab to the Cloudflare Zone Settings page for managing custom firewall
rules (the http_request_firewall_custom phase entry-point ruleset).

- CloudflareClient: ruleset list/get + phase-entrypoint create (PUT) + per-rule
  POST/PATCH/DELETE.
- CloudflareService: list rules (empty when no custom ruleset yet, distinguished
  from an auth error by listing rulesets first), add rule (creates the ruleset on
  first use), update/delete, and three one-click presets — lock WordPress admin
  to an IP, block common exploit paths, challenge suspicious bots. The IP in the
  lock preset is validated with ipaddress so it can't inject expression syntax;
  rule actions are constrained to a safe terminal subset.
- /api/v1/cloudflare/zones/:id/waf/* routes (list any user; add/preset/update/
  delete admin).
- WafPanel component (preset picker + custom-rule form + active-rules list with
  enable toggle and delete); api methods; SCSS.

Tests: ruleset discovery, empty vs auth-error, create-on-first-rule vs append,
action validation, preset IP validation + safe expression, update/delete (10).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:20:26 -04:00
Juan DenisandClaude Opus 4.8 6bc0ac36e5 feat(cloudflare): cache purge (Phase 2)
Add Cloudflare cache management to the Zone Settings page. Purge everything (with
a confirm) or purge specific URLs (one per line, capped at 30 to match Free/Pro
limits); hosts/prefixes/tags are accepted by the API for Enterprise plans and
their plan errors are surfaced verbatim.

- CloudflareClient.purge_cache(zone_id, payload).
- CloudflareService.purge_cache: validates intent (raises on empty), caps files
  at 30, normalizes the payload.
- POST /api/v1/cloudflare/zones/:id/purge-cache (admin).
- Actions tab gains a "Purge cache" card (purge-everything button + URL list);
  api method; SCSS.

Tests: client payload, purge-everything, 30-file cap, empty-raises, provider
error surfaced (5 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:12:20 -04:00
Juan DenisandClaude Opus 4.8 125b1e4553 feat(cloudflare): zone settings page (Phase 1)
Add a Cloudflare Zone Settings surface on top of the existing Cloudflare DNS
connection — SSL/TLS, Speed, Caching and Security toggles plus a one-click
"recommended hardening" preset. Reuses the connected DNSProviderConfig
credential and shared CloudflareClient, so auth/encryption-at-rest are not
re-implemented.

Backend:
- CloudflareClient: generic v4 request() helper + zone-settings get/update
  (envelope normalized to {success, error?, result?}).
- CloudflareService: resolve zone+credential by ServerKit DNS zone id, curated
  setting groups (UI metadata), get/update setting, apply recommended preset
  with per-setting reporting.
- /api/v1/cloudflare blueprint: settings GET / GET-one / PATCH + apply-preset
  (reads any user, writes admin; mutations captured by the audit fallback).

Frontend:
- CloudflareZoneSettings page (tabbed SSL/TLS · Speed · Caching · Security ·
  Actions) with declarative toggle/select/HSTS controls and optimistic save.
- Route /cloudflare/zones/:zoneId, "Cloudflare" link from Cloudflare-managed
  DNS zones, api module, SCSS.

Tests: client envelope/zone-settings + service resolution guards, indexing,
and preset reporting (11 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:08:38 -04:00