fix(dashmate): load ZeroSSL config in force mode - #4298
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 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.
|
|
✅ Final review complete — no blockers (commit 41dc4bf) |
✅ 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.
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.
thepastaclaw
left a comment
There was a problem hiding this comment.
Preliminary review — Codex only
The force-mode configuration initialization now works, and the prior private-key permission issue is fixed by staging the key with mode 0600. One blocker remains: replacing certificate files with renameSync disconnects successful renewals from the gateway's existing file-level bind mounts, so its SIGHUP hot restart continues serving the old certificate.
Source: reviewer codex/general=gpt-5.6-sol; final verifier codex/verifier=gpt-5.6-sol; orchestration-only and not reviewer evidence: openclaw-agent/cliproxy/gpt-5.6-sol.
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 - 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:358-361: Preserve bind-mounted certificate inodes during renewal
The gateway mounts bundle.crt and private.key as individual files in docker-compose.yml lines 208-209. Replacing either destination with renameSync creates a new inode on the host, while the running container's bind mount remains attached to the old inode. The renewal scheduler then sends SIGHUP to PID 1, whose hot-restart supervisor forks another Envoy process in the same mount namespace, so that process also reads the old certificate. Normal expiration renewal replaces bundle.crt, and force mode replaces both mounted files; either path can publish the new certificate ID and report success while the gateway continues serving the expiring certificate. Overwrite existing destinations in place to preserve their mounted inodes, and use renameSync only for first-time installation.
Canonical verifier result: REQUEST_CHANGES. GitHub does not allow authors to approve or request changes on their own pull requests, so this review was submitted using COMMENT transport. The findings and blocker status above are unchanged.
dashmate ssl obtain --force skipped the ZeroSSL validation task that also initialized the task context, leaving the API key, external IP, and certificate paths undefined before key and CSR generation (dashpay#3803, dashpay#4249). Initialize configuration and paths unconditionally and keep --force limited to bypassing the existing-certificate check. Replacement artifacts are staged first and installed transactionally: the new certificate ID is only published after key, CSR, and bundle succeed, with rollback of artifacts and config if persistence fails. The private key is staged with owner-only permissions, and existing destinations are overwritten in place so the gateway container's single-file bind mounts (which stay attached to the mounted inode) pick up renewals on SIGHUP; renameSync is used only for first-time installation.
9955519 to
41dc4bf
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Final validation — Codex/Sol only (Phase 2 disabled)
At exact head 41dc4bf, the prior bind-mount blocker is fixed: existing certificate artifacts are overwritten in place, while first-time installations still use rename, and regression coverage confirms the behavior. The targeted ZeroSSL suites pass with 21 tests, and ESLint passes for both changed files.
Source: reviewers codex/general=gpt-5.6-sol and codex/security-auditor=gpt-5.6-sol; final verifier codex/verifier=gpt-5.6-sol; openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.
Validated zero-blocker Codex/Sol precheck evidence was promoted to final because Phase 2 (Sonnet/Opus) is temporarily disabled. This is Codex/Sol-only final validation, not Codex + Sonnet/Opus coverage.
Review provenance
- Codex reviewers:
gpt-5.6-sol— general (completed),gpt-5.6-sol— security-auditor (completed) - Verifier:
gpt-5.6-sol— verifier - Sonnet/Opus: not run (Phase 2 disabled — temporary Codex/Sol-only final)
- Secondary pass: disabled (
temporary_phase2_sonnet_disable)
Canonical verifier result: APPROVE. GitHub does not allow authors to approve or request changes on their own pull requests, so this review was submitted using COMMENT transport. The findings and blocker status above are unchanged.
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