Skip to content

Commit 8465c9d

Browse files
authored
Merge pull request #116 from Gaucho-Racing/bk1031/refactor-auth
Refactor auth service + add SkipAuthCheck for local dev
2 parents bf2453d + 1368114 commit 8465c9d

34 files changed

Lines changed: 584 additions & 410 deletions

.github/workflows/auth.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
name: auth
2+
run-name: Triggered by ${{ github.event_name }} to ${{ github.ref }} by @${{ github.actor }}
3+
4+
on:
5+
push:
6+
branches:
7+
- "**"
8+
tags:
9+
- "**"
10+
11+
jobs:
12+
build:
13+
runs-on: ${{ matrix.runner }}
14+
name: Build ${{ matrix.platform }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
include:
19+
- platform: linux/amd64
20+
runner: ubuntu-24.04
21+
- platform: linux/arm64
22+
runner: ubuntu-24.04-arm
23+
24+
permissions:
25+
contents: read
26+
packages: write
27+
28+
steps:
29+
- name: Checkout code
30+
uses: actions/checkout@v4
31+
32+
- name: Set up Docker Buildx
33+
uses: docker/setup-buildx-action@v3
34+
35+
- name: Log in to GitHub Container Registry
36+
uses: docker/login-action@v3
37+
with:
38+
registry: ghcr.io
39+
username: ${{ github.actor }}
40+
password: ${{ secrets.GITHUB_TOKEN }}
41+
42+
- name: Generate platform pair
43+
id: platform
44+
run: |
45+
platform=${{ matrix.platform }}
46+
echo "pair=${platform//\//-}" >> $GITHUB_OUTPUT
47+
48+
- name: Build and push by digest
49+
id: build
50+
uses: docker/build-push-action@v5
51+
with:
52+
context: auth
53+
platforms: ${{ matrix.platform }}
54+
outputs: type=image,name=ghcr.io/gaucho-racing/mapache/auth,push-by-digest=true,name-canonical=true,push=true
55+
cache-from: type=gha,scope=build-${{ steps.platform.outputs.pair }}
56+
cache-to: type=gha,scope=build-${{ steps.platform.outputs.pair }},mode=max
57+
58+
- name: Export digest
59+
run: |
60+
mkdir -p /tmp/digests
61+
digest="${{ steps.build.outputs.digest }}"
62+
touch "/tmp/digests/${digest#sha256:}"
63+
64+
- name: Upload digest
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: digests-${{ steps.platform.outputs.pair }}
68+
path: /tmp/digests/*
69+
if-no-files-found: error
70+
retention-days: 1
71+
72+
merge:
73+
runs-on: ubuntu-latest
74+
name: Merge manifests
75+
needs: build
76+
77+
permissions:
78+
contents: read
79+
packages: write
80+
81+
steps:
82+
- name: Checkout code
83+
uses: actions/checkout@v4
84+
with:
85+
fetch-depth: 0
86+
fetch-tags: true
87+
88+
- name: Download digests
89+
uses: actions/download-artifact@v4
90+
with:
91+
path: /tmp/digests
92+
pattern: digests-*
93+
merge-multiple: true
94+
95+
- name: Set up Docker Buildx
96+
uses: docker/setup-buildx-action@v3
97+
98+
- name: Log in to GitHub Container Registry
99+
uses: docker/login-action@v3
100+
with:
101+
registry: ghcr.io
102+
username: ${{ github.actor }}
103+
password: ${{ secrets.GITHUB_TOKEN }}
104+
105+
- name: Check if this commit has a release tag
106+
id: release
107+
run: |
108+
tag=$(git tag --points-at HEAD | grep '^v' | head -n1)
109+
if [ -n "$tag" ]; then
110+
echo "Found tag: $tag"
111+
if gh release view "$tag" --json tagName > /dev/null 2>&1; then
112+
echo "release_tag=$tag" >> $GITHUB_OUTPUT
113+
echo "is_release=true" >> $GITHUB_OUTPUT
114+
exit 0
115+
fi
116+
fi
117+
echo "is_release=false" >> $GITHUB_OUTPUT
118+
env:
119+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120+
121+
- name: Generate tag list
122+
id: tags
123+
shell: bash
124+
run: |
125+
TAGS="type=sha"
126+
127+
if [ "${GITHUB_REF_TYPE}" = "branch" ] && [ "${GITHUB_REF_NAME}" = "main" ]; then
128+
TAGS="${TAGS}\ntype=raw,value=latest"
129+
fi
130+
131+
if [ "${{ steps.release.outputs.is_release }}" = "true" ]; then
132+
CLEAN_TAG=$(echo "${{ steps.release.outputs.release_tag }}" | sed 's/^v//')
133+
TAGS="${TAGS}\ntype=raw,value=${CLEAN_TAG}"
134+
fi
135+
136+
echo -e "tags<<EOF\n$TAGS\nEOF" >> $GITHUB_OUTPUT
137+
138+
- name: Extract image metadata
139+
id: meta
140+
uses: docker/metadata-action@v5
141+
with:
142+
images: ghcr.io/gaucho-racing/mapache/auth
143+
tags: ${{ steps.tags.outputs.tags }}
144+
145+
- name: Create manifest list and push
146+
working-directory: /tmp/digests
147+
run: |
148+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
149+
$(printf 'ghcr.io/gaucho-racing/mapache/auth@sha256:%s ' *)
150+
151+
- name: Inspect image
152+
run: |
153+
docker buildx imagetools inspect ghcr.io/gaucho-racing/mapache/auth:${{ steps.meta.outputs.version }}

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
- name: Setup Go
1616
uses: actions/setup-go@v4
1717
with:
18-
go-version: "1.22.0"
18+
go-version: "1.26.0"
1919
- name: Build Auth
2020
run: |
2121
cd auth

auth/.air.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
root = "."
2+
tmp_dir = "tmp"
3+
4+
[build]
5+
bin = "./tmp/main"
6+
cmd = "go mod tidy && go build -o ./tmp/main ."
7+
delay = 1000
8+
exclude_dir = ["tmp", "vendor"]
9+
exclude_regex = ["_test.go"]
10+
include_ext = ["go", "toml"]
11+
kill_delay = "0s"
12+
send_interrupt = false
13+
poll = true
14+
poll_interval = 500
15+
stop_on_error = true
16+
17+
[log]
18+
time = false
19+
20+
[misc]
21+
clean_on_exit = true

auth/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.env
2+
tmp/
23

34
### VisualStudioCode template
45
.vscode/*

auth/Dockerfile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM --platform=$BUILDPLATFORM golang:1.23-alpine AS builder
1+
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder
22

33
RUN apk --no-cache add ca-certificates
44
RUN apk add --no-cache tzdata
@@ -12,18 +12,18 @@ RUN go mod download
1212
COPY . ./
1313
ARG TARGETOS
1414
ARG TARGETARCH
15-
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /auth
15+
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /app
1616

1717
##
1818
## Deploy
1919
##
20-
FROM alpine:3.21
20+
FROM alpine:3.19
2121

2222
WORKDIR /
2323

24-
COPY --from=builder /auth /auth
24+
COPY --from=builder /app /app
2525

2626
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
2727
ENV TZ=America/Los_Angeles
2828

29-
ENTRYPOINT ["/auth"]
29+
ENTRYPOINT ["/app"]

auth/Dockerfile.dev

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM golang:1.26-alpine
2+
3+
RUN go install github.com/air-verse/air@latest
4+
5+
WORKDIR /app/auth
6+
7+
CMD ["air", "-c", ".air.toml"]

auth/Makefile

Lines changed: 0 additions & 15 deletions
This file was deleted.

auth/api/api.go

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
package api
22

33
import (
4-
"auth/config"
5-
"auth/service"
6-
"auth/utils"
4+
"fmt"
75
"net/http"
86
"strings"
97
"time"
108

9+
"github.com/gaucho-racing/mapache/auth/config"
10+
"github.com/gaucho-racing/mapache/auth/pkg/logger"
11+
"github.com/gaucho-racing/mapache/auth/service"
1112
"github.com/gin-contrib/cors"
1213
"github.com/gin-gonic/gin"
1314
)
1415

15-
func SetupRouter() *gin.Engine {
16-
if config.Env == "PROD" {
16+
func Run() {
17+
api := InitializeRouter()
18+
InitializeRoutes(api)
19+
err := api.Run(":" + config.Port)
20+
if err != nil {
21+
logger.SugarLogger.Fatalf("Failed to start server: %v", err)
22+
}
23+
}
24+
25+
func InitializeRouter() *gin.Engine {
26+
if config.IsProduction() {
1727
gin.SetMode(gin.ReleaseMode)
1828
}
1929
r := gin.Default()
@@ -30,7 +40,7 @@ func SetupRouter() *gin.Engine {
3040
}
3141

3242
func InitializeRoutes(router *gin.Engine) {
33-
router.GET("/auth/ping", Ping)
43+
router.GET(fmt.Sprintf("/%s/ping", config.Service.Name), Ping)
3444
router.POST("/auth/login", Login)
3545
router.GET("/users", GetAllUsers)
3646
router.GET("/users/@me", GetCurrentUser)
@@ -39,19 +49,27 @@ func InitializeRoutes(router *gin.Engine) {
3949

4050
func AuthChecker() gin.HandlerFunc {
4151
return func(c *gin.Context) {
52+
if config.SkipAuthCheck {
53+
c.Set("Auth-Token", "mock-token")
54+
c.Set("Auth-UserID", "mock-user")
55+
c.Set("Auth-Audience", "mock-audience")
56+
c.Set("Auth-Scope", "openid profile email")
57+
c.Next()
58+
return
59+
}
4260
if c.GetHeader("Authorization") != "" {
4361
authHeader := c.GetHeader("Authorization")
4462
if strings.HasPrefix(authHeader, "Bearer ") {
4563
claims, err := service.ValidateJWT(strings.Split(c.GetHeader("Authorization"), "Bearer ")[1])
4664
if err != nil {
47-
utils.SugarLogger.Errorln("Failed to validate token: " + err.Error())
65+
logger.SugarLogger.Errorln("Failed to validate token: " + err.Error())
4866
c.AbortWithStatusJSON(401, gin.H{"message": err.Error()})
4967
} else {
50-
utils.SugarLogger.Infof("Decoded token: %s", claims.Subject)
51-
utils.SugarLogger.Infof("↳ Client ID: %s", claims.Audience[0])
52-
utils.SugarLogger.Infof("↳ Scope: %s", claims.Scope)
53-
utils.SugarLogger.Infof("↳ Issued at: %s", claims.IssuedAt.String())
54-
utils.SugarLogger.Infof("↳ Expires at: %s", claims.ExpiresAt.String())
68+
logger.SugarLogger.Infof("Decoded token: %s", claims.Subject)
69+
logger.SugarLogger.Infof("↳ Client ID: %s", claims.Audience[0])
70+
logger.SugarLogger.Infof("↳ Scope: %s", claims.Scope)
71+
logger.SugarLogger.Infof("↳ Issued at: %s", claims.IssuedAt.String())
72+
logger.SugarLogger.Infof("↳ Expires at: %s", claims.ExpiresAt.String())
5573
c.Set("Auth-Token", strings.Split(c.GetHeader("Authorization"), "Bearer ")[1])
5674
c.Set("Auth-UserID", claims.Subject)
5775
c.Set("Auth-Audience", claims.Audience[0])
@@ -70,8 +88,7 @@ func UnauthorizedPanicHandler() gin.HandlerFunc {
7088
if err == "Unauthorized" {
7189
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "you are not authorized to access this resource"})
7290
} else {
73-
// Handle other panics
74-
utils.SugarLogger.Errorf("Unexpected panic: %v", err)
91+
logger.SugarLogger.Errorf("Unexpected panic: %v", err)
7592
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": err.(string)})
7693
}
7794
}
@@ -80,14 +97,12 @@ func UnauthorizedPanicHandler() gin.HandlerFunc {
8097
}
8198
}
8299

83-
// Require checks if a condition is true, otherwise aborts the request
84100
func Require(c *gin.Context, condition bool) {
85101
if !condition {
86102
panic("Unauthorized")
87103
}
88104
}
89105

90-
// Any checks if any condition is true, otherwise returns false
91106
func Any(conditions ...bool) bool {
92107
for _, condition := range conditions {
93108
if condition {
@@ -97,7 +112,6 @@ func Any(conditions ...bool) bool {
97112
return false
98113
}
99114

100-
// All checks if all conditions are true, otherwise returns false
101115
func All(conditions ...bool) bool {
102116
for _, condition := range conditions {
103117
if !condition {

auth/api/auth.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package api
22

33
import (
4-
"auth/service"
54
"net/http"
65

6+
"github.com/gaucho-racing/mapache/auth/service"
77
"github.com/gin-gonic/gin"
88
)
99

@@ -19,4 +19,4 @@ func Login(c *gin.Context) {
1919
return
2020
}
2121
c.JSON(http.StatusOK, token)
22-
}
22+
}

auth/api/ping.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package api
22

33
import (
4-
"auth/config"
54
"net/http"
65

6+
"github.com/gaucho-racing/mapache/auth/config"
77
"github.com/gin-gonic/gin"
88
)
99

0 commit comments

Comments
 (0)