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
126 changes: 126 additions & 0 deletions .github/workflows/build-consumer-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: Build and Push Consumer Service Docker Image

on:
push:
branches:
- main
- develop
paths:
- 'consumer-service/**'
- '.github/workflows/build-consumer-service.yml'
pull_request:
branches:
- main
- develop
paths:
- 'consumer-service/**'
workflow_dispatch:
inputs:
version:
description: 'Docker image version'
required: false
default: 'latest'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}/consumer-service

jobs:
build:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: ./consumer-service
file: ./consumer-service/Dockerfile.prod
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ github.sha }}
BUILD_TIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
GIT_COMMIT=${{ github.sha }}

- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'

- name: Download dependencies
run: |
cd consumer-service
go mod download

- name: Run tests
run: |
cd consumer-service
go test -v ./...

- name: Run linter
uses: golangci/golangci-lint-action@v3
with:
working-directory: consumer-service
version: latest

scan:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: 'consumer-service'
format: 'sarif'
output: 'trivy-results.sarif'

- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
64 changes: 64 additions & 0 deletions consumer-service/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Git files
.git
.gitignore
.gitattributes

# IDEs and Editors
.vscode
.idea
*.swp
*.swo
*~
.DS_Store
.env.local
.env.*.local

# Build and test artifacts
.bin
*.o
*.a
*.so
*.exe
*.test
coverage.out
*.coverprofile

# Temporary files
tmp/
temp/
*.tmp

# Docker files
Dockerfile
Dockerfile.*
docker-compose*.yml
.dockerignore
.docker

# CI/CD
.github
.gitlab-ci.yml
.circleci

# Documentation
*.md
docs/
README.md

# Development files
Makefile
makefile
scripts/
*.sh

# Database
*.db
*.sqlite
*.sqlite3

# Logs
*.log
logs/

# OS files
Thumbs.db
50 changes: 50 additions & 0 deletions consumer-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Stage 1: Builder
FROM golang:1.26-alpine AS builder

# Install build dependencies
RUN apk add --no-cache git ca-certificates tzdata openssh-client

WORKDIR /app

# Configure Git for private repos
RUN git config --global url."git@github.com:".insteadOf "https://github.com/"

# Copy SSH key for private repo access (build arg)
ARG SSH_PRIVATE_KEY
RUN mkdir -p /root/.ssh && \
echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa && \
ssh-keyscan -H github.com >> /root/.ssh/known_hosts

# Copy go mod files
COPY go.mod go.sum ./

# Download dependencies
RUN go mod download

# Copy source code
COPY . .

# Build the application
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o consumer-service .

# Stage 2: Runtime
FROM alpine:3.18

RUN apk --no-cache add ca-certificates tzdata

RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser

WORKDIR /home/appuser

COPY --from=builder --chown=appuser:appuser /app/consumer-service .

USER appuser

EXPOSE 50051

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD nc -z localhost 50051 || exit 1

CMD ["./consumer-service"]
60 changes: 60 additions & 0 deletions consumer-service/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Stage 1: Builder
FROM golang:1.26-alpine AS builder

ARG VERSION=dev
ARG BUILD_TIME
ARG GIT_COMMIT

# Install build dependencies
RUN apk add --no-cache git ca-certificates tzdata make

WORKDIR /app

# Copy go mod files
COPY go.mod go.sum ./

# Download dependencies (cached layer)
RUN go mod download

# Copy source code
COPY . .

# Build with optimizations
ARG TARGETARCH

RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build \
-a \
-installsuffix cgo \
-o consumer-service .

# Stage 2: Runtime
FROM alpine:3.18

# Install minimal runtime dependencies
RUN apk --no-cache add ca-certificates tzdata curl

# Create non-root user for security
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser

WORKDIR /home/appuser

# Copy binary from builder
COPY --from=builder --chown=appuser:appuser /app/consumer-service .

# Copy any config files if needed
# COPY --from=builder --chown=appuser:appuser /app/config ./config

USER appuser

# Expose gRPC port
EXPOSE 50051

# Metadata
LABEL org.opencontainers.image.title="HireMind Consumer Service"
LABEL org.opencontainers.image.description="gRPC service for interview management"
LABEL org.opencontainers.image.version="${VERSION}"


# Run the application
CMD ["./consumer-service"]
Loading
Loading