fix(canary-phase0): address audit findings before phase rollup
Phase 0 audit (superpowers:code-reviewer + general-purpose) returned FAIL
on shared findings. This commit resolves the blockers + important items.
Blockers:
- infra/docker/vite.prod: replace 'react-scss/' COPY paths with 'frontend/'
(would have broken 'docker compose build nginx')
- Delete backend/Dockerfile (broken template debris referencing deleted
cmd/api, missing migrations/, deleted keys/)
- Delete backend/Justfile (docker compose recipes pointed at deleted
backend/compose.yml + backend/dev.compose.yml; project-root justfile
[backend] group covers everything operationally)
- backend/internal/admin/handler.go: strip the residual JWT/auth scaffolding
(AuthService interface, authSvc field, authenticator+adminOnly mw params).
Phase 12 will gate /admin under OperatorBearer; for now RegisterRoutes
takes only chi.Router.
- Delete backend/.env + backend/.env.example: stale template duplicates
containing only template keys; project-root .env.example is the source
of truth per spec §12.4.
Important:
- Add © glyph to file headers in cloudflared.compose.yml, infra/docker/
vite.{dev,prod}, backend/.gitignore (operator's standing rule:
'©AngelaMos | 2026', not 'AngelaMos | 2026')
- backend/.gitignore: drop stale 'keys/*.pem' / 'keys/*.key' entries
(backend/keys/ no longer exists)
- scripts/init.sh: rename 'local_tmp' variable to 'tmp_dir' to remove
visual ambiguity with the 'local' bash keyword (both audit agents
briefly misread it as 'local local_tmp=...')
- .env.example: add inline comment explaining the dual NGINX_HOST_PORT
defaults (22784 prod compose, 58495 dev compose; do not override in
shared .env)
Deferred (logged but not blocking Phase 0):
- Pre-existing template Go files (internal/{config,core,server,health,
middleware/{request_id,logging,headers,ratelimit},admin}/*.go) carry
'// AngelaMos | 2026' without ©. Bulk-fixing these belongs to a
hygiene pass; not Phase 0 scope.
- frontend/vite.config.ts and frontend/stylelint.config.js reference
'2025'; operator-imported template files, separate concern.
- APP_ENVIRONMENT vs ENVIRONMENT spec/impl mismatch: spec §12.1 sample
uses APP_ENVIRONMENT; envKeyMap in config.go uses ENVIRONMENT (template
default). Implementation is internally consistent. Logged in plan
Appendix C as a non-blocking spec amendment candidate.
Verification: go build ./... + go vet ./... clean. grep returns no
hits for react-scss / carterperez-dev/templates / JWTConfig /
InvalidateAllSessions across backend/, infra/, scripts/, compose files.
This commit is contained in:
parent
a4811d1c04
commit
98c006897d
|
|
@ -10,6 +10,9 @@
|
|||
# Public-facing
|
||||
# ---------------------------------------------------------------------------
|
||||
APP_NAME=canary-token-generator
|
||||
|
||||
# Production nginx host port (compose.yml). Dev compose has its own default
|
||||
# of 58495 in dev.compose.yml; do not override NGINX_HOST_PORT in shared .env.
|
||||
NGINX_HOST_PORT=22784
|
||||
|
||||
# Used to construct trigger URLs embedded in artifacts (e.g. canary docs).
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
# AngelaMos | 2026
|
||||
# .env.example
|
||||
|
||||
# Environment: development, staging, production
|
||||
ENVIRONMENT=development
|
||||
|
||||
# Server
|
||||
HOST=0.0.0.0
|
||||
PORT=8080
|
||||
|
||||
# Database
|
||||
DATABASE_URL=postgres://postgres:postgres@localhost:5432/app?sslmode=disable
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_REQUESTS=100
|
||||
RATE_LIMIT_WINDOW=1m
|
||||
|
||||
# OpenTelemetry
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
|
||||
OTEL_SERVICE_NAME=canary-token-generator
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=debug
|
||||
LOG_FORMAT=text
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# AngelaMos | 2026
|
||||
# ©AngelaMos | 2026
|
||||
# .gitignore
|
||||
|
||||
# Binaries
|
||||
|
|
@ -33,10 +33,6 @@ Thumbs.db
|
|||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Keys (sensitive)
|
||||
keys/*.pem
|
||||
keys/*.key
|
||||
|
||||
# Vendor (if using)
|
||||
vendor/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
# AngelaMos | 2026
|
||||
# Dockerfile - Multi-stage distroless build
|
||||
|
||||
# Build stage
|
||||
FROM golang:1.25-bookworm AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Copy dependency files first for layer caching
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build binary
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app ./cmd/api
|
||||
|
||||
# Production stage - Distroless
|
||||
FROM gcr.io/distroless/static-debian12
|
||||
|
||||
# Copy binary from builder
|
||||
COPY --from=builder /app /app
|
||||
|
||||
# Copy migrations (embedded, but useful for debugging)
|
||||
COPY --from=builder /build/migrations /migrations
|
||||
|
||||
# Copy keys if they exist (for JWT)
|
||||
COPY --from=builder /build/keys /keys
|
||||
|
||||
# Run as non-root user
|
||||
USER nonroot:nonroot
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["/app"]
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
# AngelaMos | 2026
|
||||
# Justfile
|
||||
|
||||
set dotenv-load := true
|
||||
|
||||
# Default recipe
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Development
|
||||
# -----------
|
||||
|
||||
# Run the API server with hot reload (requires air)
|
||||
dev:
|
||||
air -c .air.toml
|
||||
|
||||
# Run the canary server without hot reload
|
||||
run:
|
||||
go run ./cmd/canary
|
||||
|
||||
# Build the binary
|
||||
build:
|
||||
CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o bin/canary ./cmd/canary
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
go test -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
# Run tests with coverage report
|
||||
test-coverage: test
|
||||
go tool cover -html=coverage.out -o coverage.html
|
||||
|
||||
# Run linter
|
||||
lint:
|
||||
golangci-lint run --timeout=5m
|
||||
|
||||
# Format code
|
||||
fmt:
|
||||
gofumpt -w .
|
||||
goimports -w .
|
||||
|
||||
# Tidy dependencies
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
# Database
|
||||
# --------
|
||||
|
||||
# Run database migrations
|
||||
migrate-up:
|
||||
goose -dir migrations postgres "${DATABASE_URL}" up
|
||||
|
||||
# Rollback last migration
|
||||
migrate-down:
|
||||
goose -dir migrations postgres "${DATABASE_URL}" down
|
||||
|
||||
# Check migration status
|
||||
migrate-status:
|
||||
goose -dir migrations postgres "${DATABASE_URL}" status
|
||||
|
||||
# Create new migration
|
||||
migrate-create name:
|
||||
goose -dir migrations create {{name}} sql
|
||||
|
||||
# Docker
|
||||
# ------
|
||||
|
||||
# Start development containers
|
||||
up:
|
||||
docker compose -f dev.compose.yml up -d
|
||||
|
||||
# Stop development containers
|
||||
down:
|
||||
docker compose -f dev.compose.yml down
|
||||
|
||||
# View container logs
|
||||
logs:
|
||||
docker compose -f dev.compose.yml logs -f
|
||||
|
||||
# Rebuild and restart containers
|
||||
rebuild:
|
||||
docker compose -f dev.compose.yml up -d --build
|
||||
|
||||
# Build production image
|
||||
docker-build:
|
||||
docker build -t canary-token-generator:latest .
|
||||
|
||||
# Clean
|
||||
# -----
|
||||
|
||||
# Remove build artifacts
|
||||
clean:
|
||||
rm -rf bin/ coverage.out coverage.html tmp/
|
||||
|
||||
# Full clean including containers
|
||||
clean-all: clean
|
||||
docker compose -f dev.compose.yml down -v
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// AngelaMos | 2026
|
||||
// ©AngelaMos | 2026
|
||||
// handler.go
|
||||
|
||||
package admin
|
||||
|
|
@ -15,16 +15,11 @@ import (
|
|||
"github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/core"
|
||||
)
|
||||
|
||||
type AuthService interface {
|
||||
InvalidateAllSessions(ctx context.Context) error
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
dbStats func() sql.DBStats
|
||||
redisStats func() *redis.PoolStats
|
||||
redisPing func(ctx context.Context) error
|
||||
dbPing func(ctx context.Context) error
|
||||
authSvc AuthService
|
||||
}
|
||||
|
||||
type HandlerConfig struct {
|
||||
|
|
@ -32,7 +27,6 @@ type HandlerConfig struct {
|
|||
RedisStats func() *redis.PoolStats
|
||||
RedisPing func(ctx context.Context) error
|
||||
DBPing func(ctx context.Context) error
|
||||
AuthSvc AuthService
|
||||
}
|
||||
|
||||
func NewHandler(cfg HandlerConfig) *Handler {
|
||||
|
|
@ -41,18 +35,11 @@ func NewHandler(cfg HandlerConfig) *Handler {
|
|||
redisStats: cfg.RedisStats,
|
||||
redisPing: cfg.RedisPing,
|
||||
dbPing: cfg.DBPing,
|
||||
authSvc: cfg.AuthSvc,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) RegisterRoutes(
|
||||
r chi.Router,
|
||||
authenticator, adminOnly func(http.Handler) http.Handler,
|
||||
) {
|
||||
func (h *Handler) RegisterRoutes(r chi.Router) {
|
||||
r.Route("/admin", func(r chi.Router) {
|
||||
r.Use(authenticator)
|
||||
r.Use(adminOnly)
|
||||
|
||||
r.Get("/stats", h.GetSystemStats)
|
||||
r.Get("/stats/db", h.GetDatabaseStats)
|
||||
r.Get("/stats/redis", h.GetRedisStats)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# =============================================================================
|
||||
# AngelaMos | 2026
|
||||
# ©AngelaMos | 2026
|
||||
# cloudflared.compose.yml
|
||||
# =============================================================================
|
||||
# Cloudflare Tunnel for production remote access
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# =============================================================================
|
||||
# AngelaMos | 2026
|
||||
# ©AngelaMos | 2026
|
||||
# vite.dev
|
||||
# =============================================================================
|
||||
# Development Dockerfile for Vite/React frontend
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# =============================================================================
|
||||
# AngelaMos | 2026
|
||||
# ©AngelaMos | 2026
|
||||
# vite.prod
|
||||
# =============================================================================
|
||||
# Production Dockerfile: builds Vite app, serves via Nginx
|
||||
|
|
@ -15,12 +15,12 @@ RUN corepack enable && corepack prepare pnpm@latest --activate
|
|||
|
||||
WORKDIR /app
|
||||
|
||||
COPY react-scss/package.json react-scss/pnpm-lock.yaml* ./
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml* ./
|
||||
|
||||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
COPY react-scss/ .
|
||||
COPY frontend/ .
|
||||
|
||||
ARG VITE_API_URL=/api
|
||||
ARG VITE_APP_TITLE="My App"
|
||||
|
|
|
|||
|
|
@ -60,14 +60,14 @@ if [[ -n "$ACCT" && -n "$KEY" ]]; then
|
|||
if [[ ! -f "$MMDB_PATH" ]]; then
|
||||
mkdir -p "$DATA_DIR"
|
||||
echo " downloading GeoLite2-City.mmdb from MaxMind..."
|
||||
local_tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "$local_tmp"' EXIT
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
if curl -sSf -u "$ACCT:$KEY" \
|
||||
"https://download.maxmind.com/geoip/databases/GeoLite2-City/download?suffix=tar.gz" \
|
||||
-o "$local_tmp/geolite.tar.gz"; then
|
||||
tar -xzf "$local_tmp/geolite.tar.gz" -C "$local_tmp" --strip-components=1 \
|
||||
-o "$tmp_dir/geolite.tar.gz"; then
|
||||
tar -xzf "$tmp_dir/geolite.tar.gz" -C "$tmp_dir" --strip-components=1 \
|
||||
"*/GeoLite2-City.mmdb"
|
||||
mv "$local_tmp/GeoLite2-City.mmdb" "$MMDB_PATH"
|
||||
mv "$tmp_dir/GeoLite2-City.mmdb" "$MMDB_PATH"
|
||||
echo " GeoLite2-City.mmdb downloaded to $MMDB_PATH"
|
||||
else
|
||||
echo " Warning: GeoLite2 download failed (check MAXMIND_ACCOUNT_ID and MAXMIND_LICENSE_KEY)" >&2
|
||||
|
|
|
|||
Loading…
Reference in New Issue