From 2227900704433adf41fde4407fe069e5b6bb81f4 Mon Sep 17 00:00:00 2001 From: 2204Zero <166999816+2204Zero@users.noreply.github.com> Date: Mon, 2 Nov 2026 18:14:01 +0000 Subject: [PATCH] Add container image and CI build Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .dockerignore | 15 +++++++++++++++ .github/workflows/node.yml | 3 +++ Dockerfile | 34 ++++++++++++++++++++++++++++++++++ README.md | 19 +++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9401b30 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +dist +coverage +.env +.env.* +!.env.example +.git +.github +test +**/*.test.ts +**/*.test.tsx +**/*.spec.ts +**/*.spec.tsx +Dockerfile +*.log diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 098cfe5..521fc6b 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -50,6 +50,9 @@ jobs: - name: Build run: pnpm build + - name: Build container image + run: docker build --tag keygate-server:ci . + - name: Boot the service against an unreachable RPC # The routes that matter must answer before the first sync completes, and # answering is the point: `/readyz` is 503 and a decision is a denial, not diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b1080b5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM node:20-bookworm-slim AS build + +WORKDIR /app + +RUN corepack enable + +COPY package.json pnpm-lock.yaml ./ +COPY scripts/only-pnpm.js scripts/ +RUN pnpm install --frozen-lockfile + +COPY . . +RUN pnpm build + +FROM node:20-bookworm-slim AS runtime + +ENV NODE_ENV=production +WORKDIR /app + +RUN groupadd --system --gid 1001 keygate \ + && useradd --system --uid 1001 --gid keygate keygate + +RUN corepack enable + +COPY package.json pnpm-lock.yaml ./ +COPY scripts/only-pnpm.js scripts/ +RUN pnpm install --prod --frozen-lockfile \ + && pnpm store prune \ + && rm -rf scripts + +COPY --from=build /app/dist ./dist + +USER keygate + +CMD ["node", "dist/index.js"] diff --git a/README.md b/README.md index bd0c7fd..6baac11 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,25 @@ cp .env.example .env # then edit the three contract ids pnpm dev # tsx watch, on KEYGATE_PORT ``` +### Running in a container + +Build and run the image with the required configuration supplied as environment +variables. The image runs as a non-root user and does not contain `.env` files. + +```bash +docker build -t keygate-server . +docker run --rm \ + -p 8080:8080 \ + -e KEYGATE_SOROBAN_RPC_URL=https://your-rpc.example \ + -e KEYGATE_CORE_CONTRACT=C... \ + -e KEYGATE_POLICY_CONTRACT=C... \ + -e KEYGATE_BREAKER_CONTRACT=C... \ + keygate-server +``` + +Configure the orchestrator to use `/readyz` for readiness and `/healthz` for +liveness. `/readyz` remains unavailable until the first ledger sync completes. + ```bash curl -s localhost:8080/readyz # {"ready":true,"stalenessSeconds":4}