1 Commits

Author SHA1 Message Date
clawbot
de38b03508 feat: split Dockerfile into dedicated lint and build stages
All checks were successful
check / check (push) Successful in 5s
- Add dedicated lint stage using pre-built golangci-lint v2.10.1 image
- Move fmt-check and lint from build stage to lint stage for faster feedback
- Remove manual golangci-lint binary download (now handled by lint image)
- Remove curl from build stage dependencies (no longer needed)
- Add COPY --from=lint dependency to force BuildKit to run lint stage
- Build stage now runs only tests and compilation

closes #20
2026-03-02 00:05:52 -08:00
2 changed files with 78 additions and 72 deletions

View File

@@ -1,33 +1,38 @@
# Build stage # Lint stage — fast feedback on formatting and lint issues
# golangci/golangci-lint:v2.10.1, 2026-03-01
FROM golangci/golangci-lint@sha256:ea84d14c2fef724411be7dc45e09e6ef721d748315252b02df19a7e3113ee763 AS lint
# Install CGO dependencies needed for static analysis of vips/libheif code
RUN apt-get update && apt-get install -y --no-install-recommends \
libvips-dev \
libheif-dev \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN make fmt-check
RUN make lint
# Build stage — tests and compilation
# golang:1.25.4-alpine, 2026-02-25 # golang:1.25.4-alpine, 2026-02-25
FROM golang:1.25.4-alpine@sha256:d3f0cf7723f3429e3f9ed846243970b20a2de7bae6a5b66fc5914e228d831bbb AS builder FROM golang:1.25.4-alpine@sha256:d3f0cf7723f3429e3f9ed846243970b20a2de7bae6a5b66fc5914e228d831bbb AS builder
ARG VERSION=dev ARG VERSION=dev
# Force BuildKit to run the lint stage by creating a stage dependency
COPY --from=lint /src/go.sum /dev/null
# Install build dependencies for CGO image libraries # Install build dependencies for CGO image libraries
RUN apk add --no-cache \ RUN apk add --no-cache \
build-base \ build-base \
vips-dev \ vips-dev \
libheif-dev \ libheif-dev \
pkgconfig \ pkgconfig
curl
# golangci-lint v2.10.1, 2026-02-25
# SHA-256 checksums per architecture (amd64 / arm64)
RUN set -e; \
ARCH="$(uname -m)"; \
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
GOARCH="arm64"; \
HASH="6652b42ae02915eb2f9cb2a2e0cac99514c8eded8388d88ae3e06e1a52c00de8"; \
else \
GOARCH="amd64"; \
HASH="dfa775874cf0561b404a02a8f4481fc69b28091da95aa697259820d429b09c99"; \
fi; \
curl -sSfL "https://github.com/golangci/golangci-lint/releases/download/v2.10.1/golangci-lint-2.10.1-linux-${GOARCH}.tar.gz" -o /tmp/golangci-lint.tar.gz && \
echo "${HASH} /tmp/golangci-lint.tar.gz" | sha256sum -c - && \
tar -xzf /tmp/golangci-lint.tar.gz -C /tmp && \
mv "/tmp/golangci-lint-2.10.1-linux-${GOARCH}/golangci-lint" /usr/local/bin/ && \
rm -rf /tmp/golangci-lint*
WORKDIR /src WORKDIR /src
@@ -38,8 +43,8 @@ RUN GOTOOLCHAIN=auto go mod download
# Copy source code # Copy source code
COPY . . COPY . .
# Run all checks (fmt-check, lint, test) # Run tests
RUN make check RUN make test
# Build with CGO enabled # Build with CGO enabled
RUN CGO_ENABLED=1 GOTOOLCHAIN=auto go build -ldflags "-X main.Version=${VERSION}" -o /pixad ./cmd/pixad RUN CGO_ENABLED=1 GOTOOLCHAIN=auto go build -ldflags "-X main.Version=${VERSION}" -o /pixad ./cmd/pixad

101
TODO.md
View File

@@ -1,64 +1,65 @@
# Status # Pixa 1.0 TODO
pre-1.0. No git tags. Full policy file set is present, but make check Remaining tasks sorted by priority for a working 1.0 release.
fails on main with 10 gosec lint findings, so main is not green.
# Next Step ## P0: Critical for 1.0
Fix the 10 gosec findings so make check passes on main. Fix each issue ### Image Processing
properly (no blanket nolint suppressions) and confirm lint, tests, and - [x] Add WebP encoding support (currently returns error)
CI are green. This restores the main-always-green policy. - [ ] Add AVIF encoding support (currently returns error)
# Completed Steps ### Manual Testing (verify auth/encrypted URLs work)
- [ ] Manual test: visit `/`, see login form
- [ ] Manual test: enter wrong key, see error
- [ ] Manual test: enter correct signing key, see generator form
- [ ] Manual test: generate encrypted URL, verify it works
- [ ] Manual test: wait for expiration or use short TTL, verify expired URL returns 410
- [ ] Manual test: logout, verify redirected to login
- 2026-02-25: Docker arm64 build fixed via architecture detection for ### Cache Management
golangci-lint download (#16) - [ ] Implement cache size management/eviction (prevent disk from filling up)
- 2026-02-25: full repo policy compliance pass (#14): LICENSE,
REPO_POLICIES.md, .editorconfig, Gitea Actions CI workflow, Docker
images pinned by hash, README restructured to policy sections, hooks
Makefile target, golangci-lint errors resolved
- 2026-02-20: stale local dev config files removed (#12)
- 2026-02-09: correctness fixes: negative cache checked in Service.Get()
before upstream fetch (#8); Stats() column scanning and HitRate
computation corrected (#9)
- 2026-02-08: AllowHTTP propagated to SourceURL() scheme selection (#6)
- WebP encoding support added (P0 item, checked off in TODO)
- 2026-01-08: initial implementation with Makefile and TODO checklist
# Future Steps ### Configuration
- [ ] Validate configuration on startup (fail fast on bad config)
Compliance: ## P1: Important for Production
- After the gosec fix lands, verify CI runs make check green on main ### Security
- [ ] Implement blocked networks configuration (extend SSRF protection)
- [ ] Add rate limiting global concurrent fetches (prevent resource exhaustion)
P0, critical for 1.0 (from existing TODO.md): ### Image Processing
- [ ] Implement EXIF/metadata stripping (privacy)
- Add AVIF encoding support (currently returns error) ## P2: Nice to Have
- Manual test pass for auth and encrypted URLs:
- visit /, see login form
- wrong key shows error; correct signing key shows generator form
- generated encrypted URL works
- expired URL (short TTL) returns 410
- logout redirects to login
- Implement cache size management and eviction (prevent disk fill)
- Validate configuration on startup (fail fast on bad config)
P1, important for production: ### Security
- [ ] Implement referer blacklist
- [ ] Add rate limiting per-IP
- [ ] Add rate limiting per-origin
- Blocked networks configuration (extend SSRF protection) ### HTTP Response Handling
- Rate limit global concurrent fetches (resource exhaustion) - [ ] Implement Last-Modified headers
- EXIF/metadata stripping (privacy) - [ ] Implement Vary header for content negotiation
- [ ] Implement X-Request-ID propagation
P2, nice to have: ### Additional Endpoints
- [ ] Implement auto-format selection (format=auto based on Accept header)
- Referer blacklist; per-IP and per-origin rate limiting ### Configuration
- Last-Modified headers; Vary header; X-Request-ID propagation - [ ] Add all configuration options from README
- Auto-format selection (format=auto based on Accept header) - [ ] Implement environment variable overrides
- All configuration options from README; env var overrides; YAML config - [ ] Implement YAML config file support
file support
- Sentry error reporting (optional); comprehensive request logging; ### Operational
Prometheus metrics - [ ] Implement Sentry error reporting (optional)
- Integration tests for the image proxy flow; load tests for the - [ ] Add comprehensive request logging
1-5k req/s target - [ ] Add performance metrics (Prometheus)
- Docs: configuration options, API endpoints, deployment guide, example - [ ] Write integration tests for image proxy flow
nginx/caddy reverse proxy config - [ ] Write load tests to verify 1-5k req/s target
### Documentation
- [ ] Document configuration options
- [ ] Document API endpoints
- [ ] Document deployment guide
- [ ] Add example nginx/caddy reverse proxy config