You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(hosts): rate-limit heartbeats and close enrollment and audit gaps #87
Heartbeats have no minimum interval (apps/control_plane/lib/workharbor/host_connections.ex, around lines 215-247). Each one writes a transaction plus an undeletable audit row, so a buggy or compromised agent can grow the audit table without bound and starve owner writes (persistence_busy).
Issuing a new enrollment code for a host leaves earlier unexpired codes valid (hosts.ex, around lines 15-52). Redeeming the stale code retires the identity the agent just enrolled with.
authorize! inside a transaction calls Repo.rollback(:forbidden), which also rolls back the authorization_denied audit (hosts.ex around 18/242/374, config_trust.ex around 29/111). Denial audits are security evidence under authentication.md §4.
Acceptance criteria
Heartbeats faster than a fixed floor (for example 5 s against the 10 s cadence) are refused or close the connection, with a test.
Issuing a code revokes the host's outstanding unconsumed codes, with a test.
A denial inside a transaction keeps its audit row, with a test.
make check is green.
Found by the independent pilot review on 2026-10-16. Builds on the pilot branch pilot/installable-pilot-pr (split from #83); start from its current head.
Activity
fix(hosts): rate-limit heartbeats with a receive-time token bucket
fix(hosts): revoke earlier unconsumed codes when issuing a new one
fix(hosts): keep authorization_denied audits raised inside transactions
test(hosts): prove in-transaction denial keeps its audit row
fix(hosts): rate-limit heartbeats with a receive-time token bucket
fix(hosts): revoke earlier unconsumed codes when issuing a new one
fix(hosts): keep authorization_denied audits raised inside transactions
test(hosts): prove in-transaction denial keeps its audit row
fix(hosts): rate-limit heartbeats with a receive-time token bucket
fix(hosts): revoke earlier unconsumed codes when issuing a new one
fix(hosts): keep authorization_denied audits raised inside transactions
test(hosts): prove in-transaction denial keeps its audit row
fix(hosts): rate-limit heartbeats with a receive-time token bucket
fix(hosts): revoke earlier unconsumed codes when issuing a new one
fix(hosts): keep authorization_denied audits raised inside transactions
test(hosts): prove in-transaction denial keeps its audit row
fix(hosts): rate-limit heartbeats with a receive-time token bucket
fix(hosts): revoke earlier unconsumed codes when issuing a new one
fix(hosts): keep authorization_denied audits raised inside transactions
test(hosts): prove in-transaction denial keeps its audit row
wstein commentedon Oct 16, 2026
Done in #100. Final
make checkon main1cb22c2: GREEN (850 harness, 654 Go, 200 ExUnit).