Skip to content

Fix certificate rotation policy correlation - #365

Open
maperu wants to merge 1 commit into
masterfrom
agent/fix-correlated-rotation-policy
Open

Fix certificate rotation policy correlation#365
maperu wants to merge 1 commit into
masterfrom
agent/fix-correlated-rotation-policy

Conversation

@maperu

@maperu maperu commented Aug 13, 2026

Copy link
Copy Markdown

Summary

  • correlate the in_rotation_window SQL expression with each certificate's assigned rotation policy
  • eliminate the implicit cross join against every row in rotation_policies
  • add a regression test covering certificates assigned to different rotation windows

Root cause and impact

In #362 the hybrid SQL expression referenced RotationPolicy.days without joining it through Certificate.rotation_policy_id. A certificate therefore qualified when its expiry matched any rotation policy, effectively applying the largest configured window to the entire rotation-enabled fleet.

The expression now uses the rotation_policy relationship, producing a correlated EXISTS condition. Certificates with no assigned policy remain ineligible, and unrelated policies can no longer affect them.

Validation

  • flake8 lemur/certificates/models.py lemur/tests/test_certificates.py
  • git diff --check
  • compiled the query with the PostgreSQL dialect and confirmed it contains rotation_policies.id = certificates.rotation_policy_id with no top-level cross join
  • added a PostgreSQL-backed regression test proving a 70-day policy cannot select a certificate assigned to a 30-day policy

The focused test is collected successfully, but could not execute locally because PostgreSQL is not running on localhost:5432; CI will execute it against the project test database.

@maperu
maperu marked this pull request as ready for review August 13, 2026 20:58
@maperu
maperu requested review from a team as code owners August 13, 2026 20:58
@maperu

maperu commented Aug 13, 2026

Copy link
Copy Markdown
Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91089f3979

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +392 to 394
return cls.rotation_policy.has(
extract("day", cls.not_after - func.now()) <= RotationPolicy.days
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Backfill legacy NULL rotation policies before filtering them out

When a rotation-enabled certificate predates 484764d or was imported without a policy, its rotation_policy_id may still be NULL: the column remains nullable, and the automatically_enable_autorotate_* commands in lemur/certificates/cli.py only set rotation=True. This has() predicate is always false for those rows, whereas the previous expression selected them using an available policy, so get_all_pending_reissue() silently stops renewing these certificates and they can expire. Add a data backfill or an explicit default-policy fallback before requiring the relationship.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

the backfill has already run and commercial currently has zero active or rotation-enabled certs with a NULL policy. New certs also receive the default policy.

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.

2 participants