Skip to content

Commit 8dcda7d

Browse files
authored
Merge pull request #45 from VectorInstitute/add-catalog-analytics-auth
Add catalog analytics auth
2 parents f367ffe + ab910d9 commit 8dcda7d

35 files changed

+17303
-91
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
name: Deploy Catalog Analytics (Cloud Run)
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'catalog-analytics/**'
8+
- 'catalog/public/data/**'
9+
- '.github/workflows/deploy-catalog-analytics.yml'
10+
workflow_dispatch:
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: false
15+
16+
env:
17+
PROJECT_ID: coderd
18+
GAR_LOCATION: us-central1
19+
REPOSITORY: catalog
20+
SERVICE_NAME: catalog-analytics
21+
REGION: us-central1
22+
23+
jobs:
24+
build-and-deploy:
25+
name: Build and Deploy to Cloud Run
26+
runs-on: ubuntu-latest
27+
permissions:
28+
contents: read
29+
id-token: write
30+
31+
steps:
32+
- name: Checkout code
33+
uses: actions/checkout@v4
34+
35+
- name: Free up disk space
36+
run: |
37+
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/share/boost "$AGENT_TOOLSDIRECTORY"
38+
docker system prune -af --volumes
39+
40+
- name: Set up Docker Buildx
41+
uses: docker/setup-buildx-action@v3
42+
43+
- name: Authenticate to Google Cloud
44+
uses: google-github-actions/auth@v2
45+
with:
46+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
47+
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
48+
token_format: access_token
49+
50+
- name: Set up Cloud SDK
51+
uses: google-github-actions/setup-gcloud@v2
52+
53+
- name: Configure Docker for Artifact Registry
54+
run: |
55+
gcloud auth configure-docker ${{ env.GAR_LOCATION }}-docker.pkg.dev --quiet
56+
57+
- name: Create Artifact Registry repository
58+
run: |
59+
if ! gcloud artifacts repositories describe ${{ env.REPOSITORY }} \
60+
--location=${{ env.GAR_LOCATION }} \
61+
--format="get(name)" 2>/dev/null; then
62+
echo "Creating Artifact Registry repository"
63+
gcloud artifacts repositories create ${{ env.REPOSITORY }} \
64+
--repository-format=docker \
65+
--location=${{ env.GAR_LOCATION }} \
66+
--description="Docker repository for Catalog services"
67+
echo "✓ Repository created"
68+
else
69+
echo "✓ Repository exists"
70+
fi
71+
72+
- name: Copy data files from catalog
73+
run: |
74+
mkdir -p catalog-analytics/public/data
75+
if [ -d "catalog/public/data" ]; then
76+
cp -r catalog/public/data/* catalog-analytics/public/data/ || true
77+
fi
78+
echo "✓ Data files copied"
79+
80+
- name: Build and push Docker image
81+
run: |
82+
IMAGE_URL="${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE_NAME }}:${{ github.sha }}"
83+
LATEST_URL="${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE_NAME }}:latest"
84+
85+
docker build \
86+
-t "$IMAGE_URL" \
87+
-t "$LATEST_URL" \
88+
--cache-from type=gha,scope=catalog-analytics \
89+
--cache-to type=gha,mode=max,scope=catalog-analytics \
90+
catalog-analytics/
91+
92+
docker push "$IMAGE_URL"
93+
docker push "$LATEST_URL"
94+
95+
echo "✓ Image pushed: $IMAGE_URL"
96+
echo "image=$IMAGE_URL" >> $GITHUB_OUTPUT
97+
id: build
98+
99+
- name: Deploy to Cloud Run
100+
id: deploy
101+
run: |
102+
gcloud run deploy ${{ env.SERVICE_NAME }} \
103+
--image ${{ steps.build.outputs.image }} \
104+
--region ${{ env.REGION }} \
105+
--platform managed \
106+
--allow-unauthenticated \
107+
--memory=1Gi \
108+
--cpu=1 \
109+
--timeout=300s \
110+
--max-instances=10 \
111+
--min-instances=0 \
112+
--concurrency=80 \
113+
--port=8080 \
114+
--set-env-vars="NODE_ENV=production,NEXT_PUBLIC_GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }},GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }},SESSION_SECRET=${{ secrets.SESSION_SECRET }},NEXT_PUBLIC_APP_URL=https://catalog.vectorinstitute.ai,REDIRECT_URI=https://catalog.vectorinstitute.ai/analytics/api/auth/callback,ALLOWED_DOMAINS=vectorinstitute.ai" \
115+
--update-labels="deployed-by=github-actions,commit=${{ github.sha }},service=catalog-analytics" \
116+
--quiet
117+
118+
SERVICE_URL=$(gcloud run services describe ${{ env.SERVICE_NAME }} \
119+
--region ${{ env.REGION }} \
120+
--format 'value(status.url)')
121+
122+
echo "url=$SERVICE_URL" >> $GITHUB_OUTPUT
123+
echo "✓ Service deployed at $SERVICE_URL"
124+
125+
- name: Verify deployment
126+
run: |
127+
SERVICE_URL="${{ steps.deploy.outputs.url }}"
128+
echo "Verifying deployment at $SERVICE_URL..."
129+
130+
MAX_RETRIES=20
131+
for i in $(seq 1 $MAX_RETRIES); do
132+
if curl -sf --max-time 10 "${SERVICE_URL}/login" > /dev/null 2>&1; then
133+
echo "✓ Service is responding"
134+
exit 0
135+
fi
136+
echo "Attempt $i/$MAX_RETRIES failed, waiting..."
137+
sleep 5
138+
done
139+
140+
echo "✗ Deployment verification failed"
141+
exit 1
142+
143+
- name: Output deployment summary
144+
run: |
145+
cat >> $GITHUB_STEP_SUMMARY << EOF
146+
## 🚀 Catalog Analytics Deployed
147+
148+
**Service URL:** ${{ steps.deploy.outputs.url }}
149+
**Commit:** \`${{ github.sha }}\`
150+
**Region:** ${{ env.REGION }}
151+
152+
### Next Steps
153+
Configure load balancer to route:
154+
- \`catalog.vectorinstitute.ai/analytics/*\` → Cloud Run service
155+
- \`catalog.vectorinstitute.ai/*\` → GCS backend (existing)
156+
157+
**Cloud Run Service:** \`${{ env.SERVICE_NAME }}\`
158+
EOF

.github/workflows/deploy-catalog.yml

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

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ repos:
3838
hooks:
3939
- id: typos
4040
args: []
41-
exclude: ^(catalog/public/data/repositories.json|catalog/public/data/papers\.bib|catalog/public/data/github_metrics.json|catalog/public/data/github_metrics_history.json|repositories/crisp-nam\.yaml)$
41+
exclude: ^(catalog/public/data/.*\.json|catalog/public/data/papers\.bib|catalog-analytics/public/data/.*\.json|repositories/crisp-nam\.yaml)$
4242

4343
- repo: local
4444
hooks:

catalog-analytics/.dockerignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Dockerfile
2+
.dockerignore
3+
node_modules
4+
npm-debug.log
5+
README.md
6+
.next
7+
.git
8+
.gitignore
9+
.env*.local

catalog-analytics/.env.example

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Google OAuth Configuration
2+
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
3+
GOOGLE_CLIENT_SECRET=your-client-secret
4+
5+
# Session Configuration
6+
SESSION_SECRET=generate-a-secure-random-string-at-least-32-characters-long
7+
8+
# App Configuration
9+
NEXT_PUBLIC_APP_URL=https://catalog.vectorinstitute.ai
10+
REDIRECT_URI=https://catalog.vectorinstitute.ai/analytics/api/auth/callback
11+
12+
# Domain Restrictions (comma-separated)
13+
ALLOWED_DOMAINS=vectorinstitute.ai

catalog-analytics/.gitignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# dependencies
2+
/node_modules
3+
/.pnp
4+
.pnp.*
5+
.yarn/*
6+
!.yarn/patches
7+
!.yarn/plugins
8+
!.yarn/releases
9+
!.yarn/versions
10+
11+
# testing
12+
/coverage
13+
14+
# next.js
15+
/.next/
16+
/out/
17+
18+
# production
19+
/build
20+
21+
# misc
22+
.DS_Store
23+
*.pem
24+
25+
# debug
26+
npm-debug.log*
27+
yarn-debug.log*
28+
yarn-error.log*
29+
30+
# local env files
31+
.env*.local
32+
.env
33+
34+
# vercel
35+
.vercel
36+
37+
# typescript
38+
*.tsbuildinfo
39+
next-env.d.ts

catalog-analytics/Dockerfile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Multi-stage build for Next.js on Cloud Run
2+
FROM node:20-alpine AS base
3+
4+
# Install dependencies only when needed
5+
FROM base AS deps
6+
RUN apk add --no-cache libc6-compat
7+
WORKDIR /app
8+
9+
# Copy package files
10+
COPY package.json package-lock.json* ./
11+
RUN npm ci
12+
13+
# Rebuild the source code only when needed
14+
FROM base AS builder
15+
WORKDIR /app
16+
COPY --from=deps /app/node_modules ./node_modules
17+
COPY . .
18+
19+
# Disable telemetry during build
20+
ENV NEXT_TELEMETRY_DISABLED=1
21+
22+
# Build the application
23+
RUN npm run build
24+
25+
# Production image, copy all the files and run next
26+
FROM base AS runner
27+
WORKDIR /app
28+
29+
ENV NODE_ENV=production
30+
ENV NEXT_TELEMETRY_DISABLED=1
31+
32+
# Install curl for health checks
33+
RUN apk add --no-cache curl
34+
35+
# Create a non-root user for security
36+
RUN addgroup --system --gid 1001 nodejs
37+
RUN adduser --system --uid 1001 nextjs
38+
39+
# Copy public directory from builder
40+
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
41+
42+
# Set the correct permission for prerender cache
43+
RUN mkdir .next
44+
RUN chown nextjs:nodejs .next
45+
46+
# Automatically leverage output traces to reduce image size
47+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
48+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
49+
50+
USER nextjs
51+
52+
# Expose the port
53+
EXPOSE 8080
54+
55+
ENV PORT=8080
56+
ENV HOSTNAME="0.0.0.0"
57+
58+
# Run the application
59+
CMD ["node", "server.js"]

0 commit comments

Comments
 (0)