mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-29 08:07:37 +09:00
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>
64 lines
2.7 KiB
Python
64 lines
2.7 KiB
Python
"""Prove the Cloudflare zone-ops extraction (Phase 5, #36; standalone repo
|
|
since the plan 52 Ph2 cutover).
|
|
|
|
Zone-ops (the /api/v1/cloudflare blueprint + CloudflareService) lives in the
|
|
standalone serverkit-cloudflare-ops repo now — no longer a seeded flagship. A
|
|
lean panel boots with no cloudflare routes; the suite mounts the extension
|
|
from the sibling checkout (skip when absent). The DNS layer stays core: the
|
|
moved service borrows the single core CloudflareClient via DNSZoneService.
|
|
"""
|
|
import importlib
|
|
|
|
import pytest
|
|
|
|
from app.models.plugin import InstalledPlugin
|
|
from app.services import cloudflare_ops_bridge
|
|
|
|
SLUG = 'serverkit-cloudflare-ops'
|
|
|
|
|
|
def test_cloudflare_service_left_core():
|
|
"""The zone-ops service is gone from core after extraction."""
|
|
with pytest.raises(ModuleNotFoundError):
|
|
importlib.import_module('app.services.cloudflare_service')
|
|
|
|
|
|
def test_dns_client_stays_core_single_source():
|
|
"""The one Cloudflare API client remains core (no duplicate in the extension)."""
|
|
from app.services.dns import CloudflareClient
|
|
assert CloudflareClient.__module__ == 'app.services.dns.cloudflare'
|
|
|
|
|
|
def test_bridge_resolves_service_from_extension(cf_extension):
|
|
CloudflareService = cloudflare_ops_bridge.cloudflare_service()
|
|
assert CloudflareService.__name__ == 'CloudflareService'
|
|
assert CloudflareService.__module__.startswith(f'app.plugins.{SLUG}')
|
|
# And it does not vendor its own client — it imports the core one lazily.
|
|
import inspect
|
|
src = inspect.getsource(CloudflareService)
|
|
assert 'from app.services.dns import CloudflareClient' in src
|
|
assert 'DNSZoneService._resolve_credential' in src
|
|
|
|
|
|
@pytest.mark.fresh_app
|
|
def test_cloudflare_is_not_seeded_on_a_lean_panel(app):
|
|
"""The flagship era ended with the cutover: a fresh panel has no
|
|
cloudflare-ops row and no zone routes until a registry install."""
|
|
assert InstalledPlugin.query.filter_by(slug=SLUG).first() is None
|
|
rules = {r.rule for r in app.url_map.iter_rules()}
|
|
assert not any(r.startswith('/api/v1/cloudflare/') for r in rules)
|
|
|
|
|
|
def test_cloudflare_blueprint_registered_from_extension(cf_extension, app):
|
|
rules = [r.rule for r in app.url_map.iter_rules()]
|
|
assert any(r.startswith('/api/v1/cloudflare/zones') for r in rules), \
|
|
'Cloudflare zone-ops API should be registered from the extension'
|
|
|
|
|
|
def test_cloudflare_api_reachable_not_404(cf_extension, app, client, auth_headers):
|
|
"""The extension blueprint is live (not 404) and the status guard passes for
|
|
the mounted extension (not 503). It may 400/502 without a real CF zone — we
|
|
only assert the route is wired."""
|
|
resp = client.get('/api/v1/cloudflare/zones/1/settings', headers=auth_headers)
|
|
assert resp.status_code not in (404, 503), resp.status_code
|