pbsdr: escrow seed writes in place (config dir is root-owned; tmp+rename impossible for the non-root agent — demo live finding); recovery copy parked in the state dir

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-10 21:59:51 +02:00
parent e5e8f3920a
commit 3d1323cc09
+18 -4
View File
@@ -407,12 +407,26 @@ func (m *Manager) seedEscrowStorageID(storageID string) error {
if err != nil {
return err
}
tmp := m.configPath + ".pbsdr-tmp"
if err := os.WriteFile(tmp, out, st.Mode().Perm()); err != nil {
// The config DIRECTORY (/etc/felhom-agent) is root-owned while the FILE is agent-owned —
// tmp+rename is impossible for the non-root agent (rename mutates the directory; live
// finding on the demo). So: park a recovery copy in the agent state dir, then rewrite the
// file IN PLACE (O_TRUNC). The agent is the file's only writer and the content is small;
// a torn write is recoverable from the parked copy.
if err := os.MkdirAll(m.stateDir, 0o700); err != nil {
return err
}
if err := os.Rename(tmp, m.configPath); err != nil {
os.Remove(tmp)
if err := os.WriteFile(filepath.Join(m.stateDir, "agent.json.pre-seed"), raw, 0o600); err != nil {
return fmt.Errorf("parking the pre-seed copy: %w", err)
}
f, err := os.OpenFile(m.configPath, os.O_WRONLY|os.O_TRUNC, st.Mode().Perm())
if err != nil {
return err
}
if _, err := f.Write(out); err != nil {
f.Close()
return err
}
if err := f.Close(); err != nil {
return err
}
m.logger.Info("pbsdr: seeded escrow.pbs_storage_id (the ceremony one-liner needs no flags)", "storage_id", storageID)