mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-10 12:47:04 +00:00
fix(sys-dns-cloudflare-records): root the API constant at /zones
The bare https://api.cloudflare.com/client/v4 answers HTTP 404, so test_urls_reachable failed test-external in run 42056917806. Every request of the plugin goes below /zones; the constant now names that path, which answers 403 (alive for the URL test), and the requested URLs stay byte-identical. 🎯 Fix: 95 % 💥 Break: 1 % 💸 Cost: – ⏱️ Time: – 🛡️ Security: 100 % 🏆 Score: 94 🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 % Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
735308266e
commit
d301a4d3c3
2 files changed
+7
-7
No files matched your search
@@ -13,7 +13,7 @@ from ansible.module_utils.urls import ConnectionError as UrlsConnectionError
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
API = "https://api.cloudflare.com/client/v4"
|
||||
ZONES = "https://api.cloudflare.com/client/v4/zones"
|
||||
REVIEWED_COMMUNITY_GENERAL = "14.0.0"
|
||||
PAGE_SIZE = 5000
|
||||
ARGUMENTS = frozenset({"api_token", "records", "timeout"})
|
||||
@@ -40,7 +40,7 @@ READ_FAILURES = (
|
||||
def _get(path: str, token: str, timeout: int) -> dict[str, Any]:
|
||||
"""
|
||||
Args:
|
||||
path: API path below ``API``, query string included.
|
||||
path: API path below ``ZONES``, query string included.
|
||||
token: Cloudflare API token, sent in the bearer header only.
|
||||
timeout: seconds one socket operation may stall.
|
||||
|
||||
@@ -48,7 +48,7 @@ def _get(path: str, token: str, timeout: int) -> dict[str, Any]:
|
||||
The decoded answer; raises ``ValueError`` when Cloudflare reports no success.
|
||||
"""
|
||||
response = open_url(
|
||||
API + path,
|
||||
ZONES + path,
|
||||
method="GET",
|
||||
headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
@@ -59,7 +59,7 @@ def _get(path: str, token: str, timeout: int) -> dict[str, Any]:
|
||||
answer = json.loads(response.read())
|
||||
if not isinstance(answer, dict) or answer.get("success") is not True:
|
||||
errors = answer.get("errors") if isinstance(answer, dict) else answer
|
||||
raise ValueError(f"GET {path} answered without success: {errors}")
|
||||
raise ValueError(f"GET {ZONES + path} answered without success: {errors}")
|
||||
return answer
|
||||
|
||||
|
||||
@@ -74,14 +74,14 @@ def zone_records(zone: str, token: str, timeout: int) -> list[dict[str, Any]]:
|
||||
Every DNS record of the zone, across all pages; raises ``ValueError``
|
||||
unless exactly one zone carries the name.
|
||||
"""
|
||||
zones = _get("/zones?" + urlencode({"name": zone}), token, timeout)["result"]
|
||||
zones = _get("?" + urlencode({"name": zone}), token, timeout)["result"]
|
||||
if len(zones) != 1:
|
||||
raise ValueError(f"{len(zones)} Cloudflare zones match {zone}")
|
||||
records: list[dict[str, Any]] = []
|
||||
page = 1
|
||||
while True:
|
||||
answer = _get(
|
||||
f"/zones/{zones[0]['id']}/dns_records?"
|
||||
f"/{zones[0]['id']}/dns_records?"
|
||||
+ urlencode({"page": page, "per_page": PAGE_SIZE}),
|
||||
token,
|
||||
timeout,
|
||||
|
||||
@@ -296,7 +296,7 @@ class TestCloudflareRecordsConverged(unittest.TestCase):
|
||||
):
|
||||
records = [a("www"), a("api")]
|
||||
error = HTTPError(
|
||||
f"{plugin.API}/zones?name={ZONE}", 429, "Too Many Requests", {}, None
|
||||
f"{plugin.ZONES}?name={ZONE}", 429, "Too Many Requests", {}, None
|
||||
)
|
||||
cloudflare = _FakeCloudflare([[]], error=error)
|
||||
|
||||
|
||||
Reference in new issue
Block a user