diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..0e61d5a2
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+.github
+.vscode
+benches
+temp
+tests
+renovate.json
+temp
\ No newline at end of file
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644
index 00000000..666fbd32
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,109 @@
+name: build
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ release:
+ types: [created]
+
+jobs:
+ dockerize:
+ name: dockerize
+ runs-on: ubuntu-22.04
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+
+ - name: configure eqemu
+ uses: docker/setup-qemu-action@v3
+ with:
+ platforms: "linux/arm64,linux/amd64"
+
+ - name: configure docker buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: login to docker registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: build docker images
+ timeout-minutes: 15
+ id: docker-bake
+ uses: docker/bake-action@v4
+ env:
+ DOCKER_REGISTRY: ghcr.io/${{ github.repository }}/
+ COMMIT_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
+ PUBLISH_VERSION: ${{ github.event_name == 'release' && github.event.release.tag_name || '' }}
+ PUBLISH_LATEST: ${{ github.event_name == 'release' && !github.event.release.prerelease && '1' || '' }}
+ with:
+ workdir: .
+ provenance: false
+ push: true
+ files: docker/bake.hcl
+ targets: build
+ set: |
+ *.cache-from=type=gha,scope=build
+ *.cache-to=type=gha,scope=build,mode=max
+
+ - name: docker details pr comment
+ uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ github.event_name == 'pull_request' }}
+ with:
+ message: |
+ 🐋 This PR was built and pushed to the following [Docker images](https://github.com/the-guild-org/conductor-t2/pkgs/container/conductor-t2%2Fconductor):
+
+
+ Docker Bake metadata
+
+ ```json
+ ${{ steps.docker-bake.outputs.metadata }}
+ ```
+
+
+ binary:
+ name: compile binary (${{ matrix.platform.target }})
+ strategy:
+ matrix:
+ platform:
+ - os: ubuntu-22.04
+ target: x86_64-unknown-linux-gnu
+
+ - os: ubuntu-22.04
+ target: aarch64-unknown-linux-gnu
+
+ runs-on: ${{ matrix.platform.os }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+
+ - name: build binary
+ uses: houseabsolute/actions-rust-cross@v0
+ with:
+ command: build
+ target: ${{ matrix.platform.target }}
+ args: "--locked --release"
+ strip: true
+
+ - uses: actions/upload-artifact@v3
+ if: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
+ name: upload binary artifact
+ with:
+ name: conductor-${{ matrix.platform.target }}
+ path: target/${{ matrix.platform.target }}/release/conductor
+
+ - name: upload binaries to release
+ if: ${{ github.event_name == 'release' }}
+ uses: svenstaro/upload-release-action@v2
+ with:
+ repo_token: ${{ secrets.GITHUB_TOKEN }}
+ file: target/${{ matrix.platform.target }}/release/conductor
+ asset_name: conductor-${{ matrix.platform.target }}
+ tag: ${{ github.ref }}
+ overwrite: true
diff --git a/Cargo.lock b/Cargo.lock
index 38e3327c..2e73c815 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -535,6 +535,7 @@ dependencies = [
"hyper",
"hyper-tls",
"mime",
+ "openssl",
"serde",
"serde_json",
"serde_yaml",
@@ -1566,6 +1567,15 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+[[package]]
+name = "openssl-src"
+version = "111.27.0+1.1.1v"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06e8f197c82d7511c5b014030c9b1efeda40d7d5f99d23b4ceed3524a5e63f02"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "openssl-sys"
version = "0.9.91"
@@ -1574,6 +1584,7 @@ checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac"
dependencies = [
"cc",
"libc",
+ "openssl-src",
"pkg-config",
"vcpkg",
]
diff --git a/Cargo.toml b/Cargo.toml
index bdc7fa77..3e927533 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,6 +28,7 @@ url = "2.4.1"
graphql-parser = "0.4.0"
futures = "0.3.28"
axum-test = "12.5.0"
+openssl = { version = "0.10", features = ["vendored"] }
[dev-dependencies]
criterion = { version = "0.5.1", features = ["html_reports"] }
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 00000000..9233d64e
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,28 @@
+FROM rust:1.72.1 as builder
+
+WORKDIR /usr/src/conductor
+
+COPY Cargo.toml Cargo.lock ./
+# This is a trick to get the most out of Docker's caching mechanism in GH Actions.
+RUN mkdir src
+RUN mkdir benches
+RUN echo 'fn main() { println!("Dummy!"); }' > ./src/main.rs
+RUN echo 'fn main() { println!("Dummy!"); }' > ./src/lib.rs
+RUN echo 'fn main() { println!("Dummy!"); }' > ./benches/bench.rs
+# We are only building the dependencies here, with a dummy file, this compiles all dependencies code only.
+RUN cargo build --release --bin conductor
+
+# Now we can remove the dummy code, copy the actual code and compile the user code.
+# This ensures that building dependencies and the actual code are cached separately.
+RUN rm -rf src
+COPY src src
+RUN touch src/main.rs src/lib.rs
+RUN cargo build --release --bin conductor
+
+FROM debian:12.1
+
+RUN apt-get update -y && apt-get install -y ca-certificates
+
+COPY --from=builder /usr/src/conductor/target/release/conductor /usr/local/bin/conductor
+
+CMD conductor
diff --git a/docker/bake.hcl b/docker/bake.hcl
new file mode 100644
index 00000000..0b34e5fe
--- /dev/null
+++ b/docker/bake.hcl
@@ -0,0 +1,60 @@
+variable "DOCKER_REGISTRY" {
+ default = ""
+}
+
+variable "COMMIT_SHA" {
+ default = "local"
+}
+
+variable "PUBLISH_VERSION" {
+ # Can be "" or the actual version to publish
+ default = ""
+}
+
+variable "PUBLISH_LATEST" {
+ # Can be "" or "1"
+ default = ""
+}
+
+function "maybe_latest_image_tag" {
+ params = [name]
+ result = equal("1", PUBLISH_LATEST) ? "${DOCKER_REGISTRY}${name}:latest" : ""
+}
+
+function "maybe_version_tag" {
+ params = [name]
+ result = notequal("", PUBLISH_VERSION) ? "${DOCKER_REGISTRY}${name}:${PUBLISH_VERSION}" : ""
+}
+
+function "commit_id_tag" {
+ params = [name, tag]
+ result = notequal("", tag) ? "${DOCKER_REGISTRY}${name}:${tag}" : ""
+}
+
+target "conductor" {
+ context = "./"
+ dockerfile = "./docker/Dockerfile"
+ tags = [
+ commit_id_tag("conductor", COMMIT_SHA),
+ maybe_latest_image_tag("conductor"),
+ maybe_version_tag("conductor"),
+ ]
+ labels = {
+ "org.opencontainers.image.source" = "https://github.com/the-guild-org/conductor-t2",
+ "org.opencontainers.image.authors": "The Guild ",
+ "org.opencontainers.image.vendor": "The Guild",
+ "org.opencontainers.image.url": "https://the-guild.dev/graphql/gateway",
+ "org.opencontainers.image.docs": "https://the-guild.dev/graphql/gateway",
+ "org.opencontainers.image.version": PUBLISH_VERSION,
+ "org.opencontainers.image.revision": COMMIT_SHA,
+ "org.opencontainers.image.licenses": "MIT",
+ "org.opencontainers.image.title": "Conductor",
+ "org.opencontainers.image.description": "Conductor is a robust GraphQL Gateway."
+ }
+}
+
+group "build" {
+ targets = [
+ "conductor"
+ ]
+}
diff --git a/src/endpoint/graphiql.rs b/src/endpoint/graphiql.rs
index f64b9e35..55b69bf6 100644
--- a/src/endpoint/graphiql.rs
+++ b/src/endpoint/graphiql.rs
@@ -13,9 +13,9 @@ pub struct GraphiQLSource {
const YOGA_GRAPHIQL_VERSION: &str = "4.1.1";
impl GraphiQLSource {
- pub fn new(endpoint: &String) -> GraphiQLSource {
+ pub fn new(endpoint: &str) -> GraphiQLSource {
GraphiQLSource {
- endpoint: endpoint.clone(),
+ endpoint: endpoint.to_string(),
query: String::from(""),
headers_editor_enabled: true,
}
diff --git a/src/graphql_utils.rs b/src/graphql_utils.rs
index 1db8afd8..cef355c6 100644
--- a/src/graphql_utils.rs
+++ b/src/graphql_utils.rs
@@ -37,9 +37,9 @@ pub struct GraphQLError {
}
impl GraphQLError {
- pub fn new(message: &String) -> Self {
+ pub fn new(message: &str) -> Self {
GraphQLError {
- message: message.clone(),
+ message: message.to_string(),
extensions: None,
}
}
@@ -87,7 +87,7 @@ pub struct GraphQLResponse {
}
impl GraphQLResponse {
- pub fn new_error(error: &String) -> Self {
+ pub fn new_error(error: &str) -> Self {
GraphQLResponse {
data: None,
errors: Some(vec![GraphQLError::new(error)]),
diff --git a/src/lib.rs b/src/lib.rs
index bba6c044..02674890 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,10 +89,8 @@ pub async fn http_request_handler(
}
if flow_ctx.has_failed_extraction() {
- return GraphQLResponse::new_error(
- &"failed to extract GraphQL request from HTTP request".to_string(),
- )
- .into_response(StatusCode::BAD_REQUEST);
+ return GraphQLResponse::new_error("failed to extract GraphQL request from HTTP request")
+ .into_response(StatusCode::BAD_REQUEST);
}
// Execute plugins on the GraphQL request.
diff --git a/src/plugins/http_get_plugin.rs b/src/plugins/http_get_plugin.rs
index c68107ae..1ec5d20b 100644
--- a/src/plugins/http_get_plugin.rs
+++ b/src/plugins/http_get_plugin.rs
@@ -45,10 +45,8 @@ impl Plugin for HttpGetPlugin {
if let Some(gql_req) = &ctx.downstream_graphql_request {
if gql_req.is_mutation() {
ctx.short_circuit(
- GraphQLResponse::new_error(
- &"mutations are not allowed over GET".to_string(),
- )
- .into_response(StatusCode::METHOD_NOT_ALLOWED),
+ GraphQLResponse::new_error("mutations are not allowed over GET")
+ .into_response(StatusCode::METHOD_NOT_ALLOWED),
);
}
}