fix(dashmate): load ZeroSSL config in force mode - #4298
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe ZeroSSL task pipeline now initializes API configuration, external IP, certificate paths, and SSL directory state before certificate generation. Forced regeneration clears stale state and proceeds with fresh keypair, CSR, and certificate generation. Unit tests cover successful and invalid forced runs. ChangesZeroSSL certificate acquisition
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
⛔ Blockers found — Sonnet deferred (commit e910329) |
✅ Action performedReviews resumed. |
|
The failing CodeRabbit or PastaClaw review check is unrelated to this PR's code changes. The gate ran when the PR opened, before either reviewer had submitted a formal GitHub review, and its log explicitly says it will rerun automatically when a review is submitted. CodeRabbit has since completed its analysis, and the PastaClaw review is queued separately. The ZeroSSL change is proper as-is; no branch change, rebase, empty commit, or CI retrigger is needed for this failure. |
thepastaclaw
left a comment
There was a problem hiding this comment.
Preliminary review — Codex only
The PR fixes force mode's missing ZeroSSL configuration and path initialization, but the new regeneration path can persist a replacement certificate ID while leaving the previous certificate's key and CSR on disk. If renewal is interrupted and later retried without force, the pipeline can install a certificate bundle that does not match the retained private key.
Source: reviewers codex/general=gpt-5.6-sol(completed); verifier=codex/verifier=gpt-5.6-sol(completed); coordinator=openclaw-agent/cliproxy/gpt-5.6-sol(orchestration-only).
Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.
Review provenance
- Codex reviewers:
gpt-5.6-sol— general (completed) - Verifier:
gpt-5.6-sol— verifier - Opus: not run (deferred by blocker gate)
🔴 1 blocking
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/dashmate/src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js`:
- [BLOCKING] packages/dashmate/src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js:75-81: Keep forced renewal artifacts consistent with the persisted certificate ID
Force mode clears only the in-memory presence flags; the previous `private.key`, `csr.pem`, and `bundle.crt` remain on disk. After generating a replacement key and CSR, the create task persists the new certificate ID at lines 180-185 before verification, download, or any artifact save occurs. If a later task fails, a subsequent non-force run loads that new pending certificate while `validateZeroSslCertificate` reports the old key and CSR as present; its pending-certificate branch clears only the bundle flag. Key/CSR generation and save are therefore skipped, while the new bundle is downloaded and written beside the old private key, producing a certificate/key mismatch. Stage the replacement ID, key, CSR, and bundle and commit them together after successful download, or roll back the persisted ID on failure so a retry cannot associate the old artifacts with the replacement certificate. Add a regression test covering a force run that fails after certificate creation followed by a non-force retry.
Note: GitHub does not allow me to request changes on my own PR, so this COMMENT review preserves the verified blocking finding and should still be treated as merge-blocking feedback.
--force previously skipped the only task that loaded externalIp/apiKey/paths, so generateCsr crashed with node-forge "Attribute value not specified". Always initialize config/paths, and only skip the existing-valid-certificate short-circuit under --force (mirroring Let's Encrypt). Clear presence flags so keypair/CSR/certificate regenerate. Fixes dashpay#3803 Fixes dashpay#4249 Co-Authored-By: Claude <noreply@anthropic.com>
91431c2 to
e910329
Compare
|
Addressed the blocking forced-renewal consistency finding in
Validation: targeted unit spec (8 passing), changed-file ESLint, and |
There was a problem hiding this comment.
Preliminary review — Codex only
The carried-forward blocker, "Keep forced renewal artifacts consistent with the persisted certificate ID," is resolved: the current head delays publishing the replacement ID until the artifacts are ready and rolls back artifacts and configuration when persistence fails. The latest delta introduces a new blocking security regression because the staged replacement private key is installed with the process-default file mode rather than preserving owner-only access.
Source: reviewers codex/general=gpt-5.6-sol(completed); verifier=codex/verifier=gpt-5.6-sol(completed); coordinator=openclaw-agent/cliproxy/gpt-5.6-sol(orchestration-only).
Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.
Review provenance
- Codex reviewers:
gpt-5.6-sol— general (completed) - Verifier:
gpt-5.6-sol— verifier - Sonnet: not run (deferred by blocker gate)
🔴 1 blocking
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/dashmate/src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js`:
- [BLOCKING] packages/dashmate/src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js:338-357: Preserve restrictive permissions when installing the replacement private key
The staged private key is created with Node's default mode (`0666` masked by the process umask), and `renameSync` replaces the destination inode instead of overwriting it. A forced renewal therefore changes an existing owner-only `0600` key to `0644` under the usual `0022` umask. Dashmate also creates its default and nested home directories without an explicitly restrictive mode, so on typical installations other local users can traverse the path and read the gateway TLS private key. Create the staged `private.key` with mode `0600` or explicitly chmod it before or after installation, while leaving the CSR and certificate bundle modes unchanged, and add a regression assertion for the installed key mode.
Note: GitHub does not allow me to request changes on my own PR, so this COMMENT review preserves the verified blocking finding and should still be treated as merge-blocking feedback.
| stagedArtifacts = artifacts.map(({ filePath, content }) => { | ||
| const stagedFilePath = path.join(stagingDir, path.basename(filePath)); | ||
| const wasPresent = fs.existsSync(filePath); | ||
| const previousContent = wasPresent | ||
| ? fs.readFileSync(filePath, 'utf8') | ||
| : undefined; | ||
|
|
||
| fs.writeFileSync(stagedFilePath, content, 'utf8'); | ||
|
|
||
| return { | ||
| stagedFilePath, | ||
| filePath, | ||
| wasPresent, | ||
| previousContent, | ||
| }; | ||
| }); | ||
|
|
||
| artifactInstallStarted = true; | ||
| stagedArtifacts.forEach(({ stagedFilePath, filePath }) => { | ||
| fs.renameSync(stagedFilePath, filePath); |
There was a problem hiding this comment.
🔴 Blocking: Preserve restrictive permissions when installing the replacement private key
The staged private key is created with Node's default mode (0666 masked by the process umask), and renameSync replaces the destination inode instead of overwriting it. A forced renewal therefore changes an existing owner-only 0600 key to 0644 under the usual 0022 umask. Dashmate also creates its default and nested home directories without an explicitly restrictive mode, so on typical installations other local users can traverse the path and read the gateway TLS private key. Create the staged private.key with mode 0600 or explicitly chmod it before or after installation, while leaving the CSR and certificate bundle modes unchanged, and add a regression assertion for the installed key mode.
source: ['codex']
Issue being fixed or feature implemented
Fixes #3803
Fixes #4249
Tracking: https://github.com/thepastaclaw/tracker/issues/1419
dashmate ssl obtain --forceskipped the ZeroSSL validation task that also initialized the task context. As a result, required values such as the API key, external IP, and certificate paths were undefined before key and CSR generation.What was done?
--forcelimited to bypassing existing-certificate validation and resetting prior certificate/artifact state so a fresh keypair, CSR, certificate, and bundle are generated.How Has This Been Tested?
yarn exec mocha --require ./test/bootstrap.js test/unit/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.spec.js test/unit/ssl/zerossl/validateZeroSslCertificateFactory.spec.js— 16 passingyarn exec eslint src/listr/tasks/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.js test/unit/ssl/zerossl/obtainZeroSSLCertificateTaskFactory.spec.jsyarn workspace dashmate lintvia the pre-commit hookBreaking Changes
None.
Checklist:
For repository code-owners and collaborators only
Summary by CodeRabbit