Skip to content

fix(certificates): allow deletion of expired and unused certificates#873

Merged
Wikid82 merged 43 commits intodevelopmentfrom
feature/beta-release
Mar 24, 2026
Merged

fix(certificates): allow deletion of expired and unused certificates#873
Wikid82 merged 43 commits intodevelopmentfrom
feature/beta-release

Conversation

@Wikid82
Copy link
Copy Markdown
Owner

@Wikid82 Wikid82 commented Mar 22, 2026

Summary

Users could not remove expired Let's Encrypt certificates from the Certificates UI, causing clutter over time. Only custom and staging certificates had a visible delete button. The backend DELETE endpoint already supported deleting any certificate not attached to a proxy host, but the frontend artificially restricted which certificates showed the delete action.

Changes

  • Expired certificates not attached to any proxy host are now deletable
  • Custom and staging certificates remain deletable when not in use
  • Certificates attached to a proxy host show a disabled delete button with tooltip explaining why deletion is blocked
  • Valid production Let's Encrypt certificates hide the delete button entirely (auto-managed by Caddy)
  • Replaced the native browser confirm() dialog with an accessible Radix-based confirmation dialog with context-sensitive warnings per certificate type
  • Removed a duplicate client-side backup call that caused two backups per deletion — the server already handles backups with disk space validation
  • Staging detection now uses the canonical provider field instead of fragile issuer string matching

Deletion Policy

Certificate Type Status In Use Deletable?
Custom Any No Yes
Staging Any No Yes
Let's Encrypt Expired No Yes
Let's Encrypt Valid/Expiring No No (auto-managed)
Any Any Yes No (disabled + tooltip)

Testing

  • 8 new Playwright E2E tests across Chromium, Firefox, and WebKit (1867 total passed)
  • 2 new backend handler-level gap tests confirming no provider-based deletion restrictions
  • 10 new frontend unit tests (isDeletable, isInUse, dialog behavior)
  • Backend coverage: 88.0% | Frontend coverage: 89.33%
  • All security scans pass (Trivy, Docker image, GORM)
  • Manual test plan created at docs/issues/certificate-delete-manual-test.md

QA Report

Full audit report at docs/reports/qa_report_cert_delete_ux.md

renovate bot and others added 9 commits March 21, 2026 16:17
…n-major-updates

fix(deps): update non-major-updates (feature/beta-release)
…n-major-updates

fix(deps): update dependency i18next to ^25.10.3 (feature/beta-release)
…or certificate deletion

- Implement DeleteCertificateDialog component to handle certificate deletion confirmation.
- Add tests for DeleteCertificateDialog covering various scenarios including rendering, confirmation, and cancellation.
- Update translation files for multiple languages to include new strings related to certificate deletion.
- Create end-to-end tests for certificate deletion UX, including button visibility, confirmation dialog, and success/failure scenarios.
@Wikid82 Wikid82 changed the title feat(certificates): allow deletion of expired and unused certificates fix(certificates): allow deletion of expired and unused certificates Mar 22, 2026
@github-advanced-security
Copy link
Copy Markdown
Contributor

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 22, 2026

✅ Supply Chain Verification Results

PASSED

📦 SBOM Summary

  • Components: 1483

🔍 Vulnerability Scan

Severity Count
🔴 Critical 0
🟠 High 0
🟡 Medium 4
🟢 Low 2
Total 6

📎 Artifacts

  • SBOM (CycloneDX JSON) and Grype results available in workflow artifacts

Generated by Supply Chain Verification workflow • View Details

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 22, 2026

Codecov Report

❌ Patch coverage is 92.50000% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
frontend/src/components/CertificateList.tsx 93.68% 6 Missing ⚠️
...components/dialogs/BulkDeleteCertificateDialog.tsx 85.71% 2 Missing ⚠️
...src/components/dialogs/DeleteCertificateDialog.tsx 90.90% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Wikid82 and others added 3 commits March 22, 2026 12:00
…n-major-updates

fix(deps): update non-major-updates (feature/beta-release)
- Install gotestsum in CI so the coverage script uses compact
  pkgname-formatted output instead of go test -v, which produces
  massive verbose logs that exceed GitHub Actions' step log buffer
- Upload the full test output as a downloadable artifact on every
  run (including failures) so truncated logs never block debugging
- Aligns upload-artifact pin to v7.0.0 matching the rest of the repo
@Wikid82 Wikid82 marked this pull request as ready for review March 22, 2026 19:01
Copilot AI review requested due to automatic review settings March 22, 2026 19:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Certificates UI/UX to align frontend deletion controls with existing backend behavior, enabling cleanup of expired/orphaned certificates while preventing deletion of certificates currently attached to proxy hosts. It also replaces the native confirm() prompt with an accessible dialog and adds test coverage across E2E, frontend unit tests, and backend handler tests.

Changes:

  • Expand certificate deletion eligibility in the frontend (expired LE + unused custom/staging) and add an accessible confirmation dialog + tooltip messaging.
  • Add E2E + unit tests for deletion policy and dialog behavior; add backend handler tests confirming deletion isn’t provider-restricted.
  • Update docs/changelog and adjust CI workflows to upload backend test output artifacts; bump a few tooling/deps.

Reviewed changes

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

Show a summary per file
File Description
tests/certificate-delete.spec.ts New Playwright E2E coverage for certificate deletion UX and policy.
package.json Bump markdownlint-cli2 version.
package-lock.json Lockfile updates for markdownlint-cli2 and related deps.
frontend/src/locales/en/translation.json Add i18n strings for delete flow + update note text.
frontend/src/locales/de/translation.json Add delete-flow i18n keys (placeholders).
frontend/src/locales/es/translation.json Add delete-flow i18n keys (placeholders).
frontend/src/locales/fr/translation.json Add delete-flow i18n keys (placeholders).
frontend/src/locales/zh/translation.json Add delete-flow i18n keys (placeholders).
frontend/src/components/dialogs/DeleteCertificateDialog.tsx New Radix-based confirmation dialog for certificate deletion.
frontend/src/components/dialogs/tests/DeleteCertificateDialog.test.tsx Unit tests for dialog warning text + confirm/cancel behavior.
frontend/src/components/CertificateList.tsx Implement deletion policy helpers, integrate dialog, add tooltip for disabled delete state, remove duplicate client backup call.
frontend/src/components/tests/CertificateList.test.tsx Update tests for deletability/in-use logic and dialog-driven deletion flow.
frontend/package.json Bump a few frontend dependencies (react-query, i18next, react-hook-form, react-i18next, vitest eslint plugin).
frontend/package-lock.json Lockfile updates for frontend dependency bumps.
docs/reports/qa_report_cert_delete_ux.md Add QA report documenting testing and security checks for this feature.
docs/plans/current_spec.md Replace “current spec” content with certificate deletion feature spec.
docs/issues/certificate-delete-manual-test.md Add manual test plan for edge cases/race conditions.
docs/features/ssl-certificates.md Document manual certificate deletion policy in user docs.
backend/internal/models/ssl_certificate.go Fix provider comment to match actual provider values.
backend/internal/api/tests/user_smtp_audit_test.go Improve in-memory SQLite stability (MaxOpenConns/cleanup) and migrate SecurityAudit.
backend/internal/api/handlers/certificate_handler_test.go Add handler-level tests confirming LE cert deletion works when not in use.
CHANGELOG.md Document the new certificate deletion UX capability.
.github/workflows/quality-checks.yml Install gotestsum + upload backend test output artifact.
.github/workflows/codecov-upload.yml Install gotestsum + upload backend test output artifact in Codecov workflow.
.docker/compose/docker-compose.playwright-local.yml Increase tmpfs size for backups during E2E runs.
Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

renovate bot and others added 3 commits March 22, 2026 20:26
…n-major-updates

fix(deps): update non-major-updates (feature/beta-release)
…deletion

- Implemented BulkDeleteCertificateDialog with confirmation and listing of certificates to be deleted.
- Added translations for bulk delete functionality in English, German, Spanish, French, and Chinese.
- Created unit tests for BulkDeleteCertificateDialog to ensure proper rendering and functionality.
- Developed end-to-end tests for bulk certificate deletion, covering selection, confirmation, and cancellation scenarios.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

- Update isInUse function to handle certificates without an ID.
- Modify isDeletable function to include 'expiring' status as deletable.
- Adjust CertificateList component to reflect changes in deletable logic.
- Update BulkDeleteCertificateDialog and DeleteCertificateDialog to handle expiring certificates.
- Add tests for expiring certificates in CertificateList and BulkDeleteCertificateDialog.
- Update translations for expiring certificates in multiple languages.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 28 changed files in this pull request and generated 12 comments.

Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

actions-user and others added 24 commits March 23, 2026 05:24
…locales

- The certificate section's noteText had previously been translated into
  Chinese, German, Spanish, and French but was inadvertently overwritten
  with an English string when the individual certificate delete feature
  was introduced.
- All four locales now carry properly translated text that also reflects
  the updated policy: expired or expiring production certificates that
  are not attached to a proxy host are now eligible for deletion.
- Newly introduced keys (deleteConfirmExpiring and other delete-related
  keys) remain as English placeholders pending professional translation,
  which is the established pattern for this project.
- Added clarity and structure to README files, including recent updates and getting started sections.
- Improved manual verification documentation for CrowdSec authentication, emphasizing expected outputs and success criteria.
- Updated debugging guide with detailed output examples and automatic trace capture information.
- Refined best practices for E2E tests, focusing on efficient polling, locator strategies, and state management.
- Documented triage report for DNS Provider feature tests, highlighting issues fixed and test results before and after improvements.
- Revised E2E test writing guide to include when to use specific helper functions and patterns for better test reliability.
- Enhanced troubleshooting documentation with clear resolutions for common issues, including timeout and token configuration problems.
- Updated tests README to provide quick links and best practices for writing robust tests.
…ests

Removed local i18n mock to allow global mock to function correctly, updated assertions to use resolved English translations for better consistency in test outcomes.
- Upgraded @tanstack/query-core and @tanstack/react-query from 5.95.0 to 5.95.2
- Updated @typescript-eslint packages from 8.57.1 to 8.57.2
- Bumped @vitest packages from 4.1.0 to 4.1.1
- Updated knip from 6.0.3 to 6.0.4
- Upgraded picomatch from 4.0.3 to 4.0.4 and from 2.3.1 to 2.3.2
- Updated react-router and react-router-dom from 7.13.1 to 7.13.2
- Bumped typescript from 6.0.1-rc to 6.0.2
Renovate could not resolve the Go module path
github.com/oschwald/geoip2-golang/v2 because the /v2 suffix is a Go
module convention, not a separate GitHub repository. Added a packageRules
entry with an explicit sourceUrl pointing to the actual upstream repo so
Renovate can correctly look up available versions.

No changes to application code, go.mod, or go.sum — the dependency was
already declared correctly.
…n-major-updates

fix(deps): update non-major-updates (feature/beta-release)
…jor-1-lucide-monorepo

fix(deps): update dependency lucide-react to v1 (feature/beta-release)
…n-major-updates

fix(deps): update non-major-updates (feature/beta-release)
@Wikid82 Wikid82 merged commit f237fa5 into development Mar 24, 2026
38 checks 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.

3 participants