R-35 (D4): dashboard sign-ins survive the controller's own restart; disk holds only a fingerprint

Sessions are keyed by sha256(cookie) and persisted to dashboard-sessions.json
(0600, tmp+fsync+rename) in the data dir: fingerprint, expiry, CSRF token.
Loaded in NewServer; expired rows dropped at load and save. Logout and
invalidateAllSessions (password change, claim reset) write the file at once.
Corrupt/unreadable file = start with no sessions (never fatal).

Red-proof: with load/save as no-ops the restart test fails ('the old cookie
no longer signs in'); with the raw token as the key the file test fails
('the sessions file holds the cookie value').

Also: TestR650_NoBareDockerExec skips a non-.go file that vanished mid-walk
(a parallel stacks test's update-journal.json.tmp raced it in a full run).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-08 14:32:20 +02:00
parent fcd9f09927
commit 1040cfe225
5 changed files with 362 additions and 4 deletions
@@ -75,6 +75,12 @@ func TestR650_NoBareDockerExec(t *testing.T) {
n := 0
err := filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
if err != nil {
// Another package's test, running in parallel, may create and rename a scratch file (for example
// internal/stacks/update-journal.json.tmp) between the directory read and the lstat. A file that vanished
// is not a Go source file; skip it. Seen 2026-10-08 in a full `go test ./...`.
if os.IsNotExist(err) && !strings.HasSuffix(p, ".go") {
return nil
}
return err
}
if info.IsDir() || !strings.HasSuffix(p, ".go") || strings.HasSuffix(p, "_test.go") {