Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/shared_utilities_to_handle_vrl_expressions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
default: minor
---

# Breaking

Removed `pool_idle_timeout_seconds` from `traffic_shaping`, instead use `pool_idle_timeout` with duration format.

```diff
traffic_shaping:
- pool_idle_timeout_seconds: 30
+ pool_idle_timeout: 30s
```

#540 by @ardatan
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 12 additions & 17 deletions bin/router/src/pipeline/progressive_override.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use std::collections::{BTreeMap, HashMap, HashSet};

use hive_router_config::override_labels::{LabelOverrideValue, OverrideLabelsConfig};
use hive_router_plan_executor::execution::client_request_details::ClientRequestDetails;
use hive_router_plan_executor::{
execution::client_request_details::ClientRequestDetails, utils::expression::compile_expression,
};
use hive_router_query_planner::{
graph::{PlannerOverrideContext, PERCENTAGE_SCALE_FACTOR},
state::supergraph_state::SupergraphState,
};
use rand::Rng;
use vrl::{
compiler::{compile as vrl_compile, Program as VrlProgram, TargetValue as VrlTargetValue},
compiler::Program as VrlProgram,
compiler::TargetValue as VrlTargetValue,
core::Value as VrlValue,
prelude::{
state::RuntimeState as VrlState, Context as VrlContext, ExpressionError,
TimeZone as VrlTimeZone,
},
stdlib::all as vrl_build_functions,
value::Secrets as VrlSecrets,
};

Expand Down Expand Up @@ -126,27 +128,20 @@ impl OverrideLabelsEvaluator {
) -> Result<Self, OverrideLabelsCompileError> {
let mut static_enabled_labels = HashSet::new();
let mut expressions = HashMap::new();
let vrl_functions = vrl_build_functions();

for (label, value) in override_labels_config.iter() {
match value {
LabelOverrideValue::Boolean(true) => {
static_enabled_labels.insert(label.clone());
}
LabelOverrideValue::Expression { expression } => {
let compilation_result =
vrl_compile(expression, &vrl_functions).map_err(|diagnostics| {
OverrideLabelsCompileError {
label: label.clone(),
error: diagnostics
.errors()
.into_iter()
.map(|d| d.code.to_string() + ": " + &d.message)
.collect::<Vec<_>>()
.join(", "),
}
})?;
expressions.insert(label.clone(), compilation_result.program);
let program = compile_expression(expression, None).map_err(|err| {
OverrideLabelsCompileError {
label: label.clone(),
error: err.to_string(),
}
})?;
expressions.insert(label.clone(), program);
}
_ => {} // Skip false booleans
}
Expand Down
33 changes: 28 additions & 5 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
|[**csrf**](#csrf)|`object`|Configuration for CSRF prevention.<br/>Default: `{"enabled":false,"required_headers":[]}`<br/>||
|[**graphiql**](#graphiql)|`object`|Configuration for the GraphiQL interface.<br/>Default: `{"enabled":true}`<br/>||
|[**headers**](#headers)|`object`|Configuration for the headers.<br/>Default: `{}`<br/>||
|[**hmac\_signature**](#hmac_signature)|`object`||yes|
|[**http**](#http)|`object`|Configuration for the HTTP server/listener.<br/>Default: `{"host":"0.0.0.0","port":4000}`<br/>||
|[**jwt**](#jwt)|`object`|Configuration for JWT authentication plugin.<br/>|yes|
|[**log**](#log)|`object`|The router logger configuration.<br/>Default: `{"filter":null,"format":"json","level":"info"}`<br/>||
|[**override\_labels**](#override_labels)|`object`|Configuration for overriding labels.<br/>||
|[**override\_subgraph\_urls**](#override_subgraph_urls)|`object`|Configuration for overriding subgraph URLs.<br/>Default: `{}`<br/>||
|[**query\_planner**](#query_planner)|`object`|Query planning configuration.<br/>Default: `{"allow_expose":false,"timeout":"10s"}`<br/>||
|[**supergraph**](#supergraph)|`object`|Configuration for the Federation supergraph source. By default, the router will use a local file-based supergraph source (`./supergraph.graphql`).<br/>||
|[**traffic\_shaping**](#traffic_shaping)|`object`|Configuration for the traffic-shaper executor. Use these configurations to control how requests are being executed to subgraphs.<br/>Default: `{"dedupe_enabled":true,"max_connections_per_host":100,"pool_idle_timeout_seconds":50}`<br/>||
|[**traffic\_shaping**](#traffic_shaping)|`object`|Configuration for the traffic-shaping of the executor. Use these configurations to control how requests are being executed to subgraphs.<br/>Default: `{"dedupe_enabled":true,"max_connections_per_host":100,"pool_idle_timeout":"50s"}`<br/>||

**Additional Properties:** not allowed
**Example**
Expand Down Expand Up @@ -57,6 +58,9 @@ headers:
default: unknown
named: x-tenant-id
rename: x-acct-tenant
hmac_signature:
enabled: false
extension_name: hmac-signature
http:
host: 0.0.0.0
port: 4000
Expand Down Expand Up @@ -109,7 +113,7 @@ supergraph: {}
traffic_shaping:
dedupe_enabled: true
max_connections_per_host: 100
pool_idle_timeout_seconds: 50
pool_idle_timeout: 50s

```

Expand Down Expand Up @@ -1341,6 +1345,25 @@ For more information on the available functions and syntax, see the
|**expression**|`string`||yes|


<a name="hmac_signature"></a>
## hmac\_signature: object

**Properties**

|Name|Type|Description|Required|
|----|----|-----------|--------|
|**enabled**||Default: `false`<br/>|no|
|**extension\_name**|`string`|Default: `"hmac-signature"`<br/>|no|
|**secret**|`string`||yes|

**Example**

```yaml
enabled: false
extension_name: hmac-signature

```

<a name="http"></a>
## http: object

Expand Down Expand Up @@ -1808,7 +1831,7 @@ Request timeout for the Hive Console CDN requests.
<a name="traffic_shaping"></a>
## traffic\_shaping: object

Configuration for the traffic-shaper executor. Use these configurations to control how requests are being executed to subgraphs.
Configuration for the traffic-shaping of the executor. Use these configurations to control how requests are being executed to subgraphs.


**Properties**
Expand All @@ -1817,15 +1840,15 @@ Configuration for the traffic-shaper executor. Use these configurations to contr
|----|----|-----------|--------|
|**dedupe\_enabled**|`boolean`|Enables/disables request deduplication to subgraphs.<br/><br/>When requests exactly matches the hashing mechanism (e.g., subgraph name, URL, headers, query, variables), and are executed at the same time, they will<br/>be deduplicated by sharing the response of other in-flight requests.<br/>Default: `true`<br/>||
|**max\_connections\_per\_host**|`integer`|Limits the concurrent amount of requests/connections per host/subgraph.<br/>Default: `100`<br/>Format: `"uint"`<br/>Minimum: `0`<br/>||
|**pool\_idle\_timeout\_seconds**|`integer`|Timeout for idle sockets being kept-alive.<br/>Default: `50`<br/>Format: `"uint64"`<br/>Minimum: `0`<br/>||
|**pool\_idle\_timeout**|`string`|Timeout for idle sockets being kept-alive.<br/>Default: `"50s"`<br/>||

**Additional Properties:** not allowed
**Example**

```yaml
dedupe_enabled: true
max_connections_per_host: 100
pool_idle_timeout_seconds: 50
pool_idle_timeout: 50s

```

Expand Down
4 changes: 4 additions & 0 deletions e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ subgraphs = { path = "../bench/subgraphs" }

mockito = "1.7.0"
tempfile = "3.23.0"

hmac = "0.12.1"
sha2 = "0.10.9"
hex = "0.4.3"
3 changes: 3 additions & 0 deletions e2e/configs/hmac_forward.router.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hmac_signature:
enabled: true
secret: VERY_SECRET
56 changes: 56 additions & 0 deletions e2e/src/hmac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#[cfg(test)]
mod hmac_e2e_tests {
use crate::testkit::{
init_graphql_request, init_router_from_config_file, wait_for_readiness, SubgraphsServer,
};

use ntex::web::test;
use sonic_rs::JsonValueTrait;

fn create_hmac_signature(secret: &str, query: &str) -> String {
use hex;
use hmac::{Hmac, Mac};
use sha2::Sha256;

type HmacSha256 = Hmac<Sha256>;

let mut mac =
HmacSha256::new_from_slice(secret.as_bytes()).expect("HMAC can take key of any size");
let message = format!("{{\"query\":\"{}\"}}", query);
mac.update(message.as_bytes());
let result = mac.finalize();
let code_bytes = result.into_bytes();
hex::encode(code_bytes)
}

#[ntex::test]
async fn should_forward_hmac_signature_to_subgraph_via_extensions() {
let subgraphs_server = SubgraphsServer::start().await;
let app = init_router_from_config_file("configs/hmac_forward.router.yaml")
.await
.unwrap();
wait_for_readiness(&app.app).await;
let query = "query{users{id}}";
let req = init_graphql_request(query, None);
let resp: ntex::web::WebResponse = test::call_service(&app.app, req.to_request()).await;

assert!(resp.status().is_success(), "Expected 200 OK");

let subgraph_requests = subgraphs_server
.get_subgraph_requests_log("accounts")
.await
.expect("expected requests sent to accounts subgraph");
assert_eq!(
subgraph_requests.len(),
1,
"expected 1 request to accounts subgraph"
);
let extensions = subgraph_requests[0].request_body.get("extensions").unwrap();

let expected_signature = create_hmac_signature("VERY_SECRET", query);
assert_eq!(
extensions.get("hmac-signature").unwrap(),
&expected_signature
);
}
}
2 changes: 2 additions & 0 deletions e2e/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ mod file_supergraph;
#[cfg(test)]
mod hive_cdn_supergraph;
#[cfg(test)]
mod hmac;
#[cfg(test)]
mod jwt;
#[cfg(test)]
mod override_subgraph_urls;
Expand Down
4 changes: 4 additions & 0 deletions lib/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ itoa = "1.0.15"
ryu = "1.0.20"
indexmap = "2.10.0"
bumpalo = "3.19.0"
once_cell = "1.21.3"
hmac = "0.12.1"
sha2 = "0.10.9"
hex = "0.4.3"

[dev-dependencies]
subgraphs = { path = "../../bench/subgraphs" }
Expand Down
Loading
Loading