Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Publish Docker Image

on:
# Trigger directly on version tags so github.ref carries the tag context
# reliably (avoids the workflow_run ref scoping problem).
push:
tags:
- "v*.*.*"
# Keep manual dispatch for emergency re-publishes
workflow_dispatch:
inputs:
tag:
description: "Image tag to publish (e.g. v0.4.0)"
required: true

env:
REGISTRY_DOCKERHUB: docker.io
REGISTRY_GHCR: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# Required for OIDC JWT (used by provenance attestation)
id-token: write
# Required to write attestation manifests back to GHCR
attestations: write

steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
# Use the manual workflow_dispatch `tag` input when provided,
# otherwise fall back to the ref that triggered the workflow.
ref: ${{ github.event.inputs.tag || github.ref }}

# QEMU is required for cross-compiling to linux/arm64 on an amd64 runner.
# Matches the aarch64 targets in your dist-workspace.toml.
- name: Set up QEMU
uses: docker/setup-qemu-action@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

# ── Registry logins ──────────────────────────────────────────────────
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY_GHCR }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# ── Image metadata ───────────────────────────────────────────────────
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY_DOCKERHUB }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY_GHCR }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# FIX: use the built-in shorthand instead of the broken string literal
type=raw,value=latest,enable={{is_default_branch}}
# Prevent metadata-action from auto-adding a redundant 'latest' tag
# on top of the one we control above.
flavor: |
latest=false

# ── Build & push ─────────────────────────────────────────────────────
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v7
with:
context: .
# Build for both architectures your release targets.
# Remove linux/arm64 if your CI minutes are constrained — arm64
# emulation via QEMU is significantly slower.
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Attach OCI-standard provenance using the OIDC token.
# This is what id-token: write is actually for.
provenance: true
sbom: true
cache-from: type=gha
cache-to: type=gha,mode=max

# ── Attestations (supply-chain security) ─────────────────────────────
# Writes a signed SLSA provenance attestation to GHCR.
# Requires attestations: write + id-token: write permissions above.
# Note: as of v4, this action is a wrapper over actions/attest.
# New projects can use actions/attest directly, but this remains valid.
- name: Attest GHCR image
uses: actions/attest-build-provenance@v4 # latest: v4
with:
subject-name: ${{ env.REGISTRY_GHCR }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
43 changes: 43 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Base stage: install cargo-chef
FROM rust:slim-bookworm AS chef
RUN cargo install cargo-chef
WORKDIR /app

# Planner stage: only needs manifests to generate recipe.json
FROM chef AS planner
COPY Cargo.toml Cargo.lock ./
RUN cargo chef prepare --recipe-path recipe.json

# Builder stage: compile dependencies then source
FROM chef AS builder
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y \
build-essential \
libssl-dev \
pkg-config

COPY --from=planner /app/recipe.json recipe.json
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo chef cook --release --recipe-path recipe.json

COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo build --release && \
mkdir /out && \
cp /app/target/release/amdb /out/amdb

FROM gcr.io/distroless/cc-debian12 AS runtime

COPY --chown=nonroot:nonroot --from=builder /out/amdb /usr/local/bin/amdb

USER nonroot
WORKDIR /data

LABEL org.opencontainers.image.source="https://github.com/BETAER-08/amdb"
LABEL org.opencontainers.image.license="MIT"

ENTRYPOINT ["amdb"]
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ If you have the Rust toolchain installed:
cargo install amdb
```

### Option 3: Docker
You can run `amdb` directly from a Docker container without installing Rust or dependencies.

```bash
# Pull the image
docker pull ghcr.io/betaer-08/amdb:latest

# Run amdb (mount your current directory to /data)
docker run --rm -v $(pwd):/data ghcr.io/betaer-08/amdb init
docker run --rm -v $(pwd):/data ghcr.io/betaer-08/amdb generate
```

**Note:** The container runs as a non-root user. If you encounter permission issues with the generated files, you can run the container with your current user ID:

```bash
docker run --rm -u $(id -u):$(id -g) -v $(pwd):/data ghcr.io/betaer-08/amdb init
```

**Pro Tip:** To persist the embedding models and avoid re-downloading them on every run, you can mount a volume to the `nonroot` user's cache directory:

```bash
docker run --rm -v $(pwd):/data -v $(pwd)/.cache:/home/nonroot/.cache ghcr.io/betaer-08/amdb generate
```

## 🚀 Quick Start

### 1. Initialize Project
Expand Down