mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 10:35:51 +00:00
Normalize bounded APT agent clock skew
This commit is contained in:
@@ -39,10 +39,19 @@ func hostAPTExecutionResult(resourceID, agentID, operation, output string, succe
|
||||
verificationTruth.ReasonCode = "stale_agent_readback"
|
||||
verificationTruth.Summary = "The agent readback was stale, skewed, or had invalid mutation chronology."
|
||||
} else {
|
||||
evidenceObservedAt := afterObservedAt.UTC()
|
||||
evidenceReceivedAt := receivedAt.UTC()
|
||||
// Validation permits the agent clock to be slightly ahead of the
|
||||
// server. Canonical evidence cannot claim an observation after its
|
||||
// receipt, so conservatively bind bounded positive skew to the
|
||||
// server receipt boundary.
|
||||
if evidenceObservedAt.After(evidenceReceivedAt) {
|
||||
evidenceObservedAt = evidenceReceivedAt
|
||||
}
|
||||
evidence, err := unified.NormalizeActionEvidence(unified.ActionEvidence{
|
||||
Version: unified.ActionEvidenceVersion, ID: operation + "-agent-readback", ObserverID: agentID,
|
||||
ObserverKind: "unified_agent", ObserverTrustDomain: "agent:" + agentID, ExecutorTrustDomain: "agent:" + agentID,
|
||||
Method: "typed_read_after_write", SubjectID: resourceID, ObservedAt: afterObservedAt.UTC(), ReceivedAt: receivedAt.UTC(),
|
||||
Method: "typed_read_after_write", SubjectID: resourceID, ObservedAt: evidenceObservedAt, ReceivedAt: evidenceReceivedAt,
|
||||
Summary: output,
|
||||
})
|
||||
if err == nil {
|
||||
|
||||
@@ -52,6 +52,21 @@ func TestHostAPTActionResultFutureVerifiedClaimFailsClosed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostAPTActionResultBoundsPermittedPositiveClockSkewToReceipt(t *testing.T) {
|
||||
now := time.Date(2026, 7, 12, 9, 0, 0, 0, time.UTC)
|
||||
result, err := hostAPTExecutionResult("agent:host-1", "host-1", agentexec.HostStorageCleanupOperationPackageCache, "cleanup complete", true, true, agentexec.HostStorageCleanupVerificationVerified, true, false, false, false, false, now.Add(-time.Second), now.Add(time.Second), now, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
truth := result.ActionResultV2.Verification
|
||||
if truth.Status != unified.ActionVerificationConfirmed || truth.EvidenceClass != unified.ActionEvidenceAgentAttested || len(truth.Evidence) != 1 {
|
||||
t.Fatalf("bounded clock skew lost verified readback: %#v", truth)
|
||||
}
|
||||
if !truth.Evidence[0].ObservedAt.Equal(now) || !truth.Evidence[0].ReceivedAt.Equal(now) {
|
||||
t.Fatalf("bounded clock skew was not conservatively normalized: %#v", truth.Evidence[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostAPTActionResultStaleReadbackFailsClosed(t *testing.T) {
|
||||
now := time.Date(2026, 7, 12, 9, 0, 0, 0, time.UTC)
|
||||
result, err := hostAPTExecutionResult("agent:host-1", "host-1", agentexec.HostUpdateOperationInstall, "updates complete", true, true, agentexec.HostUpdateVerificationVerified, true, true, true, true, false, now.Add(-time.Hour-time.Minute), now.Add(-time.Hour), now, now)
|
||||
|
||||
Reference in New Issue
Block a user