Skip to content

chore: fixes, self-contained scratch image, and dev-flow improvements#325

Merged
gwleclerc merged 7 commits into
mainfrom
chore/improvements
Jul 18, 2026
Merged

chore: fixes, self-contained scratch image, and dev-flow improvements#325
gwleclerc merged 7 commits into
mainfrom
chore/improvements

Conversation

@gwleclerc

Copy link
Copy Markdown
Collaborator

Summary

A batch of small fixes and build/tooling improvements gathered while triaging the issues.
No change to the mock format, its serialization, or the HTTP/CLI API.

Fixes (from the issue triage)

Build / packaging

  • Embed the web UI in the binary (go:embed, Use Go 1.16 embed API to package the binary #180): a released binary/image is
    self-contained; --static-files still overrides for development.
  • Docker image FROM scratch, static (CGO_ENABLED=0) + CA roots for the proxy →
    ~18 MB, no OS/shell.
  • Run the container as a non-root user (nobody).
  • Docker smoke test (Add smoke tests on the generated docker image #68): a smoke-docker target (config API, embedded UI, mock
    round-trip), run in CI after start-docker.

Dev experience

  • npm run dev works against the backend: the Vite dev server now substitutes the Go
    template placeholders and proxies the admin API to make start (SMOCKER_DEV_PROXY
    overridable). Production build unchanged.

Release / CI hygiene

  • IS_SEMVER accepts a leading v, so a stable vX.Y.Z tag updates the docker :latest.
  • Dependabot also covers Go modules and npm (grouped, weekly).
  • check-default-ports also checks the go-httpbin proxy port; document the vX.Y.Z tag convention.

Test plan

  • go test ./server/..., golden serialization tests, vitest, tsc, oxlint, golangci-lint — green locally.
  • go:embed, scratch, non-root, HTTPS proxy, and the smoke test validated by building/running the
    image with podman (self-contained image serves the UI + mocks; HTTPS proxy works).
  • Dev flow verified: npm run dev serves substituted placeholders and proxies the API.

Closes #309
Closes #313

🤖 Generated with Claude Code

gwleclerc and others added 7 commits July 18, 2026 17:32
…mage

IS_SEMVER only matched X.Y.Z, so a stable vX.Y.Z tag would publish a GitHub
release marked "Latest" without updating the docker :latest tag. Accept an
optional leading v so vX.Y.Z and X.Y.Z both push :latest, while -preview/-draft
suffixes stay non-latest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- #309: 'Copy as curl' no longer wraps a raw/urlencoded body in extra quotes
  (only JSON bodies are serialized; a string body is used as-is).
- #313: response headers are served with the exact casing the mock declares
  instead of Go's canonical form (e.g. 'BrokerProperties' stays as-is), matching
  servers that treat header names case-sensitively.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mage

#180: the built client is baked into the binary with go:embed, so a released
binary/image is self-contained. --static-files still takes precedence when it
holds an index.html (development and explicit overrides), otherwise the embedded
UI is served. A committed dist/.gitkeep keeps 'go build' working before the client
is built; the release build and Dockerfile copy the client into the embed source.
The docker image no longer ships a separate client directory.

#68: add a 'smoke-docker' target (config API answers, embedded UI is served, and a
registered mock is served on the mock port) and run it in CI after start-docker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build the binary statically (CGO_ENABLED=0) and put it on a scratch base instead of
alpine: the UI is already embedded (go:embed) and CA roots are copied in for the proxy
mock type's HTTPS backends, so nothing else is needed. Result is an ~18 MB image with
no OS/shell — smaller and a much smaller attack surface. Validated with podman:
embedded UI served, local mock round-trip, and an HTTPS proxy call all succeed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add USER 65534:65534 to the scratch image so smocker runs unprivileged by default.
The listen ports are >1024 (no privilege needed to bind); a mounted persistence
directory must be writable by this uid. Validated with podman: the process runs as
uid 65534 and still serves the UI, mock round-trips, and HTTPS proxy calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Vite dev server served index.html with the raw Go template placeholders
({{.basePath}}/{{.version}}) and had no API proxy, so the app's API base and
<base href> were broken and calls hit the SPA fallback. Add a serve-only
transformIndexHtml that substitutes the placeholders in dev, a server.proxy for
the admin API routes to the backend (SMOCKER_DEV_PROXY overridable), and serve
from base '/' in dev while the build keeps './' for the Go <base href>. The
production build is unchanged (placeholders + assets/ prefix preserved).
Update the README dev commands (yarn -> npm) accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e the v tag convention

- Dependabot now also updates Go modules and npm packages (grouped, weekly), not just actions.
- check-default-ports also verifies the go-httpbin proxy port (PROXY_TARGET_PORT, 8090).
- Document the 'vX.Y.Z' tag convention in the CI trigger comments (bare X.Y.Z still works).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gwleclerc
gwleclerc merged commit 2a8bb19 into main Jul 18, 2026
6 checks passed
@gwleclerc
gwleclerc deleted the chore/improvements branch July 18, 2026 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Response headers change on match when defined in PascalCase "Copy as curl" copies extra/unwanted quotes

1 participant