diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9b7b86f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,175 @@ +name: Enokiweave CI/CD + +permissions: {} # Default to no permissions + +on: + push: + branches: [ '**' ] + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + REGISTRY: docker.io + REPOSITORY: myceliumai + IMAGE_NAME: enokiweave + +jobs: + changes: + runs-on: ubuntu-latest + permissions: + pull-requests: read + contents: read + outputs: + core: ${{ steps.filter.outputs.core }} + steps: + - uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + core: + - 'src/**' + - 'Cargo.*' + - '.github/workflows/**' + - 'Dockerfile' + + check: + needs: changes + if: ${{ needs.changes.outputs.core == 'true' }} + name: Check + runs-on: ubuntu-latest + continue-on-error: true + permissions: + contents: read + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Set up cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + - name: Install LMDB + run: sudo apt-get update && sudo apt-get install -y liblmdb-dev + + - name: Run cargo fmt + run: cargo fmt --all -- --check + + - name: Run cargo clippy + run: cargo clippy -- -D warnings + + test: + needs: changes + if: ${{ needs.changes.outputs.core == 'true' }} + name: Test Suite + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Set up cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + - name: Install LMDB + run: sudo apt-get update && sudo apt-get install -y liblmdb-dev + + - name: Run cargo test + run: cargo test + + security: + name: Security Checks + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - uses: actions/checkout@v4 + - uses: aquasecurity/trivy-action@master + with: + scan-type: 'fs' + scan-ref: '.' + format: 'sarif' + output: 'trivy-results.sarif' + severity: 'CRITICAL,HIGH' + scanners: 'vuln,secret,config' + - uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: 'trivy-results.sarif' + category: 'trivy' + + build: + needs: [changes, security, check, test] + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check if should build + id: should_build + run: | + if [[ + "${{ github.event_name }}" == "push" && + "${{ github.ref }}" == "refs/heads/main" && + "${{ needs.changes.outputs.core }}" == "true" + ]]; then + echo "run=true" >> $GITHUB_OUTPUT + fi + + - uses: actions/checkout@v4 + if: steps.should_build.outputs.run == 'true' + + - uses: docker/setup-buildx-action@v3 + if: steps.should_build.outputs.run == 'true' + + - uses: docker/login-action@v3 + if: steps.should_build.outputs.run == 'true' + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - uses: docker/metadata-action@v5 + if: steps.should_build.outputs.run == 'true' + id: meta + with: + images: ${{ env.REGISTRY }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,format=long + + - uses: docker/build-push-action@v5 + if: steps.should_build.outputs.run == 'true' + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6001864 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,63 @@ +# Build stage +FROM rust:1.75-slim-bullseye as builder + +# Install system dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + pkg-config \ + liblmdb-dev \ + && rm -rf /var/lib/apt/lists/* + +# Create a new empty shell project +WORKDIR /usr/src/enokiweave + +# Copy manifests +COPY Cargo.lock Cargo.toml ./ + +# Copy source code +COPY src ./src +COPY setup ./setup + +# Build for release +RUN cargo build --release + +# Runtime stage +FROM debian:bullseye-slim + +# Install runtime dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + liblmdb0 \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user +RUN groupadd -r enoki && useradd -r -g enoki enoki + +# Create necessary directories and set permissions +RUN mkdir -p /var/lib/enokiweave /etc/enokiweave && \ + chown -R enoki:enoki /var/lib/enokiweave /etc/enokiweave + +# Copy the build artifacts from builder +COPY --from=builder /usr/src/enokiweave/target/release/enokiweave /usr/local/bin/ +COPY --from=builder /usr/src/enokiweave/target/release/build-transaction /usr/local/bin/ + +# Copy configuration files +COPY setup/example_genesis_file.json /etc/enokiweave/genesis.json +COPY setup/example_initial_peers_file.txt /etc/enokiweave/peers.txt + +# Set working directory +WORKDIR /var/lib/enokiweave + +# Switch to non-root user +USER enoki + +# Expose ports +EXPOSE 3001 + +# Add healthcheck +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3001/health || exit 1 + +# Set entrypoint +ENTRYPOINT ["enokiweave"] +CMD ["--genesis-file-path", "/etc/enokiweave/genesis.json", "--rpc_port", "3001"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..937a294 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +version: '3.8' + +services: + enokiweave: + image: ${DOCKER_HUB_USERNAME}/enokiweave:latest + ports: + - "3001:3001" + volumes: + - enokiweave-data:/var/lib/enokiweave + - ./setup/example_genesis_file.json:/etc/enokiweave/genesis.json + - ./setup/example_initial_peers_file.txt:/etc/enokiweave/peers.txt + environment: + - RUST_LOG=info + restart: unless-stopped + +volumes: + enokiweave-data: \ No newline at end of file diff --git a/src/address.rs b/src/address.rs index 8ec491c..3e7da54 100644 --- a/src/address.rs +++ b/src/address.rs @@ -1,20 +1,24 @@ use anyhow::Result; use serde::{Deserialize, Serialize}; +#[allow(dead_code)] pub const ZERO_ADDRESS: Address = Address([0; 32]); #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Copy)] pub struct Address(pub [u8; 32]); impl Address { + #[allow(dead_code)] pub fn new(data: [u8; 32]) -> Self { Self(data) } + #[allow(dead_code)] pub fn as_hex(&self) -> String { hex::encode(self.0) } + #[allow(dead_code)] pub fn from_hex(hex_address: &str) -> Result
{ let decoded = hex::decode(hex_address)?; let mut address = [0u8; 32]; diff --git a/src/main.rs b/src/main.rs index e3650ac..46f3c5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -use anyhow::{anyhow, Result}; use clap::Parser; use libp2p::futures::StreamExt; use libp2p::mdns::tokio::Tokio; @@ -17,7 +16,7 @@ use std::error::Error; use std::sync::Arc; use tcp::tokio::Transport as TokioTransport; use tokio::sync::Mutex; -use tracing::{error, info, trace, warn}; +use tracing::{info, trace, warn}; use transaction_manager::TransactionManager; use crate::rpc::run_http_rpc_server; @@ -27,7 +26,7 @@ mod rpc; mod transaction; mod transaction_manager; -const DB_NAME: &'static str = "./local_db/transaction_db"; +const DB_NAME: &str = "./local_db/transaction_db"; #[derive(NetworkBehaviour)] #[behaviour(out_event = "OutEvent")] @@ -43,13 +42,13 @@ impl From