Skip to content

Security: oracle heartbeat gate + one-shot override audit (#398) - #466

Open
oyebolarotimi269-ai wants to merge 2 commits into
TevaLabs:mainfrom
oyebolarotimi269-ai:security/oracle-heartbeat-gate-one-shot-override-audit
Open

Security: oracle heartbeat gate + one-shot override audit (#398)#466
oyebolarotimi269-ai wants to merge 2 commits into
TevaLabs:mainfrom
oyebolarotimi269-ai:security/oracle-heartbeat-gate-one-shot-override-audit

Conversation

@oyebolarotimi269-ai

Copy link
Copy Markdown
Contributor

Summary

Adds an always-on heartbeat health gate for settlement that blocks resolution when the oracle heartbeat is unhealthy, and audits the admin override to enforce strict one-shot semantics with full event coverage.

Motivation

Heartbeat unhealthy blocks settlement; admin override is a high-privilege bypass. This PR audits the single-use semantics, emits events for arm + consume, and adds negative tests for the offline heartbeat blocking and override recovery paths.

Issue: Closes #398


What Changed

New: Always-on heartbeat health gate (_enforce_heartbeat_health)

A new function _enforce_heartbeat_health is placed before any state mutation (nonce consumption) in both resolve_round and resolve_round_multi. This ensures a stale or offline oracle cannot race the admin override path.

It returns OracleHeartbeatUnhealthy when:

  • No heartbeat has been recorded
  • Status is offline (2)

Staleness and degraded status are enforced separately by the strict-mode check later in resolve_round (which handles grace periods and override consumption).

One-shot override semantics

If the admin override is armed, it is consumed atomically on the next resolve and settlement proceeds. The override_armed flag is set to false by _consume_hb_override — one shot only.

Events

Event topic When emitted
(oracle, arm_ovr) Admin arms the oracle deviation override
(oracle, hb_arm_ovr) Admin arms the heartbeat override
(oracle, hb_override) Heartbeat override is consumed during settlement

The stale hoverride topic was renamed to hb_override for consistency.

Contract aliases

New public wrappers added for external integrators:

  • arm_oracle_heartbeat_override
  • is_oracle_heartbeat_override_armed
  • set_oracle_heartbeat_strict_mode / get_oracle_heartbeat_strict_mode
  • set_oracle_heartbeat_grace / get_oracle_heartbeat_grace

Error variant

OracleHeartbeatUnhealthy = 79 — clear rejection code for the always-on gate.


Acceptance Criteria

Criterion Status
Override arms once and consumes on next resolve _consume_hb_override clears flag atomically
Events for arm + consume hb_arm_ovr on arm, hb_override on consume
Negative tests: offline heartbeat blocks test_heartbeat_offline_blocks_resolve, test_heartbeat_none_blocks_resolve
Negative tests: override recovers test_heartbeat_override_allows_resolve

Files Changed

File Summary
contracts/src/admin.rs Add arm_oracle_deviation_override and arm_hb_override events
contracts/src/settlement.rs Add _enforce_heartbeat_health, call in both resolve paths, rename hoverridehb_override
contracts/src/errors.rs Add OracleHeartbeatUnhealthy = 79
contracts/src/contract.rs Add 6 public contract alias wrappers
contracts/src/tests/security.rs Add 10 new security tests, fix duplicate imports

Security Tests Added

test_heartbeat_offline_blocks_resolve       — offline heartbeat blocks settlement
test_heartbeat_none_blocks_resolve          — missing heartbeat blocks settlement
test_heartbeat_override_allows_resolve      — armed override recovers
test_heartbeat_override_cleared_after_use   — override is one-shot
test_heartbeat_override_emits_event         — consume emits hb_override
test_arm_heartbeat_override_emits_event     — arm emits hb_arm_ovr
test_heartbeat_stale_within_grace_strict_blocks_resolve  — strict mode
test_heartbeat_degraded_fresh_strict_blocks_resolve      — strict mode
test_heartbeat_grace_config                 — grace period settable/queryable
test_heartbeat_strict_mode_config           — strict mode settable/queryable

Design Note

_enforce_heartbeat_health is placed before nonce consumption to prevent a stale oracle from racing the admin override. This is parity with the single-oracle resolve_round path and is critical for the security guarantee.

… override audit (TevaLabs#398)

Enforce an always-on heartbeat health gate before any state mutation in
both `resolve_round` and `resolve_round_multi`. This ensures a stale or
offline oracle cannot bypass the admin override by racing the nonce
consumption path.

Changes:
- Add `_enforce_heartbeat_health` that blocks settlement when:
  - No heartbeat has been recorded
  - Status is offline (2)
  The function is placed before nonce consumption to prevent race conditions.
- Add `OracleHeartbeatUnhealthy` error variant (79) for clear rejection.
- Add `_consume_hb_override` that atomically clears `override_armed`
  on next resolve, enforcing one-shot semantics.
- Emit `hb_arm_ovr` event when admin arms the override, and `hb_override`
  event when it is consumed.
- Rename stale `hoverride` event topic to `hb_override` for consistency.
- Add `_enforce_heartbeat_health` call in `resolve_round_multi` for parity
  with the single-oracle `resolve_round` path.
- Add public contract alias wrappers: `arm_oracle_heartbeat_override`,
  `is_oracle_heartbeat_override_armed`, `set_oracle_heartbeat_strict_mode`,
  `get_oracle_heartbeat_strict_mode`, `set_oracle_heartbeat_grace`,
  `get_oracle_heartbeat_grace`.
- Fix duplicate import lines in test file.

Security tests:
- `test_heartbeat_offline_blocks_resolve` — offline heartbeat blocks settlement
- `test_heartbeat_none_blocks_resolve` — missing heartbeat blocks settlement
- `test_heartbeat_override_allows_resolve` — armed override recovers
- `test_heartbeat_override_cleared_after_use` — override is one-shot
- `test_heartbeat_override_emits_event` — consume emits `hb_override`
- `test_arm_heartbeat_override_emits_event` — arm emits `hb_arm_ovr`
- `test_heartbeat_stale_within_grace_strict_blocks_resolve` — strict mode
- `test_heartbeat_degraded_fresh_strict_blocks_resolve` — strict mode
- `test_heartbeat_grace_config` — grace period settable/queryable
- `test_heartbeat_strict_mode_config` — strict mode settable/queryable

Closes TevaLabs#398

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@oyebolarotimi269-ai
oyebolarotimi269-ai force-pushed the security/oracle-heartbeat-gate-one-shot-override-audit branch from 6ef6ee8 to 3f8f3f5 Compare August 27, 2026 12:20
…ve_round

The ? operator without a trailing ; caused a syntax error, preventing
the entire crate from compiling and failing all CI jobs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: oracle heartbeat gate + one-shot override audit

1 participant