Watch
1
0
Fork
You've already forked RedFlag
0

fix: tracker save failures tee inward; drop restorecon stderr suppression (ETHOS #1)

Delivery-tracker persistence failures (ack/receipt/confirmed Save) were
local-only log lines; a tracker that cannot persist risks double-delivery
or replay-rejection after a crash, so they now tee to the server event
buffer via TeeLogger. The untagged 'Command rejected' line gains ETHOS
tags. install.sh restorecon calls lose their 2>/dev/null — SELinux
relabel failures now print a tagged warning instead of vanishing.
This commit is contained in:
Fimeg 2026-06-11 08:10:04 -04:00
commit f6bb28e9cd
2 changed files with 19 additions and 9 deletions

View file

@ -60,7 +60,7 @@ install_binary() {
# Set SELinux context for binary if SELinux is enabled
if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" != "Disabled" ]; then
echo "SELinux detected, setting file context for binary..."
restorecon -v "$AGENT_BINARY" 2>/dev/null || true
restorecon -v "$AGENT_BINARY" || echo "[WARNING] [installer] [selinux] restorecon_failed path=$AGENT_BINARY — continuing"
echo "✓ SELinux context set for binary"
fi
}
@ -177,7 +177,7 @@ register_agent() {
# Set SELinux context for config directory if SELinux is enabled
if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" != "Disabled" ]; then
echo "Setting SELinux context for config directory..."
restorecon -Rv /etc/aggregator 2>/dev/null || true
restorecon -Rv /etc/aggregator || echo "[WARNING] [installer] [selinux] restorecon_failed path=/etc/aggregator — continuing"
echo "✓ SELinux context set for config directory"
fi

View file

@ -449,7 +449,7 @@ func RunPollingLoop(loopCtx *LoopContext) error {
ctx.AckTracker.Acknowledge(response.AcknowledgedIDs)
log.Printf("[INFO] [agent] [acknowledgment] results_acknowledged count=%d", len(response.AcknowledgedIDs))
if err := ctx.AckTracker.Save(); err != nil {
log.Printf("[ERROR] [agent] [acknowledgment] save_failed error=%v", err)
teeTrackerSaveFailure(ctx, "acknowledgment", "save_failed", err)
}
}
@ -458,7 +458,7 @@ func RunPollingLoop(loopCtx *LoopContext) error {
ctx.ReceiptTracker.Confirm(response.ReceiptConfirmedIDs)
log.Printf("[INFO] [agent] [receipt] receipts_confirmed count=%d", len(response.ReceiptConfirmedIDs))
if err := ctx.ReceiptTracker.Save(); err != nil {
log.Printf("[ERROR] [agent] [receipt] save_failed error=%v", err)
teeTrackerSaveFailure(ctx, "receipt", "save_failed", err)
}
}
@ -484,7 +484,7 @@ func RunPollingLoop(loopCtx *LoopContext) error {
})
}
if err := ctx.AckTracker.Save(); err != nil {
log.Printf("[ERROR] [agent] [acknowledgment] save_failed error=%v", err)
teeTrackerSaveFailure(ctx, "acknowledgment", "save_failed", err)
}
}
if dropped := ctx.ReceiptTracker.Cleanup(); len(dropped) > 0 {
@ -500,7 +500,7 @@ func RunPollingLoop(loopCtx *LoopContext) error {
})
}
if err := ctx.ReceiptTracker.Save(); err != nil {
log.Printf("[ERROR] [agent] [receipt] save_failed error=%v", err)
teeTrackerSaveFailure(ctx, "receipt", "save_failed", err)
}
}
@ -516,7 +516,7 @@ func RunPollingLoop(loopCtx *LoopContext) error {
ctx.ConfirmedTracker.Confirm(response.ConfirmedCommandIDs)
log.Printf("[INFO] [agent] [confirmed] completions_confirmed count=%d", len(response.ConfirmedCommandIDs))
if err := ctx.ConfirmedTracker.Save(); err != nil {
log.Printf("[ERROR] [agent] [confirmed] save_failed error=%v", err)
teeTrackerSaveFailure(ctx, "confirmed", "save_failed", err)
}
}
@ -537,7 +537,7 @@ func RunPollingLoop(loopCtx *LoopContext) error {
ctx.ReceiptTracker.Add(cmd.ID)
}
if err := ctx.ReceiptTracker.Save(); err != nil {
log.Printf("[ERROR] [agent] [receipt] save_after_receive_failed error=%v", err)
teeTrackerSaveFailure(ctx, "receipt", "save_after_receive_failed", err)
}
processCommands(ctx, response.Commands)
}
@ -782,7 +782,7 @@ func processCommands(ctx *LoopContext, commands []client.Command) {
// Verify command signature
if err := ctx.CommandHandler.ProcessCommand(cmd, ctx.Cfg, ctx.Cfg.AgentID); err != nil {
log.Printf("[ERROR] Command rejected: %s", err)
log.Printf("[ERROR] [agent] [commands] command_rejected error=%v", err)
logReport := client.LogReport{
CommandID: cmd.ID,
Action: "verify_command",
@ -862,6 +862,16 @@ func applyServerPolling(cfg *config.Config, resp *client.AgentConfigResponse) bo
return changed
}
// teeTrackerSaveFailure journals a delivery-tracker persistence failure inward
// (ETHOS #1). A tracker that cannot persist risks double-delivery or
// replay-rejection after a crash — the server needs the record, not just the
// local journal. TeeLogger both logs and buffers a SystemEvent.
func teeTrackerSaveFailure(ctx *LoopContext, component, action string, err error) {
ctx.TeeLogger.Error("agent", component, "tracker",
fmt.Sprintf("%s error=%v", action, err),
map[string]interface{}{"action": action, "error": err.Error()})
}
// failureClass partitions polling failures by how they recover (BUG-014).
type failureClass int