fix(P07): concurrency safety — SQLite, flock, cache, atomic writes (REQ-156)

- SQLite busy_timeout(5000) + SetMaxOpenConns(1) on all 4 DSNs
- secrets file flock (concurrent set on same ns no longer loses data)
- upgrade lock file (refuse concurrent orca upgrade)
- backup lock file (refuse concurrent backup)
- cache invalidation by writes (read-after-write consistency)
- Executor.Run mutex scope fix (hold only for DB inserts)
- ns create/inherit/set-constraint atomic writeNSMdAtomic
- writeCurrentLead + rotateSSHKeys atomic
- consolidate 3 writeAtomic impls onto security.WriteAtomic
- WebAuthn session stores guarded with sync.Mutex

Tests: concurrent secrets set, upgrade lock rejection, cache
read-after-write, WebAuthn session thread-safety (pass under -race).

---ci---
project: orca
phase: 7
milestone: v0.13
status: complete
requirements:
  covered: [156]
---/ci---
This commit is contained in:
Jon Chery
2026-08-10 12:27:05 +00:00
parent 978334a4bc
commit 0358efe95b
18 changed files with 932 additions and 68 deletions
+9
View File
@@ -140,6 +140,10 @@ func joinLocal(cmd *cobra.Command) error {
if err := registry.Join(ctx, node); err != nil {
return err
}
// REQ-156 / P07 T5: invalidate the nodes cache so the next
// `orca node list` does not surface a stale list missing the
// just-joined node.
cacheInvalidate(cacheNodeClass)
if jsonOutput {
return printJSON(node)
}
@@ -203,6 +207,8 @@ func joinProxmox(cmd *cobra.Command) error {
if err := registry.Join(regCtx, node); err != nil {
return fmt.Errorf("register proxmox node: %w", err)
}
// REQ-156 / P07 T5: invalidate the nodes cache.
cacheInvalidate(cacheNodeClass)
if jsonOutput {
return printJSON(node)
}
@@ -236,6 +242,9 @@ var nodeLeaveCmd = &cobra.Command{
if err := registry.Leave(ctx, id); err != nil {
return err
}
// REQ-156 / P07 T5: invalidate the nodes cache so the next
// `orca node list` does not surface the just-left node.
cacheInvalidate(cacheNodeClass)
if jsonOutput {
return printJSON(map[string]string{"id": id, "state": "left"})
}