Skip to content

feat(celery): CA-extensible check_dcv_expiration task (RDNA-1000)#335

Open
evan-datadog wants to merge 3 commits into
masterfrom
evan/RDNA-1000/dcv-expiry-celery-task
Open

feat(celery): CA-extensible check_dcv_expiration task (RDNA-1000)#335
evan-datadog wants to merge 3 commits into
masterfrom
evan/RDNA-1000/dcv-expiry-celery-task

Conversation

@evan-datadog

@evan-datadog evan-datadog commented Jul 10, 2026

Copy link
Copy Markdown

Summary

Daily check_dcv_expiration Celery task discovers CA plugins implementing
get_dcv_expiration_data() and emits lemur.dcv.days_until_expiration.
DigiCert is the first implementation.

Metric Type Tags
lemur.dcv.days_until_expiration gauge domain, ca, validation_type, org_id
  • IssuerPlugin base: optional get_dcv_expiration_data() hook (default: [])
  • DigiCert plugin: first implementation via GET /v2/domain (paginated)
  • Config: DIGICERT_DCV_CHECK_ENABLED (default True)

Other CAs add DCV monitoring by overriding get_dcv_expiration_data() — no
changes to the Celery task required.

Note: Celery beat schedule entry must be added to k8s-resources
chart/config/lemur.conf.py separately.

Comment thread lemur/common/celery.py Outdated
).replace(tzinfo=None)
days_remaining = (expiry_dt - now).days
metrics.send(
"lemur.dcv.days_until_expiration",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

the metrics provider already namespaces everything under lemur., all the existing sends are bare (e.g. certificates.days_until_expiration shows up as lemur.certificates.days_until_expiration in DD). so these will land as lemur.lemur.dcv.*. mind dropping the lemur. prefix on the three sends so they match the rest of the codebase?

Comment thread lemur/plugins/lemur_digicert/plugin.py
Comment thread lemur/plugins/lemur_digicert/plugin.py Outdated
while True:
response = self.session.get(
f"{base_url}/services/v2/domain",
params={"limit": page_size, "offset": (page - 1) * page_size},

@maperu maperu Jul 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: I don't think we'll ever need pagination at our scale, we can remove this for simplicity

@evan-datadog evan-datadog force-pushed the evan/RDNA-1000/dcv-expiry-celery-task branch from c4eb51c to 8b7f400 Compare July 13, 2026 14:54
@evan-datadog evan-datadog requested a review from Copilot July 13, 2026 15:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a CA-extensible daily Celery task to report Domain Control Validation (DCV) expiration timelines via metrics, with DigiCert as the first CA plugin implementation.

Changes:

  • Introduces check_dcv_expiration Celery task that queries issuer plugins for DCV expiration data and emits lemur.dcv.days_until_expiration.
  • Extends IssuerPlugin with an optional get_dcv_expiration_data() hook (default []) and implements it for DigiCert using /services/v2/domain pagination.
  • Adds configuration flag DIGICERT_DCV_CHECK_ENABLED and unit tests covering the new task + DigiCert implementation.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
local/src/lemur.conf.py Documents beat schedule entry (commented) and adds DIGICERT_DCV_CHECK_ENABLED default.
lemur/common/celery.py Adds check_dcv_expiration task emitting DCV expiration metrics and summary metrics.
lemur/plugins/bases/issuer.py Adds optional get_dcv_expiration_data() hook to issuer plugin base.
lemur/plugins/lemur_digicert/plugin.py Implements DigiCert DCV expiration discovery via /v2/domain pagination.
lemur/tests/test_dcv_celery.py Adds tests for base hook behavior and Celery task metric emission/error isolation.
lemur/plugins/lemur_digicert/tests/test_digicert.py Adds tests for DigiCert get_dcv_expiration_data() behavior and config disable flag.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lemur/common/celery.py Outdated
Comment on lines +1179 to +1188
now = datetime.now(timezone.utc).replace(tzinfo=None)
for entry in dcv_data:
try:
dcv_expiration = entry.get("dcv_expiration")
if not dcv_expiration:
continue
expiry_dt = datetime.fromisoformat(
dcv_expiration.replace("Z", "+00:00")
).replace(tzinfo=None)
days_remaining = (expiry_dt - now).days
Daily check_dcv_expiration Celery task discovers CA plugins implementing
get_dcv_expiration_data() and emits lemur.dcv.days_until_expiration.
DigiCert is the first implementation via GET /services/v2/domain (paginated).

Live validation against the DigiCert API corrected three field mismatches:
- is_active (boolean) filters inactive domains, not a status string
- dcv_expiration is {"ev": ..., "ov": ...} per validation type, not a scalar
- validation is a plural optional array; emit one row per dcv_expiration key

| Metric                          | Type  | Tags                                    |
|---------------------------------|-------|-----------------------------------------|
| lemur.dcv.days_until_expiration | gauge | domain, ca, validation_type, org_id    |

Config: DIGICERT_DCV_CHECK_ENABLED (default True)
Note: Celery beat schedule entry must be added to k8s-resources separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Workspace: local
@evan-datadog evan-datadog force-pushed the evan/RDNA-1000/dcv-expiry-celery-task branch from 8b7f400 to 0e750dd Compare July 13, 2026 15:25
…DNA-1000)

Single /v2/domain call is sufficient at our domain count.

Workspace: local
@evan-datadog

Copy link
Copy Markdown
Author

🤖 Addressed all three review items:

  1. Metric prefix — already correct: emitting `dcv.days_until_expiration` (the metrics provider namespaces under `lemur.` automatically). This was fixed in an earlier commit.

  2. Pagination removed — latest commit replaces the `while True` loop with a single `/v2/domain` call. No pagination params needed at our domain count.

  3. `/v2/domain` API shape — parsing matches the real response shape (`domain.get("dcv_expiration")` returns a dict of `{validation_type: expiry_date}`), as confirmed in the earlier reply.

Ready for re-review, @maperu.

@evan-datadog evan-datadog requested a review from maperu July 13, 2026 19:56
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.

3 participants