From c8b7e2e216626b7f44608af2d5920e64cf5c56a9 Mon Sep 17 00:00:00 2001 From: ajianaz Date: Mon, 3 Aug 2026 20:04:35 +0700 Subject: [PATCH 1/2] feat: add Docker support for self-hosted deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dockerfile: multi-stage build (rust:1.85-bookworm → debian:bookworm-slim) with libssl3 runtime dep, tree-sitter feature, ~15MB final image - .dockerignore: exclude target, docs, vendored, tests, CI files - .woodpecker.yml: CI pipeline with Rust checks (fmt/clippy/test) + Docker build & push to Zot registry (registry.azfirazka.com/cora) auto_tag: develop→:develop+:sha-xxx, tag→:vX.Y.Z+:latest - docker-compose.yml: local dev/deploy config with volume mounts --- .dockerignore | 47 ++++++++++++++++++++++++++++++ .woodpecker.yml | 72 ++++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 46 +++++++++++++++++++++++++++++ docker-compose.yml | 29 +++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 .dockerignore create mode 100644 .woodpecker.yml create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bf7ffa2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,47 @@ +# Build artifacts +/target/ +debug/ +**/*.d +**/*.rlib +**/*.dll +**/*.dylib +**/*.so + +# Git +.git/ +.gitignore + +# Docs (VitePress — not needed in image) +docs/ + +# Vendored +vendored/ + +# Tests & benchmarks +tests/ +bench/ + +# CI/CD +.github/ +.woodpecker.yml + +# Environment & secrets +.env +.env.* +!.env.example + +# Editor +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Docker +Dockerfile +docker-compose.yml +.dockerignore diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..6727142 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,72 @@ +# Woodpecker CI for Cora Code. +# +# Pipeline: +# 1. Rust check / fmt / clippy / test — every push + PR. +# 2. On push to develop OR a tag → build Docker image and push to Zot. +# +# Image tags (via auto_tag): +# - push to develop → :develop + :sha- +# - tag v1.2.3 → :vX.Y.Z + :latest +# +# Required Woodpecker secrets (set in ci.ajianaz.dev → repo settings): +# ZOT_USER — registry account with push permission +# ZOT_PASS — registry password / token +# +# Required server config (Woodpecker admin, one-time): +# woodpeckerci/plugin-docker-buildx:5 must be in WOODPECKER_PLUGINS_PRIVILEGED +# (Docker-in-Docker needs privileged mode to run buildx). +# +# Pull from the registry (on the deploy host): +# docker pull registry.azfirazka.com/cora:develop + +steps: + # ── Rust checks ────────────────────────────────────────────────────── + check: + image: rust:1.85-bookworm + commands: + - cargo check --all-targets --features tree-sitter + when: + event: [push, pull_request] + + fmt: + image: rust:1.85-bookworm + commands: + - rustup component add rustfmt + - cargo fmt --all -- --check + when: + event: [push, pull_request] + + clippy: + image: rust:1.85-bookworm + commands: + - rustup component add clippy + - cargo clippy --all-targets --features tree-sitter -- -D warnings + when: + event: [push, pull_request] + + test: + image: rust:1.85-bookworm + commands: + - cargo test --features tree-sitter + when: + event: [push, pull_request] + + # ── Docker build & push to Zot ────────────────────────────────────── + docker: + image: woodpeckerci/plugin-docker-buildx:5 + settings: + repo: registry.azfirazka.com/cora + registry: registry.azfirazka.com + username: + from_secret: ZOT_USER + password: + from_secret: ZOT_PASS + dockerfile: Dockerfile + no_cache: true + auto_tag: true + auto_tag_suffix: sha-${CI_COMMIT_SHA:0:7} + privileged: true + when: + - branch: develop + event: push + - event: tag diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5022f5f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +# Cora Code — Docker image for self-hosted deployment. +# +# Multi-stage build: +# 1. Builder: rust:1.85 (glibc) — compile with tree-sitter + LTO +# 2. Runtime: debian:bookworm-slim — minimal glibc base, ~15MB final image +# +# Usage: +# docker build -t cora . +# docker run --rm cora --version +# docker run --rm -e CORA_API_KEY=sk-xxx -v $(pwd):/workspace cora review --staged +# docker run --rm cora mcp serve # MCP server (stdio) + +# ── Builder ──────────────────────────────────────────────────────────── +FROM rust:1.85-bookworm AS builder + +RUN apt-get update && apt-get install -y --no-install-recommends \ + pkg-config \ + libssl-dev \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Cache dependencies — copy only Cargo files first. +COPY Cargo.toml Cargo.lock ./ +RUN mkdir -p src && echo "fn main() {}" > src/main.rs +RUN cargo build --release --features tree-sitter 2>/dev/null || true + +# Copy real source and rebuild (cached deps reused). +COPY src/ src/ +RUN touch src/main.rs && cargo build --release --features tree-sitter + +# ── Runtime ───────────────────────────────────────────────────────────── +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + libssl3 \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /app/target/release/cora /usr/local/bin/cora + +# Default workdir for review targets. +WORKDIR /workspace + +ENTRYPOINT ["cora"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..29d1237 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +# Cora Code — local dev / single-host deploy via Docker Compose. +# +# Pulls prebuilt image from the self-hosted Zot registry. +# For local builds: docker compose up --build +# +# Usage: +# docker compose pull && docker compose run --rm cora --version +# docker compose run --rm -e CORA_API_KEY=sk-xxx cora review --staged +# docker compose run --rm cora mcp serve +# +# Volumes: +# ./data:/data — persistent storage (cora index DB, config) +# .:/workspace — mount repo for code review (development) + +services: + cora: + image: registry.azfirazka.com/cora:${CORA_TAG:-develop} + build: + context: . + dockerfile: Dockerfile + container_name: cora + working_dir: /workspace + volumes: + - ./data:/data + - .:/workspace + environment: + - CORA_HOME=/data + # Default: show version (override via docker compose run) + command: ["--version"] From 724f875229a6deb680a321f9a03c7359188627d9 Mon Sep 17 00:00:00 2001 From: ajianaz Date: Mon, 3 Aug 2026 20:06:19 +0700 Subject: [PATCH 2/2] fix(docker): run as non-root user for security --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index 5022f5f..e849512 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,6 +40,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY --from=builder /app/target/release/cora /usr/local/bin/cora +# Create non-root user for running cora. +RUN groupadd --gid 1000 cora && \ + useradd --uid 1000 --gid cora --create-home --shell /bin/sh cora + +USER cora + # Default workdir for review targets. WORKDIR /workspace