You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dashmate is incorrectly generating the rpcauth credentials on first restart #2497
Triage on current master (507192c, v4.x) — this still reproduces, and the
mechanism is an ordering one rather than anything wrong with the credential
generation.
The rendering itself is correct.templates/core/dash.conf.dot:39-41
generates a fresh random salt per render and HMACs the password with it, so a
rendered rpcauth always verifies against the password it was rendered from.
I checked this without Docker by driving the real template through the real renderTemplateFactory code path (script below):
a render of password X authenticates X and rejects the old password
two renders of the same password produce different hashes — expected,
the salt is crypto.randomBytes(16) each time
So the "different hash on the second restart" in the report is by design, not a
symptom. Worth ruling out before anyone goes looking in the template.
The actual problem is when rendering happens.writeConfigTemplates — the
thing that regenerates dash.conf — is only called from src/oclif/command/BaseCommand.js:190-196, inside the command's finally
teardown, and only when configFile.isChanged().
restart is stopNodeTask → startNodeTask
(src/listr/tasks/restartNodeTaskFactory.js:22-31); neither renders, and ConfigBaseCommand adds no render step either. So containers are always started
from whatever dash.conf is already on disk, and any re-render happens
strictly afterwards. A config change therefore cannot affect the containers
started by the same invocation — it lands on the next start. That is the
"two restarts" symptom.
There is a second path worth separating out. Nothing in stop/start calls config.set(), and Config.changed is only set there
(src/config/Config.js:222). A config freshly read from disk reports isChanged() === false (asserted in the script). So if the password was changed
by hand-editing config.json rather than via dashmate config set, the
render is skipped entirely and no number of restarts fixes it — dashmate config render is the only thing that syncs it.
That distinction matters for what the fix should be, and I can't tell from the
report which path was taken. @ktechmidas — do you remember whether you edited config.json directly, or used dashmate config set?
Unchanged since the report. I diffed BaseCommand.js at 7b569ab
(2025-03-14, the day this was filed) against master: the render was in async finally() then and is in teardown now. #4248 reworked the locking around
it but not the ordering.
Shape of a fix, for whoever picks this up — the choice is a design call, not
obvious to me:
Render service configs at the start of any command that brings containers
up, rather than in teardown. Most correct, touches the most.
Have startNodeTask render before dockerCompose.up. Narrower, leaves other
commands with the same latent gap.
Detect on load that config.json is newer than the rendered dash.conf and
re-render (also fixes the hand-edit path).
Repro script (no Docker needed) — drop in packages/dashmate/ and run node repro-2497.mjs. It uses the real base config and real template:
✓ the template renders a valid rpcauth for the password it is given
✓ two renders of the SAME password produce DIFFERENT hashes (random salt)
✓ an old-password render does NOT authenticate the new password
✓ a freshly loaded config is NOT marked changed; only set() marks it
4/4 passed
I have not been able to run dashmate end-to-end (no Docker in my environment),
so the container-level behaviour is inferred from the call graph rather than
observed. Everything above the "shape of a fix" section is verified against the
code; the two-restart sequence specifically is not.
Activity
bezibalazs commentedon Aug 28, 2026
Triage on current
master(507192c, v4.x) — this still reproduces, and themechanism is an ordering one rather than anything wrong with the credential
generation.
The rendering itself is correct.
templates/core/dash.conf.dot:39-41generates a fresh random salt per render and HMACs the password with it, so a
rendered
rpcauthalways verifies against the password it was rendered from.I checked this without Docker by driving the real template through the real
renderTemplateFactorycode path (script below):the salt is
crypto.randomBytes(16)each timeSo the "different hash on the second restart" in the report is by design, not a
symptom. Worth ruling out before anyone goes looking in the template.
The actual problem is when rendering happens.
writeConfigTemplates— thething that regenerates
dash.conf— is only called fromsrc/oclif/command/BaseCommand.js:190-196, inside the command'sfinallyteardown, and only when
configFile.isChanged().restartisstopNodeTask→startNodeTask(
src/listr/tasks/restartNodeTaskFactory.js:22-31); neither renders, andConfigBaseCommandadds no render step either. So containers are always startedfrom whatever
dash.confis already on disk, and any re-render happensstrictly afterwards. A config change therefore cannot affect the containers
started by the same invocation — it lands on the next start. That is the
"two restarts" symptom.
There is a second path worth separating out. Nothing in stop/start calls
config.set(), andConfig.changedis only set there(
src/config/Config.js:222). A config freshly read from disk reportsisChanged() === false(asserted in the script). So if the password was changedby hand-editing
config.jsonrather than viadashmate config set, therender is skipped entirely and no number of restarts fixes it —
dashmate config renderis the only thing that syncs it.That distinction matters for what the fix should be, and I can't tell from the
report which path was taken. @ktechmidas — do you remember whether you edited
config.jsondirectly, or useddashmate config set?Unchanged since the report. I diffed
BaseCommand.jsat 7b569ab(2025-03-14, the day this was filed) against master: the render was in
async finally()then and is in teardown now. #4248 reworked the locking aroundit but not the ordering.
Shape of a fix, for whoever picks this up — the choice is a design call, not
obvious to me:
up, rather than in teardown. Most correct, touches the most.
startNodeTaskrender beforedockerCompose.up. Narrower, leaves othercommands with the same latent gap.
config.jsonis newer than the rendereddash.confandre-render (also fixes the hand-edit path).
Repro script (no Docker needed) — drop in
packages/dashmate/and runnode repro-2497.mjs. It uses the real base config and real template:I have not been able to run dashmate end-to-end (no Docker in my environment),
so the container-level behaviour is inferred from the call graph rather than
observed. Everything above the "shape of a fix" section is verified against the
code; the two-restart sequence specifically is not.