Skip to content

Commit

Permalink
feat: add proto-file based code gen
Browse files Browse the repository at this point in the history
  • Loading branch information
j-lanson committed Aug 12, 2024
1 parent edab626 commit 39dbda2
Show file tree
Hide file tree
Showing 8 changed files with 749 additions and 3 deletions.
587 changes: 587 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ COPY scripts/ scripts/

RUN set -eux && \
apt-get update && \
apt-get install -y npm git && \
apt-get install -y npm git protobuf-compiler && \
apt-get clean && \
npm install -g [email protected] --no-audit --no-fund && \
adduser --disabled-password hc_user && \
Expand Down
4 changes: 4 additions & 0 deletions hipcheck/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ http = "1.1.0"
dialoguer = "0.11.0"
tabled = "0.15.0"
fs_extra = "1.3.0"
tonic = "0.12.1"
prost = "0.13.1"
tonic-build = { version = "0.12.1", features = ["prost"] }

# Exactly matching the version of rustls used by ureq
# Get rid of default features since we don't use the AWS backed crypto provider (we use ring).
Expand All @@ -102,6 +105,7 @@ features = [

[build-dependencies]
anyhow = "1.0.86"
tonic-build = "0.12.1"
which = { version = "6.0.1", default-features = false }

[dev-dependencies]
Expand Down
7 changes: 5 additions & 2 deletions hipcheck/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ use std::path::Path;
use std::process::Command;
use which::which;

fn main() {
fn main() -> Result<()> {
let repo_dir = env!("CARGO_MANIFEST_DIR", "can't find Cargo manifest directory");
let head = get_head_commit(repo_dir).unwrap_or_default();

println!("cargo:rustc-env=HC_HEAD_COMMIT={}", head)
tonic_build::compile_protos("proto/hipcheck.proto")?;

println!("cargo:rustc-env=HC_HEAD_COMMIT={}", head);
Ok(())
}

fn get_head_commit<P: AsRef<Path>>(path: P) -> Result<String> {
Expand Down
145 changes: 145 additions & 0 deletions hipcheck/proto/hipcheck.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
syntax = "proto3";

package hipcheck;

service Plugin {
/**
* Get schemas for all supported queries by the plugin.
*
* This is used by Hipcheck to validate that:
*
* - The plugin supports a default query taking a `target` type if used
* as a top-level plugin in the user's policy file.
* - That requests sent to the plugin and data returned by the plugin
* match the schema during execution.
*/
rpc GetQuerySchemas (Empty) returns (stream Schema);

/**
* Hipcheck sends all child nodes for the plugin from the user's policy
* file to configure the plugin.
*/
rpc SetConfiguration (Configuration) returns (ConfigurationResult);

/**
* Get the default policy for a plugin, which may additionally depend on
* the plugin's configuration.
*/
rpc GetDefaultPolicyExpression (Empty) returns (PolicyExpression);

/**
* Open a bidirectional streaming RPC to enable a request/response
* protocol between Hipcheck and a plugin, where Hipcheck can issue
* queries to the plugin, and the plugin may issue queries to _other_
* plugins through Hipcheck.
*
* Queries are cached by the publisher name, plugin name, query name,
* and key, and if a match is found for those four values, then
* Hipcheck will respond with the cached result of that prior matching
* query rather than running the query again.
*/
rpc InitiateQueryProtocol (stream Query) returns (stream Query);
}

message Configuration {
// JSON string containing configuration data expected by the plugin,
// pulled from the user's policy file.
string configuration = 1;
}

enum ConfigurationStatus {
// An unknown error occured.
ERROR_UNKNOWN = 0;
// No error; the operation was successful.
ERROR_NONE = 1;
// The user failed to provide a required configuration item.
ERROR_MISSING_REQUIRED_CONFIGURATION = 2;
// The user provided a configuration item whose name was not recognized.
ERROR_UNRECOGNIZED_CONFIGURATION = 3;
// The user provided a configuration item whose value is invalid.
ERROR_INVALID_CONFIGURATION_VALUE = 4;
}

message ConfigurationResult {
// The status of the configuration call.
ConfigurationStatus status = 1;
// An optional error message, if there was an error.
string message = 2;
}

message PolicyExpression {
// A policy expression, if the plugin has a default policy.
// This MUST be filled in with any default values pulled from the plugin's
// configuration. Hipcheck will only request the default policy _after_
// configuring the plugin.
string policy_expression = 1;
}

message Schema {
// The name of the query being described by the schemas provided.
//
// If either the key and/or output schemas result in a message which is
// too big, they may be chunked across multiple replies in the stream.
// Replies with matching query names should have their fields concatenated
// in the order received to reconstruct the chunks.
string query_name = 1;

// The key schema, in JSON Schema format.
string key_schema = 2;

// The output schema, in JSON Schema format.
string output_schema = 3;
}

enum QueryState {
// Something has gone wrong.
QUERY_UNSPECIFIED = 0;

// We are submitting a new query.
QUERY_SUBMIT = 1;

// We are replying to a query and expect more chunks.
QUERY_REPLY_IN_PROGRESS = 2;

// We are closing a reply to a query. If a query response is in one chunk,
// just send this. If a query is in more than one chunk, send this with
// the last message in the reply. This tells the receiver that all chunks
// have been received.
QUERY_REPLY_COMPLETE = 3;
}

message Query {
// The ID of the request, used to associate requests and replies.
// Odd numbers = initiated by `hc`.
// Even numbers = initiated by a plugin.
int32 id = 1;

// The state of the query, indicating if this is a request or a reply,
// and if it's a reply whether it's the end of the reply.
QueryState state = 2;

// Publisher name and plugin name, when sent from Hipcheck to a plugin
// to initiate a fresh query, are used by the receiving plugin to validate
// that the query was intended for them.
//
// When a plugin is making a query to another plugin through Hipcheck, it's
// used to indicate the destination plugin, and to indicate the plugin that
// is replying when Hipcheck sends back the reply.
string publisher_name = 3;
string plugin_name = 4;

// The name of the query being made, so the responding plugin knows what
// to do with the provided data.
string query_name = 5;

// The key for the query, as a JSON object. This is the data that Hipcheck's
// incremental computation system will use to cache the response.
string key = 6;

// The response for the query, as a JSON object. This will be cached by
// Hipcheck for future queries matching the publisher name, plugin name,
// query name, and key.
string output = 7;
}

message Empty {}
1 change: 1 addition & 0 deletions hipcheck/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hipcheck.rs
5 changes: 5 additions & 0 deletions hipcheck/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod git2_log_shim;
mod git2_rustls_transport;
mod log_bridge;
mod metric;
mod plugin;
mod report;
mod session;
mod setup;
Expand All @@ -24,6 +25,10 @@ mod target;
mod util;
mod version;

pub mod hipcheck {
include!(concat!(env!("OUT_DIR"), "/hipcheck.rs"));
}

use crate::analysis::report_builder::build_report;
use crate::analysis::report_builder::AnyReport;
use crate::analysis::report_builder::Format;
Expand Down
1 change: 1 addition & 0 deletions site/content/install/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ will need to build Hipcheck from source.
To build Hipcheck from source, you'll need:

- A Rust toolchain: see the [official Rust installation instructions](https://www.rust-lang.org/tools/install)
- The `protoc` compiler: see the [installation instructions](https://grpc.io/docs/protoc-installation/)

If you _only_ want to build from source without configuring the build in any
way, you can use `cargo install` to install Hipcheck into a Cargo0-specific
Expand Down

0 comments on commit 39dbda2

Please sign in to comment.