Skip to content

Batching to avoid acme recursive domain safeguard#8

Merged
mesudip merged 1 commit intomasterfrom
feat/recursive-batching-solution
Apr 18, 2026
Merged

Batching to avoid acme recursive domain safeguard#8
mesudip merged 1 commit intomasterfrom
feat/recursive-batching-solution

Conversation

@mesudip
Copy link
Copy Markdown
Owner

@mesudip mesudip commented Apr 18, 2026

Acme has added a resurcive domain detection in this PR

This pr adds batching support to avoid triggering such detection

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces domain batching functionality to handle ACME certificate issuance more safely, particularly for domains with many labels that might trigger rate limits or safety heuristics. It includes a new domain_batching module, updates to the CLI for custom keystore paths, and enhancements to the API and client to support batched issuance. However, the core batching logic in domain_batching.py contains a critical error where it splits single FQDNs into invalid label fragments rather than grouping full domain strings. Additionally, the CLI lacks a flag to actually trigger this new batching behavior, and there is a minor non-idiomatic type check in the certificate manager.

Comment on lines +72 to +78
labels = [label for label in normalized.split(".") if label]
if len(labels) <= 3:
compact_batch.append(normalized)
continue

for i in range(0, len(labels), 3):
singleton_batches.append([".".join(labels[i : i + 3])])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The logic for handling domains with more than 3 labels is fundamentally incorrect for ACME certificate issuance.

  1. Invalid Hostnames: It splits a single FQDN into label fragments (e.g., a.b.c.d.e.f becomes a.b.c and d.e.f). ACME requires the full FQDN for validation; you cannot obtain a certificate for a fragment of a domain to cover the original FQDN.
  2. Loss of Wildcards: The _normalize_domain function removes *. prefixes. If a user requests a wildcard certificate, this logic will attempt to issue a standard certificate for the base domain instead.
  3. Unused Logic: The function ignores the blocked_labels parameter and the would_trigger logic defined earlier in the file, blindly splitting any domain with more than 3 labels.

If the goal is to isolate potentially 'unsafe' domains to avoid triggering the safeguard for the entire order, you should group the full domain strings into separate batches (singleton batches) rather than splitting the labels of a single domain.

Suggested change
labels = [label for label in normalized.split(".") if label]
if len(labels) <= 3:
compact_batch.append(normalized)
continue
for i in range(0, len(labels), 3):
singleton_batches.append([".".join(labels[i : i + 3])])
labels = _split_labels(domain)
# Preserve the original domain (stripped/lowered) for issuance to keep wildcards
issuance_domain = domain.strip().lower().rstrip(".")
if len(labels) <= 3:
compact_batch.append(issuance_domain)
continue
singleton_batches.append([issuance_domain])

renew_threshold_days: Optional[int] = None,
batch_generator: Optional[Callable[[List[str]], List[List[str]]]] = None,
) -> CertificateResponse:
if type(hosts) == str:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It is recommended to use isinstance(hosts, str) instead of type(hosts) == str. This is more idiomatic in Python and correctly handles potential subclasses of str.

Suggested change
if type(hosts) == str:
if isinstance(hosts, str):

Comment thread src/certapi/cli.py
Comment on lines +271 to +275
obtain_parser.add_argument(
"--path",
default="/etc/ssl",
help="Directory where key/cert files will be written.",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CLI obtain command is missing a flag to enable the new batching functionality. While the API and CertManagerClient were updated to support batch_domains, the CLI still performs a single issuance for all domains because it calls AcmeCertIssuer directly instead of using the AcmeCertManager wrapper. To ensure consistency and make the feature accessible to CLI users, consider adding a --batch argument and updating the implementation to use AcmeCertManager.issue_certificate_in_batches.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 18, 2026

Codecov Report

❌ Patch coverage is 89.41176% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.24%. Comparing base (74eb9d4) to head (e3c97b9).
⚠️ Report is 2 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/certapi/domain_batching.py 94.00% 3 Missing ⚠️
src/certapi/server/api.py 0.00% 3 Missing ⚠️
src/certapi/manager/acme_cert_manager.py 88.23% 2 Missing ⚠️
src/certapi/client/cert_manager_client.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master       #8      +/-   ##
==========================================
+ Coverage   52.29%   55.24%   +2.95%     
==========================================
  Files          41       42       +1     
  Lines        2289     2355      +66     
==========================================
+ Hits         1197     1301     +104     
+ Misses       1092     1054      -38     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mesudip mesudip force-pushed the feat/recursive-batching-solution branch from d669657 to e3c97b9 Compare April 18, 2026 07:26
@mesudip mesudip merged commit ac3ddd6 into master Apr 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant