Search/Change a Self-Hosted Certificate Automation Monorepo While Keeping Secrets Out of It

Change a Self-Hosted Certificate Automation Monorepo While Keeping Secrets Out of It

Use when an AI changes a self-hosted tool that requests, renews, and deploys certificates via ACME. It keeps changes in the right package or plugin, writes tests first, adds SQL migrations, uses existing UI patterns, and keeps certificates and keys out of code and logs.

To use this AI rule
## Understand the Certificate Lifecycle and the Secrets the System Stores Treat the system as a private, self-hosted product that manages certificate application, renewal, deployment, monitoring, notification, and API integration. Its core pipeline may request certificates through ACME, complete DNS-01, HTTP-01, CNAME proxy, or provider-specific validation, export formats such as PEM, PFX, DER, JKS, and P7B, and deploy to servers, proxies, clusters, CDNs, cloud services, or control panels. The system stores certificates, cloud credentials, SSH details, API keys, and other sensitive configuration. Never expose local data or secrets in source changes, logs, fixtures, screenshots, reports, or generated metadata. ## Keep Monorepo Workspaces Separate and Leave Runtime Data Untouched Use the repository's designated package manager, workspace definition, and lockfile; do not introduce lockfiles from another package manager. If a package is an independent version-control workspace, inspect its status and diff from inside that workspace and keep its changes separate from the root repository. Do not modify or commit runtime data, logs, temporary output, generated metadata, distributions, or exported plugin manifests unless the task explicitly targets them. A runtime dependency directory may be inspected read-only when a dynamically installed SDK must be understood, but it is not source and must not enter the change set. ## Put Each Change in the Package or Plugin That Owns It Identify ownership before editing: protocol clients own account, order, and challenge behavior; pipeline packages own execution models and task lifecycles; server modules own entities, services, controllers, permissions, and migrations; client modules own views, forms, routes, and API adapters; provider plugins own provider-specific DNS, deployment, and notification behavior. Keep a single-provider defect in that provider's plugin. Move behavior into pipeline core or a shared plugin library only when it expresses reusable semantics required consistently across providers. Prefer established modules, services, components, and plugin patterns over parallel implementations. ## Use Each Package's Own Commands Without Installing Extra Dependencies Read the documented commands before running validation. Use the affected package's own unit-test, lint, formatting, and build commands, and expand to broader checks only when the change clearly crosses package boundaries. Do not substitute a known-broken type check or a placeholder test script for supported file-scoped validation. Do not install dependencies proactively. If missing dependencies, terminal requirements, or network access prevent a required check, stop that attempt and report the environmental limitation. For version-sensitive SDK behavior, inspect the exact installed runtime dependency and its bundled documentation instead of relying on memory or another version. ## Write Readable Code with Named Steps and Comments That Explain Why Favor readability over compact syntax. Break complex conditions, nested ternaries, long chains, inline objects, and multi-layer helper calls into clearly named intermediate values or focused methods. Do not place one method call directly inside another method's argument when a meaningful local variable can expose the transition. Use object parameters when a method would otherwise need more than three arguments. Explain business rules, compatibility constraints, protocol details, and hidden risks with comments that state why the decision exists. Keep small logic local, but extract recurring business rules, field conversions, permission checks, repository selection, transaction propagation, or calculations when copies must remain synchronized. ## Write a Failing Test First, Then Make the Smallest Fix Add focused unit tests for primary business behavior. For a new feature or defect correction, prefer a failing test that reproduces the expected behavior before implementation, then make the smallest change and rerun the package-level test. If a later test would require changing established behavior, confirm that the behavior is a defect rather than an existing requirement before altering it. Place pure unit tests near the source and keep them out of production builds. Use an appropriate module-mocking tool for static ESM imports instead of restructuring production code solely for the test. Set the package's unit-test environment explicitly, and run broader builds only when cross-package impact makes them necessary. ## Add SQL Migrations for Table Changes and Pass Transactions Correctly Pair every table-structure change with an explicit SQL migration; never rely on ORM schema synchronization. Promote temporary upload keys through the approved file service before storing them permanently, and preserve the required owner and public-or-private visibility. For transaction propagation, pass a context containing the optional transaction manager before a request object, and use the shared repository and transaction helpers. Do not add transaction context to simple queries or pure functions. Build optional tenant or project predicates with the canonical query helper so null or undefined values cannot become an invalid equality condition. Avoid service method names and signatures that collide with inherited base methods. Choose specific names that preserve the base contract and make the operation's scope explicit. ## Build Admin Screens with the Existing CRUD Framework and Form Dialogs Locate the owning feature view and its API module before editing. Use the approved CRUD framework for routine administration, record search, and table-based management. Build a custom list only for lightweight read-only presentation, strongly interactive interfaces, or a documented mismatch with the standard framework. Embedded data grids require a stable height or an unbroken flex chain with shrinkable children. Reuse established remote dictionaries for searchable identity fields. A simple confirmation may use a confirmation dialog, but any dialog that collects fields, validates input, or submits additional values must use the approved form-dialog abstraction. Run only the supported formatter and linter against the changed client files when the repository's broader type check or unit command is known to be invalid. ## Fix Certificate Problems in the Right Layer and Protect Account Keys Inspect provider plugins before changing shared pipeline code, and inspect the actual dynamically installed SDK when provider behavior depends on its version. Determine whether a certificate issue belongs to the ACME client, pipeline execution, a server service, a provider plugin, a shared certificate utility, or the client form before applying a fix. Use a lookup-only account operation with the existing account private key when the protocol client supports retrieving an existing account URL without consuming new external-account-binding material. If an external-account-binding identifier changes, generate a new account private key bound to that identifier; otherwise block issuance and require the account key to be refreshed. Keep credential values out of code, logs, tests, reports, and committed artifacts. Preserve validation and authorization boundaries when extending upload, deployment, notification, or open-API flows. ## Keep Old Settings Working and Report Which Checks Ran When adding a plugin parameter, handle its absence in stored legacy configurations and preserve the prior behavior unless a migration explicitly changes it. Do not reinterpret missing values as a new mode without a defined compatibility branch. Before completion, inspect the focused diff, verify the root and any nested workspace separately, run the directly affected tests and file-level formatting or lint checks, and confirm required migrations. Ensure runtime data and generated outputs remain outside the change set. Report what changed, which checks passed, which checks could not run, and why broader validation was out of scope.