Expected Behavior
dashmate ssl obtain --force should obtain a new ZeroSSL certificate, bypassing the "certificate already exists and is not expiring soon" early exit.
Current Behavior
On the ZeroSSL provider (the default), --force cannot complete. It should fail during "Create a certificate" with an undefined API key; if it got past that, "Save certificate private key file" would call fs.writeFileSync(undefined, …).
The first task in the pipeline, "Check if certificate already exists and not expiring soon", is declared skip: (ctx) => ctx.force — and it is the only place that merges the validator's data into the Listr context:
packages/dashmate/src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js — the skip predicate on the first task, and the single lodash.merge(ctx, data) inside it.
packages/dashmate/src/ssl/zerossl/validateZeroSslCertificateFactory.js — where that data originates: sslConfigDir, apiKey, externalIp, certificate, csrFilePath, privateKeyFilePath, bundleFilePath, and the isXxxFilePresent flags.
packages/dashmate/src/commands/ssl/obtain.js — seeds the context with only { noRetry, force, expirationDays }.
So under --force, every one of those values is undefined for the remainder of the pipeline.
The intent of --force appears to be "get a new certificate regardless of the existing one" — which still needs the API key and the resolved file paths. Skipping the whole task discards the context setup along with the early exit.
Possible Solution
Separate context population from the early-exit decision. Either:
- drop the
skip and make only the "certificate is still valid, stop here" branch conditional on ctx.force, so the merge always runs; or
- move the
lodash.merge(ctx, data) into a preceding task that never skips.
Steps to Reproduce
- Configure a node with the ZeroSSL provider and a valid API key.
- Run
dashmate ssl obtain --force.
- Observe the failure. Expected failure point is certificate creation with an undefined API key.
Context
Found by code inspection while fixing unrelated TLS private-key permission issues in the same files (see the private-key permission changes on feat/dashmate/update). Not reproduced end to end — doing so needs a real ZeroSSL API key and an externally reachable IP, which was not available. The exact failure point (API rejection vs. writeFileSync(undefined, …)) is therefore inferred from the code path rather than observed; the context-seeding, the skip predicate and the single merge site are all directly verifiable in the source.
The self-signed and Let's Encrypt providers do not share this path.
Your Environment
- Version used: dashmate 4.1.0 (
v4.1-dev, code path unchanged on feat/dashmate/update)
- Link to your project: Dash Platform
Expected Behavior
dashmate ssl obtain --forceshould obtain a new ZeroSSL certificate, bypassing the "certificate already exists and is not expiring soon" early exit.Current Behavior
On the ZeroSSL provider (the default),
--forcecannot complete. It should fail during "Create a certificate" with an undefined API key; if it got past that, "Save certificate private key file" would callfs.writeFileSync(undefined, …).The first task in the pipeline, "Check if certificate already exists and not expiring soon", is declared
skip: (ctx) => ctx.force— and it is the only place that merges the validator's data into the Listr context:packages/dashmate/src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js— theskippredicate on the first task, and the singlelodash.merge(ctx, data)inside it.packages/dashmate/src/ssl/zerossl/validateZeroSslCertificateFactory.js— where thatdataoriginates:sslConfigDir,apiKey,externalIp,certificate,csrFilePath,privateKeyFilePath,bundleFilePath, and theisXxxFilePresentflags.packages/dashmate/src/commands/ssl/obtain.js— seeds the context with only{ noRetry, force, expirationDays }.So under
--force, every one of those values isundefinedfor the remainder of the pipeline.The intent of
--forceappears to be "get a new certificate regardless of the existing one" — which still needs the API key and the resolved file paths. Skipping the whole task discards the context setup along with the early exit.Possible Solution
Separate context population from the early-exit decision. Either:
skipand make only the "certificate is still valid, stop here" branch conditional onctx.force, so the merge always runs; orlodash.merge(ctx, data)into a preceding task that never skips.Steps to Reproduce
dashmate ssl obtain --force.Context
Found by code inspection while fixing unrelated TLS private-key permission issues in the same files (see the private-key permission changes on
feat/dashmate/update). Not reproduced end to end — doing so needs a real ZeroSSL API key and an externally reachable IP, which was not available. The exact failure point (API rejection vs.writeFileSync(undefined, …)) is therefore inferred from the code path rather than observed; the context-seeding, theskippredicate and the single merge site are all directly verifiable in the source.The self-signed and Let's Encrypt providers do not share this path.
Your Environment
v4.1-dev, code path unchanged onfeat/dashmate/update)