Skip to content

Commit

Permalink
Add git commit hash and timestamp to info endpoint (#392)
Browse files Browse the repository at this point in the history
* Add commit hash and timestamp

* Fixed Docker build problem

#392

* Fix error message and docker build.

* Update README and openapi yaml.

* Formatting.

---------

Co-authored-by: Hendrik Eeckhaut <[email protected]>
  • Loading branch information
yuroitaki and heeckhau authored Dec 12, 2023
1 parent 31708c0 commit 52d6bb2
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 11 deletions.
25 changes: 16 additions & 9 deletions notary-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ docker run --init -p 127.0.0.1:7047:7047 notary-server:local
```bash
docker run --init -p 127.0.0.1:7047:7047 -v <your folder path>:/root/.notary-server/fixture notary-server:local
```
- Example 2: Using different key for notarization (your folder should only contain `notary.key`):
- Example 2: Using different key for notarization:
```bash
docker run --init -p 127.0.0.1:7047:7047 -v <your folder path>:/root/.notary-server/fixture/notary notary-server:local
```
Expand All @@ -71,7 +71,7 @@ Defined in the [OpenAPI specification](./openapi.yaml).
### WebSocket APIs
#### /notarize
##### Description
To perform notarization using the session id (unique id returned upon calling the `/session` endpoint successfully) submitted as a custom header.
To perform notarization using the session id (unique id returned upon calling the `/session` endpoint successfully).

##### Query Parameter
`sessionId`
Expand All @@ -86,13 +86,7 @@ The main objective of a notary server is to perform notarization together with a
1. TCP client — which has access and control over the transport layer, i.e. TCP
2. WebSocket client — which has no access over TCP and instead uses WebSocket for notarization

### Design Choices
#### Web Framework
Axum is chosen as the framework to serve HTTP and WebSocket requests from the prover clients due to its rich and well supported features, e.g. native integration with Tokio/Hyper/Tower, customizable middleware, ability to support lower level integration of TLS ([example](https://github.com/tokio-rs/axum/blob/main/examples/low-level-rustls/src/main.rs)). To simplify the notary server setup, a single Axum router is used to support both HTTP and WebSocket connections, i.e. all requests can be made to the same port of the notary server.

#### WebSocket
Axum's internal implementation of WebSocket uses [tokio_tungstenite](https://docs.rs/tokio-tungstenite/latest/tokio_tungstenite/), which provides a WebSocket struct that doesn't implement [AsyncRead](https://docs.rs/futures/latest/futures/io/trait.AsyncRead.html) and [AsyncWrite](https://docs.rs/futures/latest/futures/io/trait.AsyncWrite.html). Both these traits are required by TLSN core libraries for prover and notary. To overcome this, a [slight modification](./src/service/axum_websocket.rs) of Axum's implementation of WebSocket is used, where [async_tungstenite](https://docs.rs/async-tungstenite/latest/async_tungstenite/) is used instead so that [ws_stream_tungstenite](https://docs.rs/ws_stream_tungstenite/latest/ws_stream_tungstenite/index.html) can be used to wrap on top of the WebSocket struct to get AsyncRead and AsyncWrite implemented.

### Features
#### Notarization Configuration
To perform notarization, some parameters need to be configured by the prover and notary server (more details in the [OpenAPI specification](./openapi.yaml)), i.e.
- maximum transcript size
Expand All @@ -105,3 +99,16 @@ After calling the configuration endpoint above, prover can proceed to start nota

#### Signatures
Currently, both the private key (and cert) used to establish TLS connection with prover, and the private key used by notary server to sign the notarized transcript, are hardcoded PEM keys stored in this repository. Though the paths of these keys can be changed in the config to use different keys instead.

#### Authorization
An optional authorization module is available to only allow requests with valid API key attached in the authorization header. The API key whitelist path (as well as the flag to enable/disable this module) is configurable [here](./config/config.yaml).

#### Optional TLS
TLS between prover and notary is currently manually handled in the server, though it can be turned off if TLS is to be handled by an external environment, e.g. reverse proxy, cloud setup (configurable [here](./config/config.yaml)).

### Design Choices
#### Web Framework
Axum is chosen as the framework to serve HTTP and WebSocket requests from the prover clients due to its rich and well supported features, e.g. native integration with Tokio/Hyper/Tower, customizable middleware, ability to support lower level integration of TLS ([example](https://github.com/tokio-rs/axum/blob/main/examples/low-level-rustls/src/main.rs)). To simplify the notary server setup, a single Axum router is used to support both HTTP and WebSocket connections, i.e. all requests can be made to the same port of the notary server.

#### WebSocket
Axum's internal implementation of WebSocket uses [tokio_tungstenite](https://docs.rs/tokio-tungstenite/latest/tokio_tungstenite/), which provides a WebSocket struct that doesn't implement [AsyncRead](https://docs.rs/futures/latest/futures/io/trait.AsyncRead.html) and [AsyncWrite](https://docs.rs/futures/latest/futures/io/trait.AsyncWrite.html). Both these traits are required by TLSN core libraries for prover and notary. To overcome this, a [slight modification](./src/service/axum_websocket.rs) of Axum's implementation of WebSocket is used, where [async_tungstenite](https://docs.rs/async-tungstenite/latest/async_tungstenite/) is used instead so that [ws_stream_tungstenite](https://docs.rs/ws_stream_tungstenite/latest/ws_stream_tungstenite/index.html) can be used to wrap on top of the WebSocket struct to get AsyncRead and AsyncWrite implemented.
21 changes: 21 additions & 0 deletions notary-server/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::process::Command;

fn main() {
// Used to extract latest HEAD commit hash and timestamp for the /info endpoint
let output = Command::new("git")
.args(["show", "HEAD", "-s", "--format=%H,%cI"])
.output()
.expect("Git command to get commit hash and timestamp should work during build process");

let output_string =
String::from_utf8(output.stdout).expect("Git command should produce valid string output");

let (commit_hash, commit_timestamp) = output_string
.as_str()
.split_once(',')
.expect("Git commit hash and timestamp string output should be comma separated");

// Pass these 2 values as env var to the program
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", commit_hash);
println!("cargo:rustc-env=GIT_COMMIT_TIMESTAMP={}", commit_timestamp);
}
2 changes: 1 addition & 1 deletion notary-server/notary-server.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
FROM rust:bookworm AS builder
WORKDIR /usr/src/tlsn
COPY . .
RUN cd notary-server; cargo install --path .
RUN cargo install --path notary-server

FROM ubuntu:latest
WORKDIR /root/.notary-server
Expand Down
3 changes: 3 additions & 0 deletions notary-server/notary-server.Dockerfile.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@
!/tlsn
!/components

# include .git for program to get git info
!/.git

# exclude any /target folders inside the included folders above
**/target*
90 changes: 89 additions & 1 deletion notary-server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,66 @@ openapi: 3.0.0
info:
title: Notary Server
description: Notary server written in Rust to provide notarization service.
version: 0.1.0
version: 0.1.0-alpha.2

tags:
- name: General
- name: Notarization

paths:
/healthcheck:
get:
tags:
- General
description: Healthcheck endpoint
parameters:
- in: header
name: Authorization
description: Whitelisted API key if auth module is turned on
schema:
type: string
required: false
responses:
"200":
description: Ok response from server
content:
text/plain:
schema:
type: string
example: "Ok"
"401":
description: API key is invalid
content:
text/plain:
schema:
type: string
example: "Unauthorized request from prover: Invalid API key."
/info:
get:
tags:
- General
description: General information about the notary server
parameters:
- in: header
name: Authorization
description: Whitelisted API key if auth module is turned on
schema:
type: string
required: false
responses:
"200":
description: Info response from server
content:
application/json:
schema:
$ref: "#/components/schemas/InfoResponse"
"401":
description: API key is invalid
content:
text/plain:
schema:
type: string
example: "Unauthorized request from prover: Invalid API key."
/session:
post:
tags:
Expand All @@ -23,6 +77,12 @@ paths:
enum:
- "application/json"
required: true
- in: header
name: Authorization
description: Whitelisted API key if auth module is turned on
schema:
type: string
required: false
requestBody:
description: Notarization session request to server
required: true
Expand All @@ -44,6 +104,13 @@ paths:
schema:
type: string
example: "Invalid request from prover: Failed to deserialize the JSON body into the target type"
"401":
description: API key is invalid
content:
text/plain:
schema:
type: string
example: "Unauthorized request from prover: Invalid API key."
"500":
description: There was some internal error when processing
content:
Expand Down Expand Up @@ -118,6 +185,27 @@ components:
type: object
properties:
sessionId:
description: Unique ID returned from server upon calling POST /session
type: string
required:
- "sessionId"
InfoResponse:
type: object
properties:
version:
description: Current version of notary server
type: string
publicKey:
description: Public key of notary server for its notarization transcript signature
type: string
gitCommitHash:
description: The git commit hash of source code that this notary server is running
type: string
gitCommitTimestamp:
description: The git commit timestamp of source code that this notary server is running
type: string
required:
- "version"
- "publicKey"
- "gitCommitHash"
- "gitCommitTimestamp"
4 changes: 4 additions & 0 deletions notary-server/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ pub struct InfoResponse {
pub version: String,
/// Public key of the notary signing key
pub public_key: String,
/// Current git commit hash of notary-server
pub git_commit_hash: String,
/// Current git commit timestamp of notary-server
pub git_commit_timestamp: String,
}
5 changes: 5 additions & 0 deletions notary-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ pub async fn run_server(config: &NotaryServerProperties) -> Result<(), NotarySer
let public_key = std::fs::read_to_string(&config.notary_signature.public_key_pem_path)
.map_err(|err| eyre!("Failed to load notary public signing key for notarization: {err}"))?;
let version = env!("CARGO_PKG_VERSION").to_string();
let git_commit_hash = env!("GIT_COMMIT_HASH").to_string();
let git_commit_timestamp = env!("GIT_COMMIT_TIMESTAMP").to_string();

let router = Router::new()
.route(
"/healthcheck",
Expand All @@ -121,6 +124,8 @@ pub async fn run_server(config: &NotaryServerProperties) -> Result<(), NotarySer
Json(InfoResponse {
version,
public_key,
git_commit_hash,
git_commit_timestamp,
}),
)
.into_response()
Expand Down

0 comments on commit 52d6bb2

Please sign in to comment.