From f678b4c3e135abfdc8b02c99798520647de8d84e Mon Sep 17 00:00:00 2001 From: Chris Baugus Date: Tue, 1 Jul 2025 13:24:55 -0500 Subject: [PATCH 1/7] send JSON payload in load test request --- README.md | 22 ++++++++++++++++++++++ src/main.rs | 28 ++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2b1320f..f099b3c 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,28 @@ docker run --rm \ cbaugus/rust-loadtester:latest ``` +### Sending a JSON Payload (e.g., for Login Endpoints) + +You can configure the tool to send a JSON body with each POST request (for example, to test login endpoints that expect a JSON payload). This is controlled by two environment variables: + +* `SEND_JSON` (Optional, default: false): Set to `"true"` to enable sending a JSON payload in the body of each POST request. +* `JSON_PAYLOAD` (Required if `SEND_JSON=true`): The JSON string to send as the request body. + +If `SEND_JSON` is not set or is not `"true"`, requests will be sent without a body. + +**Example:** + +```bash +docker run --rm \ + -e TARGET_URL="https://your-service.com/login" \ + -e SEND_JSON="true" \ + -e JSON_PAYLOAD='{"username":"testuser","password":"testpass"}' \ + -e NUM_CONCURRENT_TASKS="20" \ + -e TEST_DURATION="10m" \ + -e LOAD_MODEL_TYPE="Concurrent" \ + cbaugus/rust-loadtester:latest +``` + ### Using mTLS (Mutual TLS) To enable mTLS, you need to provide both a client certificate and a client private key. The private key **must be in PKCS#8 format**. diff --git a/src/main.rs b/src/main.rs index a8b0c50..f78aaf7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -394,6 +394,15 @@ async fn main() -> Result<(), Box> { let url = env::var("TARGET_URL") .expect("TARGET_URL environment variable must be set"); + // --- NEW: Optionally send JSON payload --- + let send_json = env::var("SEND_JSON").unwrap_or_else(|_| "false".to_string()).to_lowercase() == "true"; + let json_payload = if send_json { + Some(env::var("JSON_PAYLOAD") + .expect("JSON_PAYLOAD environment variable must be set when SEND_JSON=true")) + } else { + None + }; + let num_concurrent_tasks_str = env::var("NUM_CONCURRENT_TASKS") .unwrap_or_else(|_| "10".to_string()); let num_concurrent_tasks: usize = num_concurrent_tasks_str.parse() @@ -529,8 +538,10 @@ async fn main() -> Result<(), Box> { let url_clone = url.to_string(); let overall_test_duration_clone = overall_test_duration.clone(); let start_time_clone = start_time.clone(); - let load_model_clone = load_model.clone(); // Clone load model for each task - let num_concurrent_tasks_clone = num_concurrent_tasks.clone(); // Clone for use in worker task + let load_model_clone = load_model.clone(); + let num_concurrent_tasks_clone = num_concurrent_tasks.clone(); + let send_json_clone = send_json; + let json_payload_clone = json_payload.clone(); let handle = tokio::spawn(async move { loop { @@ -559,13 +570,22 @@ async fn main() -> Result<(), Box> { let request_start_time = time::Instant::now(); // Start timer - match client_clone.get(&url_clone).send().await { + // --- CHANGED: Conditionally send POST with or without JSON --- + let req = client_clone.post(&url_clone); + let req = if send_json_clone { + req.header("Content-Type", "application/json") + .body(json_payload_clone.clone().unwrap()) + } else { + req + }; + + match req.send().await { Ok(response) => { let status = response.status().as_u16().to_string(); REQUEST_STATUS_CODES.with_label_values(&[&status]).inc(); + // Do not save the JWT token, just drop the response }, Err(e) => { - // For network errors, we might want a specific label REQUEST_STATUS_CODES.with_label_values(&["error"]).inc(); eprintln!("Task {}: Request to {} failed: {}", i, url_clone, e); } From 35aa96006dbba7d32030fbde88dd0730786b0972 Mon Sep 17 00:00:00 2001 From: Chris Baugus Date: Tue, 1 Jul 2025 13:32:03 -0500 Subject: [PATCH 2/7] run rust as non-root, and add provenance to cicd --- .github/workflows/build-cicd.yaml | 2 +- Dockerfile | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-cicd.yaml b/.github/workflows/build-cicd.yaml index 2041fc9..5d186a1 100644 --- a/.github/workflows/build-cicd.yaml +++ b/.github/workflows/build-cicd.yaml @@ -39,6 +39,7 @@ jobs: #platforms: linux/amd64,linux/arm64 # Add linux/arm64 for M3/ARM CPUs push: true tags: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }} + provenance: true # #Deploy @@ -59,4 +60,3 @@ jobs: # NOMAD_TOKEN: ${{ secrets.NOMAD_TOKEN }} # run: | # nomad job run -address=${NOMAD_ADDR} -token=${NOMAD_TOKEN} ./api.nomad.hcl -# diff --git a/Dockerfile b/Dockerfile index c5a9c8a..af27f55 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,12 +16,20 @@ RUN apt-get update \ # Set the working directory WORKDIR /usr/local/bin +# Add a non-root user and group +RUN groupadd -r appuser && useradd -r -g appuser appuser + # Copy the compiled binary from the builder stage COPY --from=builder /usr/local/cargo/bin/rust_loadtest /usr/local/bin/rust_loadtest +# Set ownership of the binary to the non-root user +RUN chown appuser:appuser /usr/local/bin/rust_loadtest + # Expose the Prometheus metrics port EXPOSE 9090 +# Switch to non-root user +USER appuser + # Command to run the application when the container starts CMD ["/usr/local/bin/rust_loadtest"] - From 6a22a560d3643b54847f82499a791eb10816e7f4 Mon Sep 17 00:00:00 2001 From: Chris Baugus Date: Tue, 1 Jul 2025 13:37:48 -0500 Subject: [PATCH 3/7] Generate SBOM with Syft --- .github/workflows/build-cicd.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build-cicd.yaml b/.github/workflows/build-cicd.yaml index 5d186a1..6093e38 100644 --- a/.github/workflows/build-cicd.yaml +++ b/.github/workflows/build-cicd.yaml @@ -41,6 +41,19 @@ jobs: tags: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }} provenance: true + - name: Generate SBOM with Syft + uses: anchore/sbom-action@v0.15.10 + with: + image: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }} + format: cyclonedx-json + output-file: sbom.cyclonedx.json + + - name: Upload SBOM artifact + uses: actions/upload-artifact@v4 + with: + name: sbom + path: sbom.cyclonedx.json + # #Deploy # deploy: From ad48a153c08c3fb145c70859bdd24a882315f68f Mon Sep 17 00:00:00 2001 From: Chris Baugus Date: Tue, 1 Jul 2025 13:45:18 -0500 Subject: [PATCH 4/7] Generate SBOM with Syft --- .github/workflows/build-cicd.yaml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-cicd.yaml b/.github/workflows/build-cicd.yaml index 6093e38..64a3eee 100644 --- a/.github/workflows/build-cicd.yaml +++ b/.github/workflows/build-cicd.yaml @@ -30,16 +30,15 @@ jobs: echo "TAG=${BRANCH_NAME}" >> $GITHUB_OUTPUT fi - - name: Build and push Docker image + - name: Build Docker image (no push) uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile platforms: linux/amd64 - #platforms: linux/amd64,linux/arm64 # Add linux/arm64 for M3/ARM CPUs - push: true tags: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }} provenance: true + push: false - name: Generate SBOM with Syft uses: anchore/sbom-action@v0.15.10 @@ -54,6 +53,16 @@ jobs: name: sbom path: sbom.cyclonedx.json + - name: Push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64 + tags: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }} + provenance: true + push: true + # #Deploy # deploy: From 6384a8eef5c242462625d428c020caebbca041f9 Mon Sep 17 00:00:00 2001 From: Chris Baugus Date: Tue, 1 Jul 2025 13:48:09 -0500 Subject: [PATCH 5/7] Generate SBOM with Syft --- .github/workflows/build-cicd.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-cicd.yaml b/.github/workflows/build-cicd.yaml index 64a3eee..6936997 100644 --- a/.github/workflows/build-cicd.yaml +++ b/.github/workflows/build-cicd.yaml @@ -40,12 +40,14 @@ jobs: provenance: true push: false + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + - name: Generate SBOM with Syft - uses: anchore/sbom-action@v0.15.10 - with: - image: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }} - format: cyclonedx-json - output-file: sbom.cyclonedx.json + run: | + syft --version + syft "cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }}" -o cyclonedx-json > sbom.cyclonedx.json - name: Upload SBOM artifact uses: actions/upload-artifact@v4 From 1f978548f46c06c7fd88e507110077155c2de7c7 Mon Sep 17 00:00:00 2001 From: Chris Baugus Date: Tue, 1 Jul 2025 13:55:05 -0500 Subject: [PATCH 6/7] cleanup cicd --- .github/workflows/build-cicd.yaml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/build-cicd.yaml b/.github/workflows/build-cicd.yaml index 6936997..da0fb4f 100644 --- a/.github/workflows/build-cicd.yaml +++ b/.github/workflows/build-cicd.yaml @@ -65,22 +65,3 @@ jobs: provenance: true push: true - -# #Deploy -# deploy: -# needs: build -# runs-on: ubuntu-latest -# steps: -# - name: Checkout code -# uses: actions/checkout@v2 -# -# - name: Install nomad (cross-platform) -# uses: gacts/install-nomad@v1.2.0 -# -# -# - name: Deploy Nomad Job -# env: -# NOMAD_ADDR: ${{ secrets.NOMAD_ADDR }} -# NOMAD_TOKEN: ${{ secrets.NOMAD_TOKEN }} -# run: | -# nomad job run -address=${NOMAD_ADDR} -token=${NOMAD_TOKEN} ./api.nomad.hcl From 164da4e93f2adfba283310fdfbe1f8fc8bc19eb5 Mon Sep 17 00:00:00 2001 From: cbaugus Date: Tue, 1 Jul 2025 14:23:01 -0500 Subject: [PATCH 7/7] resolve cve from debian --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index af27f55..b1bd591 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,10 +5,10 @@ RUN cargo install --path . # --- Stage 2: Create the final, smaller runtime image --- # Use a minimal base image for the final runtime -FROM debian:bullseye-slim +FROM ubuntu:latest RUN apt-get update \ && apt-get install -y --no-install-recommends \ - libssl1.1 \ + libssl3 \ ca-certificates \ && apt-get clean \ && rm -rf /var/lib/apt/lists/*