Skip to content

Commit f6d165c

Browse files
chore(release): 2.0.0 [skip ci]
# [2.0.0](v1.2.0...v2.0.0) (2026-02-18) ### Features * **auth:** replace static hotkey/API-key auth with Bittensor validator whitelisting and 50% consensus ([#5](#5)) ([a573ad0](a573ad0)) ### BREAKING CHANGES * **auth:** WORKER_API_KEY env var and X-Api-Key header no longer required. All validators on Bittensor netuid 100 with sufficient stake are auto-whitelisted. * ci: trigger CI run * fix(security): address auth bypass, input validation, and config issues - Move nonce consumption AFTER signature verification in verify_request() to prevent attackers from burning legitimate nonces via invalid signatures - Fix TOCTOU race in NonceStore::check_and_insert() using atomic DashMap entry API instead of separate contains_key + insert - Add input length limits for auth headers (hotkey 128B, nonce 256B, signature 256B) to prevent memory exhaustion via oversized values - Add consensus_threshold validation in Config::from_env() — must be in range (0.0, 1.0], panics at startup if invalid - Add saturating conversion for consensus required calculation to prevent integer overflow on f64→usize cast - Add tests for all security fixes * fix(dead-code): remove orphaned default_concurrent fn and unnecessary allow(dead_code) * fix: code quality issues in bittensor validator consensus - Extract magic number 100 to configurable MAX_PENDING_CONSENSUS - Restore #[allow(dead_code)] on DEFAULT_MAX_OUTPUT_BYTES constant - Use anyhow::Context instead of map_err(anyhow::anyhow!) in validator_whitelist * fix(security): address race condition, config panic, SS58 checksum, and container security - consensus.rs: Fix TOCTOU race condition in record_vote by using DashMap entry API (remove_entry) to atomically check votes and remove entry while holding the shard lock, preventing concurrent threads from inserting votes between drop and remove - config.rs: Replace assert! with proper Result<Self, String> return from Config::from_env() to avoid panicking in production on invalid CONSENSUS_THRESHOLD values - main.rs: Update Config::from_env() call to handle Result with expect - auth.rs: Add SS58 checksum verification using Blake2b-512 (correct Substrate algorithm) in ss58_to_public_key_bytes to reject addresses with corrupted checksums; previously only decoded base58 without validating the 2-byte checksum suffix - Dockerfile: Add non-root executor user for container runtime security * fix(dead-code): remove unused max_output_bytes config field and constant Remove DEFAULT_MAX_OUTPUT_BYTES constant and max_output_bytes Config field that were defined and populated from env but never read anywhere outside config.rs. Both had #[allow(dead_code)] annotations suppressing warnings. * fix(quality): replace expect/unwrap with proper error handling, extract magic numbers to constants - main.rs: Replace .expect() on Config::from_env() with match + tracing::error! + process::exit(1) - validator_whitelist.rs: Extract retry count (3) and backoff base (2) to named constants - validator_whitelist.rs: Replace unwrap_or_else on Option with if-let pattern - consensus.rs: Extract reaper interval (30s) to REAPER_INTERVAL_SECS constant * fix(security): address multiple security vulnerabilities in PR files - consensus.rs: Remove archive_data storage from PendingConsensus to prevent memory exhaustion (up to 50GB with 100 pending × 500MB each). Callers now use their own archive bytes since all votes for the same hash have identical data. - handlers.rs: Stream multipart upload with per-chunk size enforcement instead of buffering entire archive before checking size limit. Sanitize error messages to not leak internal details (file paths, extraction errors) to clients; log details server-side instead. - auth.rs: Add nonce format validation requiring non-empty printable ASCII characters (defense-in-depth against log injection and empty nonce edge cases). - main.rs: Replace .unwrap() on TcpListener::bind and axum::serve with proper error logging and process::exit per AGENTS.md rules. - ws.rs: Replace .unwrap() on serde_json::to_string with unwrap_or_default() to comply with AGENTS.md no-unwrap rule. * fix(dead-code): rename misleading underscore-prefixed variable in consensus * fix(quality): replace unwrap/expect with proper error handling in production code - main.rs:21: Replace .parse().unwrap() on tracing directive with unwrap_or_else fallback to INFO level directive - main.rs:36: Replace .expect() on workspace dir creation with error log + process::exit(1) pattern - main.rs:110: Replace .expect() on ctrl_c handler with if-let-Err that logs and returns gracefully - executor.rs:189: Replace semaphore.acquire().unwrap() with match that handles closed semaphore by creating a failed TaskResult All changes follow AGENTS.md rule: no .unwrap()/.expect() in production code paths. Test code is unchanged. * docs: refresh AGENTS.md
1 parent a573ad0 commit f6d165c

File tree

3 files changed

+108
-2
lines changed

3 files changed

+108
-2
lines changed

CHANGELOG.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,109 @@
1+
# [2.0.0](https://github.com/PlatformNetwork/term-executor/compare/v1.2.0...v2.0.0) (2026-02-18)
2+
3+
4+
### Features
5+
6+
* **auth:** replace static hotkey/API-key auth with Bittensor validator whitelisting and 50% consensus ([#5](https://github.com/PlatformNetwork/term-executor/issues/5)) ([a573ad0](https://github.com/PlatformNetwork/term-executor/commit/a573ad04df1157843b8a825d24ed5c4df06f0f90))
7+
8+
9+
### BREAKING CHANGES
10+
11+
* **auth:** WORKER_API_KEY env var and X-Api-Key header no longer required.
12+
All validators on Bittensor netuid 100 with sufficient stake are auto-whitelisted.
13+
14+
* ci: trigger CI run
15+
16+
* fix(security): address auth bypass, input validation, and config issues
17+
18+
- Move nonce consumption AFTER signature verification in verify_request()
19+
to prevent attackers from burning legitimate nonces via invalid signatures
20+
- Fix TOCTOU race in NonceStore::check_and_insert() using atomic DashMap
21+
entry API instead of separate contains_key + insert
22+
- Add input length limits for auth headers (hotkey 128B, nonce 256B,
23+
signature 256B) to prevent memory exhaustion via oversized values
24+
- Add consensus_threshold validation in Config::from_env() — must be
25+
in range (0.0, 1.0], panics at startup if invalid
26+
- Add saturating conversion for consensus required calculation to prevent
27+
integer overflow on f64→usize cast
28+
- Add tests for all security fixes
29+
30+
* fix(dead-code): remove orphaned default_concurrent fn and unnecessary allow(dead_code)
31+
32+
* fix: code quality issues in bittensor validator consensus
33+
34+
- Extract magic number 100 to configurable MAX_PENDING_CONSENSUS
35+
- Restore #[allow(dead_code)] on DEFAULT_MAX_OUTPUT_BYTES constant
36+
- Use anyhow::Context instead of map_err(anyhow::anyhow!) in validator_whitelist
37+
38+
* fix(security): address race condition, config panic, SS58 checksum, and container security
39+
40+
- consensus.rs: Fix TOCTOU race condition in record_vote by using
41+
DashMap entry API (remove_entry) to atomically check votes and remove
42+
entry while holding the shard lock, preventing concurrent threads from
43+
inserting votes between drop and remove
44+
- config.rs: Replace assert! with proper Result<Self, String> return
45+
from Config::from_env() to avoid panicking in production on invalid
46+
CONSENSUS_THRESHOLD values
47+
- main.rs: Update Config::from_env() call to handle Result with expect
48+
- auth.rs: Add SS58 checksum verification using Blake2b-512 (correct
49+
Substrate algorithm) in ss58_to_public_key_bytes to reject addresses
50+
with corrupted checksums; previously only decoded base58 without
51+
validating the 2-byte checksum suffix
52+
- Dockerfile: Add non-root executor user for container runtime security
53+
54+
* fix(dead-code): remove unused max_output_bytes config field and constant
55+
56+
Remove DEFAULT_MAX_OUTPUT_BYTES constant and max_output_bytes Config field
57+
that were defined and populated from env but never read anywhere outside
58+
config.rs. Both had #[allow(dead_code)] annotations suppressing warnings.
59+
60+
* fix(quality): replace expect/unwrap with proper error handling, extract magic numbers to constants
61+
62+
- main.rs: Replace .expect() on Config::from_env() with match + tracing::error! + process::exit(1)
63+
- validator_whitelist.rs: Extract retry count (3) and backoff base (2) to named constants
64+
- validator_whitelist.rs: Replace unwrap_or_else on Option with if-let pattern
65+
- consensus.rs: Extract reaper interval (30s) to REAPER_INTERVAL_SECS constant
66+
67+
* fix(security): address multiple security vulnerabilities in PR files
68+
69+
- consensus.rs: Remove archive_data storage from PendingConsensus to
70+
prevent memory exhaustion (up to 50GB with 100 pending × 500MB each).
71+
Callers now use their own archive bytes since all votes for the same
72+
hash have identical data.
73+
74+
- handlers.rs: Stream multipart upload with per-chunk size enforcement
75+
instead of buffering entire archive before checking size limit.
76+
Sanitize error messages to not leak internal details (file paths,
77+
extraction errors) to clients; log details server-side instead.
78+
79+
- auth.rs: Add nonce format validation requiring non-empty printable
80+
ASCII characters (defense-in-depth against log injection and empty
81+
nonce edge cases).
82+
83+
- main.rs: Replace .unwrap() on TcpListener::bind and axum::serve with
84+
proper error logging and process::exit per AGENTS.md rules.
85+
86+
- ws.rs: Replace .unwrap() on serde_json::to_string with
87+
unwrap_or_default() to comply with AGENTS.md no-unwrap rule.
88+
89+
* fix(dead-code): rename misleading underscore-prefixed variable in consensus
90+
91+
* fix(quality): replace unwrap/expect with proper error handling in production code
92+
93+
- main.rs:21: Replace .parse().unwrap() on tracing directive with
94+
unwrap_or_else fallback to INFO level directive
95+
- main.rs:36: Replace .expect() on workspace dir creation with
96+
error log + process::exit(1) pattern
97+
- main.rs:110: Replace .expect() on ctrl_c handler with if-let-Err
98+
that logs and returns gracefully
99+
- executor.rs:189: Replace semaphore.acquire().unwrap() with match
100+
that handles closed semaphore by creating a failed TaskResult
101+
102+
All changes follow AGENTS.md rule: no .unwrap()/.expect() in
103+
production code paths. Test code is unchanged.
104+
105+
* docs: refresh AGENTS.md
106+
1107
# [1.2.0](https://github.com/PlatformNetwork/term-executor/compare/v1.1.0...v1.2.0) (2026-02-17)
2108

3109

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "term-executor"
3-
version = "1.2.0"
3+
version = "2.0.0"
44
edition = "2021"
55
description = "Attested SWE-bench evaluation executor for term-challenge miners"
66
authors = ["Platform Network"]

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.0
1+
2.0.0

0 commit comments

Comments
 (0)