-
Notifications
You must be signed in to change notification settings - Fork 0
feat(api): package loopback temporal context service #186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e2b694c
f22ac1b
a8db2bf
169faa1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| .codegraph | ||
| .git | ||
| node_modules | ||
| target |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ### Added | ||
|
|
||
| - Package the existing cutoff-safe `POST /v1/temporal-context` contract as the loopback-only `tepp-loopback` binary and container for trusted same-host consumers such as LineageWeave. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| FROM rust:1.97.1-bookworm AS build | ||
| WORKDIR /src | ||
| COPY . . | ||
| RUN cargo build --locked --release -p tepp_api --bin tepp-loopback | ||
|
|
||
| FROM debian:bookworm-slim | ||
| RUN apt-get update \ | ||
| && apt-get install --yes --no-install-recommends ca-certificates curl \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
| COPY --from=build /src/target/release/tepp-loopback /usr/local/bin/tepp-loopback | ||
| USER 65532:65532 | ||
| HEALTHCHECK --interval=10s --timeout=3s --start-period=2s --retries=5 \ | ||
| CMD curl --fail --silent --show-error \ | ||
| --header "content-type: application/json" \ | ||
| --header "tepp-consumer: lineageweave" \ | ||
| --header "tepp-contract-version: 1" \ | ||
| --data '{"contract_version":1,"consumer_code":"lineageweave","knowledge_cutoff":"2026-08-20T00:00:00Z","subject_post_id":"health-post","events":[{"event_id":"health-event","source_post_id":"health-post","event_type_code":"health_probe","event_label":"Health probe","event_time":"2026-08-20T00:00:00Z","available_time":"2026-08-20T00:00:00Z","project_reference":null,"actor_references":["health-actor"]}]}' \ | ||
| http://127.0.0.1:18081/v1/temporal-context >/dev/null \ | ||
| || exit 1 | ||
|
Comment on lines
+12
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Hardcoded healthcheck payload can drift from the contract The container health probe posts a fixed temporal-context JSON body. It matches current validation, but any change to the temporal-context wire DTO will silently break the probe with no compile-time link. Keep it in sync with the contract. Was this helpful? React with 👍 or 👎 to provide feedback.
Comment on lines
+12
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Healthcheck consumes the served-request budget The Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| ENTRYPOINT ["/usr/local/bin/tepp-loopback"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| //! Runnable loopback ingress for trusted same-host TEPP consumers. | ||
|
|
||
| use std::net::SocketAddr; | ||
|
|
||
| use tepp_api::AnalysisRunLiveService; | ||
|
|
||
| const DEFAULT_BIND_ADDR: &str = "127.0.0.1:18081"; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Container reachable only via shared network namespace With no args the entrypoint binds Was this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
| let mut arguments = std::env::args().skip(1); | ||
| let bind_addr = arguments | ||
| .next() | ||
| .unwrap_or(DEFAULT_BIND_ADDR.to_owned()) | ||
| .parse::<SocketAddr>()?; | ||
| let request_limit = arguments | ||
| .next() | ||
| .map(|value| value.parse::<usize>()) | ||
| .transpose()? | ||
| .unwrap_or(usize::MAX); | ||
| let mut service = AnalysisRunLiveService::bind(bind_addr)?; | ||
| println!("{}", service.local_addr()?); | ||
| (0..request_limit).for_each(|_| drop(service.serve_one())); | ||
|
Comment on lines
+15
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Bounded limit counts failed attempts
Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| Ok(()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| //! The packaged loopback binary serves the published temporal-context wire. | ||
|
|
||
| use std::io::{BufRead, BufReader, Read, Write}; | ||
| use std::net::TcpStream; | ||
| use std::process::{Command, Stdio}; | ||
|
|
||
| #[test] | ||
| fn binary_serves_one_bounded_temporal_context_request() { | ||
| let mut child = Command::new(env!("CARGO_BIN_EXE_tepp-loopback")) | ||
| .args(["127.0.0.1:0", "1"]) | ||
| .stdout(Stdio::piped()) | ||
| .spawn() | ||
| .expect("spawn loopback service"); | ||
| let mut address = String::new(); | ||
| BufReader::new(child.stdout.take().expect("stdout")) | ||
| .read_line(&mut address) | ||
| .expect("bound address"); | ||
| let body = r#"{"contract_version":1,"consumer_code":"lineageweave","knowledge_cutoff":"2026-08-20T00:00:00Z","subject_post_id":"post-1","events":[{"event_id":"event-1","source_post_id":"post-1","event_type_code":"health_probe","event_label":"Health probe","event_time":"2026-08-20T00:00:00Z","available_time":"2026-08-20T00:00:00Z","project_reference":null,"actor_references":["actor-1"]}]}"#; | ||
| let request = format!( | ||
| "POST /v1/temporal-context HTTP/1.1\r\nHost: {}\r\ncontent-type: application/json\r\ntepp-consumer: lineageweave\r\ntepp-contract-version: 1\r\ncontent-length: {}\r\n\r\n{body}", | ||
| address.trim(), | ||
| body.len() | ||
| ); | ||
| let mut stream = TcpStream::connect(address.trim()).expect("connect"); | ||
| stream.write_all(request.as_bytes()).expect("request"); | ||
| let mut response = String::new(); | ||
| stream.read_to_string(&mut response).expect("response"); | ||
| assert!(response.starts_with("HTTP/1.1 200 OK")); | ||
| assert!(response.contains("association_not_causal")); | ||
| assert!(child.wait().expect("wait").success()); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.