commit 7766cefd12ce18e5f3b9e47bb283d47d414d6fdc
parent 00f506fe318e69a0e4933513c061e3d49215ac4b
Author: triesap <tyson@radroots.org>
Date: Sun, 14 Jun 2026 14:39:34 -0700
config: move relay example config
- Move the checked-in relay example config out of ops/production.
- Update runtime config and logging fixtures to use config/tangle.example.json.
- Align CLI tests with the neutral example config path.
- Remove the misleading production ops directory from the repo tree.
Diffstat:
4 files changed, 182 insertions(+), 11 deletions(-)
diff --git a/config/tangle.example.json b/config/tangle.example.json
@@ -0,0 +1,171 @@
+{
+ "server": {
+ "listen_addr": "0.0.0.0:7000",
+ "relay_url": "wss://relay.radroots.test"
+ },
+ "pocket": {
+ "data_directory": "runtime/pocket",
+ "map_size_bytes": 1099511627776,
+ "reader_slots": 512,
+ "sync_policy": "flush_on_shutdown"
+ },
+ "groups": {
+ "enabled": true,
+ "canonical_relay_url": "wss://relay.radroots.test",
+ "relay_secret": "7777777777777777777777777777777777777777777777777777777777777777",
+ "owner_pubkeys": [
+ "0000000000000000000000000000000000000000000000000000000000000001"
+ ],
+ "admin_pubkeys": [
+ "0000000000000000000000000000000000000000000000000000000000000002"
+ ],
+ "policy": {
+ "public_join": false,
+ "invites_enabled": false
+ },
+ "limits": {
+ "max_group_id_bytes": 128,
+ "max_group_tags_per_event": 8,
+ "max_supported_kinds": 512,
+ "max_member_list_pubkeys": 100000,
+ "max_outbox_replay_batch": 1000
+ }
+ },
+ "auth": {
+ "challenge_ttl_seconds": 300,
+ "created_at_skew_seconds": 600
+ },
+ "limits": {
+ "max_message_length": 1048576,
+ "max_subid_length": 64,
+ "max_subscriptions_per_connection": 64,
+ "max_filters_per_request": 10,
+ "max_tag_values_per_filter": 100,
+ "max_query_complexity": 2048,
+ "max_limit": 500,
+ "default_limit": 100,
+ "max_event_tags": 200,
+ "max_content_length": 65536,
+ "broadcast_channel_capacity": 4096,
+ "per_connection_outbound_queue": 256
+ },
+ "rate_limits": {
+ "auth": {
+ "per_ip": {
+ "window_seconds": 60,
+ "max_hits": 120
+ },
+ "per_pubkey": {
+ "window_seconds": 60,
+ "max_hits": 30
+ },
+ "failures": {
+ "window_seconds": 300,
+ "max_hits": 5
+ },
+ "failures_per_ip": {
+ "window_seconds": 300,
+ "max_hits": 20
+ }
+ },
+ "event": {
+ "per_ip": {
+ "window_seconds": 60,
+ "max_hits": 600
+ },
+ "per_pubkey": {
+ "window_seconds": 60,
+ "max_hits": 120
+ },
+ "per_kind": {
+ "window_seconds": 60,
+ "max_hits": 1000
+ }
+ },
+ "group": {
+ "write_per_ip": {
+ "window_seconds": 60,
+ "max_hits": 300
+ },
+ "write_per_pubkey": {
+ "window_seconds": 60,
+ "max_hits": 60
+ },
+ "write_per_group": {
+ "window_seconds": 60,
+ "max_hits": 90
+ },
+ "write_per_kind": {
+ "window_seconds": 60,
+ "max_hits": 300
+ },
+ "join_flow": {
+ "window_seconds": 300,
+ "max_hits": 10
+ },
+ "join_flow_per_ip": {
+ "window_seconds": 300,
+ "max_hits": 30
+ }
+ },
+ "req": {
+ "per_ip": {
+ "window_seconds": 60,
+ "max_hits": 600
+ },
+ "per_connection": {
+ "window_seconds": 60,
+ "max_hits": 120
+ },
+ "per_pubkey": {
+ "window_seconds": 60,
+ "max_hits": 240
+ },
+ "per_group": {
+ "window_seconds": 60,
+ "max_hits": 240
+ },
+ "per_kind": {
+ "window_seconds": 60,
+ "max_hits": 500
+ },
+ "broad": {
+ "window_seconds": 60,
+ "max_hits": 30
+ }
+ },
+ "count": {
+ "per_ip": {
+ "window_seconds": 60,
+ "max_hits": 300
+ },
+ "per_connection": {
+ "window_seconds": 60,
+ "max_hits": 60
+ },
+ "per_pubkey": {
+ "window_seconds": 60,
+ "max_hits": 120
+ },
+ "per_group": {
+ "window_seconds": 60,
+ "max_hits": 120
+ },
+ "per_kind": {
+ "window_seconds": 60,
+ "max_hits": 240
+ },
+ "broad": {
+ "window_seconds": 60,
+ "max_hits": 20
+ }
+ }
+ },
+ "observability": {
+ "tracing": {
+ "enabled": true,
+ "filter": "info,tangle=info,tangle_runtime=info,tangle_groups=info,tangle_store_pocket=info",
+ "format": "json"
+ }
+ }
+}
diff --git a/crates/tangle/src/lib.rs b/crates/tangle/src/lib.rs
@@ -193,11 +193,11 @@ mod tests {
TangleInvocation::new(TangleCommand::Version, None)
);
assert_eq!(
- parse_tangle_invocation(["run", "--config", "ops/production/tangle-v2.example.json"])
+ parse_tangle_invocation(["run", "--config", "config/tangle.example.json"])
.expect("run"),
TangleInvocation::new(
TangleCommand::Run,
- Some("ops/production/tangle-v2.example.json".to_owned())
+ Some("config/tangle.example.json".to_owned())
)
);
}
diff --git a/crates/tangle_runtime/src/config.rs b/crates/tangle_runtime/src/config.rs
@@ -616,7 +616,7 @@ mod tests {
#[test]
fn base_relay_runtime_config_parses_v2_production_example() {
let config = parse_base_relay_runtime_config_json(include_str!(
- "../../../ops/production/tangle-v2.example.json"
+ "../../../config/tangle.example.json"
))
.expect("config");
@@ -933,7 +933,7 @@ mod tests {
#[test]
fn base_relay_runtime_config_requires_explicit_query_complexity() {
- let raw = include_str!("../../../ops/production/tangle-v2.example.json")
+ let raw = include_str!("../../../config/tangle.example.json")
.replace(" \"max_query_complexity\": 2048,\n", "");
assert!(
parse_base_relay_runtime_config_json(&raw)
@@ -945,7 +945,7 @@ mod tests {
#[test]
fn base_relay_runtime_config_requires_ip_scoped_rate_limits() {
- let raw = include_str!("../../../ops/production/tangle-v2.example.json").replace(
+ let raw = include_str!("../../../config/tangle.example.json").replace(
" \"per_ip\": {\n \"window_seconds\": 60,\n \"max_hits\": 120\n },\n",
"",
);
@@ -956,7 +956,7 @@ mod tests {
.contains("missing field `per_ip`")
);
- let raw = include_str!("../../../ops/production/tangle-v2.example.json").replace(
+ let raw = include_str!("../../../config/tangle.example.json").replace(
" \"failures\": {\n \"window_seconds\": 300,\n \"max_hits\": 5\n },\n \"failures_per_ip\": {\n \"window_seconds\": 300,\n \"max_hits\": 20\n }\n",
" \"failures\": {\n \"window_seconds\": 300,\n \"max_hits\": 5\n }\n",
);
@@ -967,7 +967,7 @@ mod tests {
.contains("missing field `failures_per_ip`")
);
- let raw = include_str!("../../../ops/production/tangle-v2.example.json").replace(
+ let raw = include_str!("../../../config/tangle.example.json").replace(
" \"per_ip\": {\n \"window_seconds\": 60,\n \"max_hits\": 600\n },\n",
"",
);
@@ -978,7 +978,7 @@ mod tests {
.contains("missing field `per_ip`")
);
- let raw = include_str!("../../../ops/production/tangle-v2.example.json").replace(
+ let raw = include_str!("../../../config/tangle.example.json").replace(
" \"write_per_ip\": {\n \"window_seconds\": 60,\n \"max_hits\": 300\n },\n",
"",
);
@@ -989,7 +989,7 @@ mod tests {
.contains("missing field `write_per_ip`")
);
- let raw = include_str!("../../../ops/production/tangle-v2.example.json").replace(
+ let raw = include_str!("../../../config/tangle.example.json").replace(
" \"join_flow\": {\n \"window_seconds\": 300,\n \"max_hits\": 10\n },\n \"join_flow_per_ip\": {\n \"window_seconds\": 300,\n \"max_hits\": 30\n }\n",
" \"join_flow\": {\n \"window_seconds\": 300,\n \"max_hits\": 10\n }\n",
);
diff --git a/crates/tangle_runtime/src/logging.rs b/crates/tangle_runtime/src/logging.rs
@@ -419,7 +419,7 @@ mod tests {
#[test]
fn runtime_log_summary_never_contains_relay_secret() {
- let raw = include_str!("../../../ops/production/tangle-v2.example.json");
+ let raw = include_str!("../../../config/tangle.example.json");
let config = parse_base_relay_runtime_config_json(raw).expect("config");
let secret = "7".repeat(64);
let summary = TangleRuntimeLogSummary::from_config(&config);
@@ -434,7 +434,7 @@ mod tests {
#[test]
fn structured_runtime_config_log_redacts_relay_secret() {
- let raw = include_str!("../../../ops/production/tangle-v2.example.json");
+ let raw = include_str!("../../../config/tangle.example.json");
let config = parse_base_relay_runtime_config_json(raw).expect("config");
let secret = "7".repeat(64);
let writer = CapturedWriter::default();