check / check (push) Successful in 1m1s
The bot now serves an HTTP API on PORT (default 8080) beside the chat client. Every request needs the credential read at startup from the file named by API_TOKEN_FILE, sent as a bearer token; without one, every request is refused. Responses carry the security headers, bodies are capped at 64 KiB and each request's work at 10 seconds. GET /api/v1/chats lists the bot's contacts from the chat client's /_contacts command, ordered by id, and marks the contacts who deleted their chat with the bot, which the chat client keeps listing. bot.Run starts the API after set-up and stops it within 5 seconds; a listener failure ends the bot as a chat client failure does. Model: opus-5-5
127 lines
5.3 KiB
Docker
127 lines
5.3 KiB
Docker
# Lint stage — fast feedback on formatting and lint issues. Tools are
|
|
# invoked directly (not via make/script): the docker build is its own
|
|
# single path.
|
|
# This stage must stay the one that runs golangci-lint, and its name must
|
|
# match $lint_stage in script/cibuild, which cache-busts it by name.
|
|
# golangci/golangci-lint:v2.12.2 (Debian-based), 2026-08-07
|
|
FROM golangci/golangci-lint:v2.12.2@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240 AS lint
|
|
|
|
WORKDIR /src
|
|
|
|
# Copy go mod files first for better layer caching
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy source code
|
|
COPY . .
|
|
|
|
# Inventory of the sources that actually arrived here. script/cibuild
|
|
# reads these lines out of the build log and compares them against the
|
|
# git index, so a .dockerignore entry or a narrowed COPY that hides a
|
|
# package fails the run instead of yielding a clean report over a tree
|
|
# the linter never saw. Keep it immediately after `COPY . .`, and keep
|
|
# `echo context-manifest-begin` as its first command:
|
|
# script/assert-context-complete matches the step by that prefix.
|
|
RUN echo context-manifest-begin; \
|
|
{ find . -type f -name '*.go'; \
|
|
for f in go.mod go.sum .golangci.yml .golangci.yaml; do \
|
|
if [ -f "$f" ]; then echo "./$f"; fi; \
|
|
done; } \
|
|
| sed 's|^\./||' | LC_ALL=C sort | sed 's|^|context-file: |'; \
|
|
echo context-manifest-end
|
|
|
|
# Formatting check, config check, linter
|
|
RUN test -z "$(gofmt -s -l .)" || { echo "gofmt needed on:"; gofmt -s -l .; exit 1; }
|
|
RUN golangci-lint config verify --config .golangci.yml
|
|
RUN golangci-lint run --config .golangci.yml ./...
|
|
|
|
# Build stage. Must stay the one that runs go test, and its name must
|
|
# match $test_stage in script/cibuild, which cache-busts it by name.
|
|
# golang:1.25.7-bookworm (Debian-based: the race detector used by the
|
|
# test run requires glibc), 2026-08-07
|
|
FROM golang:1.25.7-bookworm@sha256:564e366a28ad1d70f460a2b97d1d299a562f08707eb0ecb24b659e5bd6c108e1 AS builder
|
|
|
|
# Depend on lint stage passing (forces BuildKit ordering)
|
|
COPY --from=lint /src/go.sum /dev/null
|
|
|
|
WORKDIR /build
|
|
|
|
# Copy go mod files first for better layer caching
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy source code
|
|
COPY . .
|
|
|
|
# Same inventory as the lint stage, and separately checked: this stage
|
|
# has its own COPY, so an intact context over there is no evidence about
|
|
# the tree `go test ./...` is about to walk here. A package that did not
|
|
# arrive is a package the tests never run, and the run still ends `ok`.
|
|
RUN echo context-manifest-begin; \
|
|
{ find . -type f -name '*.go'; \
|
|
for f in go.mod go.sum .golangci.yml .golangci.yaml; do \
|
|
if [ -f "$f" ]; then echo "./$f"; fi; \
|
|
done; } \
|
|
| sed 's|^\./||' | LC_ALL=C sort | sed 's|^|context-file: |'; \
|
|
echo context-manifest-end
|
|
|
|
# Run tests: quiet first, verbose rerun on failure (and still fail).
|
|
# -count=1 disables the test result cache, matching script/test.
|
|
RUN go test -count=1 -timeout 90s -race -cover ./... || \
|
|
{ echo "--- Rerunning with -v for details ---"; \
|
|
go test -count=1 -timeout 90s -race -v ./...; exit 1; }
|
|
|
|
# Static build, so the binary runs on any runtime base.
|
|
ARG VERSION=dev
|
|
RUN CGO_ENABLED=0 go build -trimpath \
|
|
-ldflags "-s -w -X main.version=${VERSION}" \
|
|
-o bin/simplexcalc ./cmd/simplexcalc
|
|
|
|
# Runtime stage, and the last one: script/cibuild passes no --target, so
|
|
# BuildKit builds whichever stage is last and appending one drops lint,
|
|
# builder and their checks out of the run. Nothing asserts the name; it
|
|
# is here so that failure reads as `[runtime n/m]` in the build log.
|
|
# Ubuntu 22.04 because it is the release the SimpleX Chat client below
|
|
# is built for, and it already has every library that client links
|
|
# (glibc, OpenSSL 3, GMP, zlib), so nothing is installed on top.
|
|
# ubuntu:22.04, 2026-09-26
|
|
FROM ubuntu:22.04@sha256:b8b6ee6aa931ecd9d0d952abc34dc0e5f7c6a30c6bb71b079fe399fde0329c02 AS runtime
|
|
|
|
# The SimpleX Chat command-line client, which the bot starts and talks
|
|
# to. BuildKit checks the download against the checksum and fails the
|
|
# build on a mismatch; a new release means changing both the URL and
|
|
# the checksum. This is the x86_64 build, so the image is x86_64 only;
|
|
# an arm64 image would need the aarch64 build and its own checksum.
|
|
# simplex-chat v7.0.2 (simplex-chat-ubuntu-22_04-x86_64), 2026-09-26
|
|
ADD --chmod=0755 \
|
|
--checksum=sha256:5afb1d25efe5ccf564a1ab124bc7f410a7a73171c974a4d8b7f4d8f2e3d62e77 \
|
|
https://github.com/simplex-chat/simplex-chat/releases/download/v7.0.2/simplex-chat-ubuntu-22_04-x86_64 \
|
|
/usr/local/bin/simplex-chat
|
|
|
|
# Create non-root user
|
|
RUN groupadd --gid 1000 simplexcalc && \
|
|
useradd --uid 1000 --gid simplexcalc --home-dir /var/lib/simplexcalc \
|
|
--no-create-home --shell /usr/sbin/nologin simplexcalc
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy binary from builder
|
|
COPY --from=builder /build/bin/simplexcalc /app/simplexcalc
|
|
|
|
# Data directory: the SimpleX database, which holds the bot's profile,
|
|
# its keys, its address and its contacts. Mount a volume over it;
|
|
# without one, the bot gets a new address every time the container is
|
|
# recreated.
|
|
RUN mkdir -p /var/lib/simplexcalc && \
|
|
chown simplexcalc:simplexcalc /var/lib/simplexcalc
|
|
|
|
USER simplexcalc
|
|
|
|
ENV DATA_DIR=/var/lib/simplexcalc
|
|
|
|
# The API, on its default PORT. The chat client's WebSocket on 5225 is
|
|
# not exposed: it has no authentication.
|
|
EXPOSE 8080
|
|
|
|
CMD ["/app/simplexcalc", "run"]
|