Skip to content
Merged
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
42 changes: 42 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Build artifacts
bin/
dist/
linux/
site/
coverage.*
*.coverprofile
*.test
*.out

# Node + UI build outputs (UI is built inside the Dockerfile when needed,
# or pre-embedded into internal/ui/dist by GoReleaser).
**/node_modules/
ui/dist/
internal/ui/dist/

# Docs (not needed in the runtime image; deployed separately to GH Pages)
docs/
mkdocs.yml

# Repo metadata
.git/
.github/
.gitignore
.gitattributes
.golangci.yml
.goreleaser.yml
.editorconfig

# Local env files (never bake into an image)
.env
.env.*
!.env.example

# IDE / OS noise
.idea/
.vscode/
.DS_Store
Thumbs.db

# Local screenshot tooling
scripts/screenshots/node_modules/
66 changes: 66 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Release

on:
push:
tags:
- "v*"

permissions: {}

jobs:
release:
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: write
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "1.26.3"
cache: true

- name: Set up Node (for SPA build)
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"

- name: Set up pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
with:
version: 10
run_install: false

- name: Verify Go modules
run: |
go mod download
go mod verify

- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

- name: Login to GitHub Container Registry
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
with:
distribution: goreleaser
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ go.work.sum
# Build artifacts
/bin/
/site/
# GoReleaser snapshot/release output (matches mcp-test convention)
/dist/
# Local docker buildx scratch dir for `make docker`
/linux/

# UI build outputs (regenerated by `make ui`; only .gitkeep is tracked
# under internal/ui/dist so the //go:embed directive has something to
Expand Down
157 changes: 157 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
#
# GoReleaser config for api-test. Publishes binaries to GitHub Releases
# and multi-arch container images to GHCR. Cosign keyless signing and
# SBOM generation are wired through via the release.yml workflow's
# id-token: write permission.

version: 2

project_name: api-test

env:
- GO111MODULE=on

before:
hooks:
- go mod download
- go mod verify
# Build the React SPA into internal/ui/dist so the embedded UI is in
# every shipped binary. Skipped if ui/ is missing (pure-binary builds).
- bash -c "if [ -f ui/package.json ]; then cd ui && (corepack enable && pnpm install --frozen-lockfile && pnpm build || npm install && npm run build) && rm -rf ../internal/ui/dist && cp -R dist ../internal/ui/dist; fi"

builds:
- id: api-test
main: ./cmd/api-test
binary: api-test
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
ignore:
- goos: windows
goarch: arm64
mod_timestamp: '{{ .CommitTimestamp }}'
env:
- CGO_ENABLED=0
flags:
- -trimpath
- -a
ldflags:
- -s -w
- -X github.com/plexara/api-test/pkg/build.Version={{.Version}}
- -X github.com/plexara/api-test/pkg/build.Commit={{.ShortCommit}}
- -X github.com/plexara/api-test/pkg/build.Date={{.Date}}

archives:
- id: default
name_template: >-
{{ .ProjectName }}_
{{- .Version }}_
{{- .Os }}_
{{- .Arch }}
format_overrides:
- goos: windows
formats: [zip]
files:
- LICENSE
- README.md

checksum:
name_template: 'checksums.txt'
algorithm: sha256

snapshot:
version_template: "{{ incpatch .Version }}-next"

changelog:
sort: asc
use: github
filters:
exclude:
- '^docs:'
- '^test:'
- '^chore:'
- '^build:'
- Merge pull request
- Merge branch
groups:
- title: Features
regexp: '^feat'
order: 0
- title: Bug Fixes
regexp: '^fix'
order: 1
- title: Security
regexp: '^security'
order: 2
- title: Others
order: 999

# Multi-arch container image to GHCR.
#
# `extra_files` augments GoReleaser's per-platform Docker build context.
# Without it the context only contains the linux/<arch>/api-test binaries
# GoReleaser stages. We add LICENSE for OCI compliance; no example config
# is shipped in the image (operators mount their own).
dockers_v2:
- id: scratch
dockerfile: Dockerfile
ids:
- api-test
images:
- ghcr.io/plexara/api-test
tags:
- latest
- "{{ .Tag }}"
- "v{{ .Major }}"
platforms:
- linux/amd64
- linux/arm64
extra_files:
- LICENSE
labels:
org.opencontainers.image.created: "{{ .Date }}"
org.opencontainers.image.title: "{{ .ProjectName }}"
org.opencontainers.image.revision: "{{ .FullCommit }}"
org.opencontainers.image.version: "{{ .Version }}"
org.opencontainers.image.source: "{{ .GitURL }}"
org.opencontainers.image.description: "A controllable HTTP REST fixture for testing API gateways"
org.opencontainers.image.licenses: "Apache-2.0"
org.opencontainers.image.vendor: "Plexara"
org.opencontainers.image.url: "https://api-test.plexara.io"

release:
github:
owner: plexara
name: api-test
name_template: "{{.ProjectName}}-v{{.Version}}"
prerelease: auto
mode: append
footer: |
## Installation

### Container

```bash
docker pull ghcr.io/plexara/api-test:{{ .Tag }}
```

### Binary (macOS / Linux)

```bash
curl -L -o api-test.tar.gz \
https://github.com/plexara/api-test/releases/download/{{ .Tag }}/api-test_{{ .Version }}_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz
tar -xzf api-test.tar.gz
./api-test --version
```

### Documentation

Full docs at <https://api-test.plexara.io>.

Open source by [Plexara](https://plexara.io), the commercial MCP + API gateway with configurable enrichment built in.
53 changes: 25 additions & 28 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,42 +1,39 @@
# Multi-stage build for the api-test fixture binary.
# syntax=docker/dockerfile:1
#
# Stage 1: build the static linux binary with version metadata stamped in.
# Stage 2: distroless base; the binary doubles as its own healthcheck via
# `--healthcheck` so we don't need curl/wget in the runtime image.
# api-test runtime image. Goreleaser supplies the pre-built binary in
# the build context (one per linux/<arch>); we just bundle it with CA
# certs and run as a non-root user.

FROM golang:1.26 AS build
FROM alpine:3.23 AS certs
RUN apk add --no-cache ca-certificates

ARG TARGETARCH=amd64
ARG VERSION=dev
ARG COMMIT=none
ARG BUILD_DATE=unknown
FROM scratch

WORKDIR /src
COPY go.mod go.sum* ./
RUN go mod download
# TLS root certs so OIDC discovery (HTTPS to the IdP) works.
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt

COPY . .
# Goreleaser sets TARGETARCH for the platform-specific binary path.
ARG TARGETARCH
COPY linux/${TARGETARCH}/api-test /usr/local/bin/api-test

RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} \
go build \
-trimpath \
-ldflags "-s -w \
-X github.com/plexara/api-test/pkg/build.Version=${VERSION} \
-X github.com/plexara/api-test/pkg/build.Commit=${COMMIT} \
-X github.com/plexara/api-test/pkg/build.Date=${BUILD_DATE}" \
-o /out/api-test \
./cmd/api-test

FROM gcr.io/distroless/static-debian12:nonroot
# No config is baked in. Operators mount one (or use env vars):
#
# docker run --rm \
# -v $(pwd)/api-test.yaml:/app/configs/api-test.yaml:ro \
# ghcr.io/plexara/api-test:latest
#
# A starter config to copy from lives in the source tree at
# configs/api-test.example.yaml on the GitHub repo.

COPY --from=build /out/api-test /usr/local/bin/api-test
COPY --chown=nonroot:nonroot configs/api-test.dev.yaml /etc/api-test/api-test.yaml
# Non-root (scratch has no /etc/passwd; numeric IDs only).
USER 1000:1000

EXPOSE 8080
USER nonroot:nonroot

# The binary doubles as its own healthcheck via `--healthcheck`, which
# probes 127.0.0.1:8080/healthz. No curl/wget needed in the runtime image.
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD ["/usr/local/bin/api-test", "--healthcheck"]

ENTRYPOINT ["/usr/local/bin/api-test"]
CMD ["--config", "/etc/api-test/api-test.yaml"]
CMD ["--config", "/app/configs/api-test.yaml"]
Loading