diff --git a/.dockerignore b/.dockerignore index d632da5ea..0d9294f54 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ .git .gitignore +.github/ build/ .picoclaw/ config/ @@ -8,3 +9,7 @@ config/ *.md LICENSE assets/ +doc/ +docker-compose.yml +Dockerfile.goreleaser +.goreleaser.yaml diff --git a/Dockerfile b/Dockerfile index 0360cfda6..fe3482ae5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # ============================================================ FROM golang:1.26.0-alpine AS builder -RUN apk add --no-cache git make +RUN apk add --no-cache git make ca-certificates tzdata WORKDIR /src @@ -13,31 +13,35 @@ RUN go mod download # Copy source and build COPY . . -RUN make build +RUN CGO_ENABLED=0 make build GOFLAGS="-v -trimpath" LDFLAGS='-ldflags "-s -w"' + +# Create non-root user entry for scratch +RUN echo "picoclaw:x:10001:10001::/home/picoclaw:/sbin/nologin" > /tmp/passwd && \ + echo "picoclaw:x:10001:" > /tmp/group && \ + mkdir -p /home/picoclaw # ============================================================ -# Stage 2: Minimal runtime image +# Stage 2: Minimal runtime image (scratch) # ============================================================ -FROM alpine:3.23 +FROM scratch -RUN apk add --no-cache ca-certificates tzdata curl +# Copy user/group files for non-root execution +COPY --from=builder /tmp/passwd /etc/passwd +COPY --from=builder /tmp/group /etc/group -# Health check -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD wget -q --spider http://localhost:18790/health || exit 1 +# Copy SSL certs and timezone data +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo + +# Copy home directory (owned by picoclaw user) +COPY --from=builder --chown=10001:10001 /home/picoclaw /home/picoclaw # Copy binary COPY --from=builder /src/build/picoclaw /usr/local/bin/picoclaw -# Create non-root user and group -RUN addgroup -g 1000 picoclaw && \ - adduser -D -u 1000 -G picoclaw picoclaw +USER 10001 -# Switch to non-root user -USER picoclaw - -# Run onboard to create initial directories and config -RUN /usr/local/bin/picoclaw onboard +EXPOSE 18790 ENTRYPOINT ["picoclaw"] CMD ["gateway"] diff --git a/Dockerfile.goreleaser b/Dockerfile.goreleaser index 0cdc8c6bd..abc741918 100644 --- a/Dockerfile.goreleaser +++ b/Dockerfile.goreleaser @@ -1,10 +1,24 @@ -FROM alpine:3.21 +# syntax=docker/dockerfile:1 + +# Certs stage — provides CA certificates and timezone data for scratch +FROM alpine:3.23 AS certs +RUN apk add --no-cache ca-certificates tzdata +RUN echo "picoclaw:x:10001:10001::/home/picoclaw:/sbin/nologin" > /tmp/passwd && \ + echo "picoclaw:x:10001:" > /tmp/group + +# Runtime +FROM scratch ARG TARGETPLATFORM -RUN apk add --no-cache ca-certificates tzdata +COPY --from=certs /tmp/passwd /etc/passwd +COPY --from=certs /tmp/group /etc/group +COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=certs /usr/share/zoneinfo /usr/share/zoneinfo COPY $TARGETPLATFORM/picoclaw /usr/local/bin/picoclaw +USER 10001 + ENTRYPOINT ["picoclaw"] CMD ["gateway"] diff --git a/docker-compose.yml b/docker-compose.yml index 32e8ee339..663d6a687 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,12 +8,20 @@ services: context: . dockerfile: Dockerfile container_name: picoclaw-agent + user: "10001" + read_only: true + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + tmpfs: + - /tmp profiles: - agent volumes: - ./config/config.json:/home/picoclaw/.picoclaw/config.json:ro - picoclaw-workspace:/home/picoclaw/.picoclaw/workspace - entrypoint: ["picoclaw", "agent"] + entrypoint: [ "picoclaw", "agent" ] stdin_open: true tty: true @@ -27,14 +35,20 @@ services: dockerfile: Dockerfile container_name: picoclaw-gateway restart: unless-stopped + user: "10001" + read_only: true + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + tmpfs: + - /tmp profiles: - gateway volumes: - # Configuration file - ./config/config.json:/home/picoclaw/.picoclaw/config.json:ro - # Persistent workspace (sessions, memory, logs) - picoclaw-workspace:/home/picoclaw/.picoclaw/workspace - command: ["gateway"] + command: [ "gateway" ] volumes: picoclaw-workspace: