From 2340edec943b3b20f4ba6bce06a2b5917fcde2d3 Mon Sep 17 00:00:00 2001 From: Nirmal Arya Date: Mon, 16 Jun 2025 21:20:30 -0400 Subject: [PATCH] github oauth fixes and deployment enhancements --- .github/workflows/ecr-deploy.yaml | 32 ++-- app/lib/auth/github-oauth.server.ts | 237 +++++++++++++++++++-------- app/routes/_index.tsx | 4 +- app/routes/_public.auth.callback.tsx | 36 ---- app/routes/_public.login.tsx | 0 app/routes/auth.callback.tsx | 53 ++++-- app/routes/auth.login.tsx | 38 +++-- app/routes/auth.logout.tsx | 8 +- docker-compose.yaml | 8 + k8s/configmap.yaml | 1 + k8s/deployment.yaml | 2 +- worker-configuration.d.ts | 3 + 12 files changed, 261 insertions(+), 161 deletions(-) delete mode 100644 app/routes/_public.auth.callback.tsx delete mode 100644 app/routes/_public.login.tsx diff --git a/.github/workflows/ecr-deploy.yaml b/.github/workflows/ecr-deploy.yaml index 85e23d84..dadd5714 100644 --- a/.github/workflows/ecr-deploy.yaml +++ b/.github/workflows/ecr-deploy.yaml @@ -109,7 +109,7 @@ jobs: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 - target: buildify-development + target: buildify-production push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} @@ -174,9 +174,9 @@ jobs: fi echo "Image pushed successfully: ${{ steps.ecr-registry.outputs.registry }}:$TAG" - # Create PR for Kubernetes manifests update (only for main branch) + # Create PR for Kubernetes manifests update (for main and dev branches) - name: Create PR for Kubernetes updates - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -192,22 +192,21 @@ jobs: if [[ "${{ github.ref }}" == refs/tags/* ]]; then # For tagged releases, use the tag name IMAGE_TAG="${{ github.ref_name }}" - sed -i "s|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:dev|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:$IMAGE_TAG|g" k8s/deployment.yaml elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - # For main branch, use 'latest' - IMAGE_TAG="latest" - sed -i "s|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:dev|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:$IMAGE_TAG|g" k8s/deployment.yaml + # For main branch, use short SHA for immutable deployments + IMAGE_TAG="sha-${GITHUB_SHA:0:7}" elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then - # For dev branch, use 'dev' - # No need to change as dev is already set as the default tag in deployment.yaml - IMAGE_TAG="dev" - echo "Using dev tag for dev branch - no change needed to deployment.yaml" + # For dev branch, use short SHA for immutable deployments + IMAGE_TAG="sha-${GITHUB_SHA:0:7}" else # For other branches/PRs, use the short SHA - IMAGE_TAG="${GITHUB_SHA:0:7}" - sed -i "s|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:dev|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:$IMAGE_TAG|g" k8s/deployment.yaml + IMAGE_TAG="sha-${GITHUB_SHA:0:7}" fi + # Update deployment file with new image tag + # Use a more flexible pattern to match any existing tag + sed -i "s|891377135844\.dkr\.ecr\.us-east-1\.amazonaws\.com/buildify:[^[:space:]]*|891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:$IMAGE_TAG|g" k8s/deployment.yaml + # Show changes for logging echo "Modified deployment manifest:" cat k8s/deployment.yaml @@ -220,10 +219,13 @@ jobs: git push origin $BRANCH_NAME # Create PR - PR_TITLE="Update Kubernetes deployment to new image" + BRANCH_TYPE=$(echo "${{ github.ref }}" | sed 's|refs/heads/||') + PR_TITLE="Update Kubernetes deployment to new image (${BRANCH_TYPE})" PR_BODY="This PR updates the Kubernetes deployment to use the latest image built from commit ${GITHUB_SHA}. - Image: ${{ steps.ecr-registry.outputs.registry }}:$IMAGE_TAG + **Branch:** ${BRANCH_TYPE} + **Commit:** ${GITHUB_SHA} + **Image:** ${{ steps.ecr-registry.outputs.registry }}:$IMAGE_TAG This PR was automatically generated by the CI/CD pipeline." diff --git a/app/lib/auth/github-oauth.server.ts b/app/lib/auth/github-oauth.server.ts index cc7392f6..7c73ebbb 100644 --- a/app/lib/auth/github-oauth.server.ts +++ b/app/lib/auth/github-oauth.server.ts @@ -44,41 +44,99 @@ export class AuthError extends Error { } } -// Get environment variables -const clientId = process.env.GITHUB_CLIENT_ID; -const clientSecret = process.env.GITHUB_CLIENT_SECRET; -const sessionSecret = process.env.SESSION_SECRET || 'buildify-session-secret'; +// Global environment variable cache to ensure consistency across context availability +let globalEnvCache: { [key: string]: string } = {}; -// Validate required environment variables -if (!clientId || !clientSecret) { - console.warn( - 'GitHub OAuth is not configured properly. Please set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment variables.' - ); +// Helper function to get environment variables from context or process.env +function getEnvVar(context: any, key: string, defaultValue: string = ''): string { + // Use cached global value if available + if (globalEnvCache[key]) { + return globalEnvCache[key]; + } + + let value = ''; + + // Try context.cloudflare.env first (Cloudflare Workers with wrangler bindings) + if (context?.cloudflare?.env?.[key]) { + value = context.cloudflare.env[key]; + } + // Try context.env (other Cloudflare Workers setups) + else if (context?.env?.[key]) { + value = context.env[key]; + } + // Fallback to process.env (Node.js) + else { + value = process.env[key] || defaultValue; + } + + // Cache environment variables globally for consistency + if (value && !globalEnvCache[key]) { + globalEnvCache[key] = value; + } + + return value; } -// Create OAuth app instance -export const oauthApp = new OAuthApp({ - clientId: clientId || '', - clientSecret: clientSecret || '', - defaultScopes: ['read:user', 'user:email'], -}); +// Create OAuth app instance with environment variables +function createOAuthApp(context?: any) { + const clientId = getEnvVar(context, 'GITHUB_CLIENT_ID'); + const clientSecret = getEnvVar(context, 'GITHUB_CLIENT_SECRET'); + + + if (!clientId || !clientSecret) { + console.warn( + 'GitHub OAuth is not configured properly. Please set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment variables.' + ); + } -// Create session storage -const sessionStorage = createCookieSessionStorage({ - cookie: { - name: 'buildify_auth_session', - httpOnly: true, - path: '/', - sameSite: 'lax', - secrets: [sessionSecret], - secure: process.env.NODE_ENV === 'production', - }, -}); + return new OAuthApp({ + clientId: clientId || '', + clientSecret: clientSecret || '', + defaultScopes: ['read:user', 'user:email'], + }); +} + +// Create session storage with context-aware secrets +function createSessionStorage(context?: any, request?: Request) { + const sessionSecret = getEnvVar(context, 'SESSION_SECRET', 'buildify-session-secret'); + + // Determine if we should use secure cookies based on environment and protocol + let secure = false; + + // Check if we're in production environment + const isProduction = process.env.NODE_ENV === 'production'; + + if (isProduction) { + // In production, check for HTTPS indicators + if (request) { + const proto = request.headers.get('x-forwarded-proto'); + const host = request.headers.get('host'); + // Use secure cookies if we have HTTPS indicators or production domain + secure = proto === 'https' || host?.includes('phexhub-np.int.bayer.com') || false; + } else { + // Default to secure in production if no request context + secure = true; + } + } + + + return createCookieSessionStorage({ + cookie: { + name: 'buildify_auth_session', + httpOnly: true, + path: '/', + sameSite: 'lax', + secrets: [sessionSecret], + secure, + }, + }); +} // Get session from request -export async function getSession(request: Request) { +export async function getSession(request: Request, context?: any) { const cookie = request.headers.get('Cookie'); - return sessionStorage.getSession(cookie); + const storage = createSessionStorage(context, request); + return storage.getSession(cookie); } // Generate state parameter for OAuth flow to prevent CSRF attacks @@ -87,28 +145,34 @@ export function generateState() { } // Store state in session -export async function storeState(request: Request, state: string) { - const session = await getSession(request); +export async function storeState(request: Request, state: string, context?: any) { + const session = await getSession(request, context); session.set('oauth:state', state); - return sessionStorage.commitSession(session); + + + const storage = createSessionStorage(context, request); + return storage.commitSession(session); } // Verify state from session -export async function verifyState(request: Request, state: string) { - const session = await getSession(request); +export async function verifyState(request: Request, state: string, context?: any) { + const session = await getSession(request, context); const storedState = session.get('oauth:state'); + if (!storedState || storedState !== state) { - throw new AuthError('Invalid state parameter. Possible CSRF attack.'); + throw new AuthError(`Invalid state parameter. Expected: ${storedState}, Got: ${state}`); } // Clear the state after verification session.unset('oauth:state'); - return sessionStorage.commitSession(session); + const storage = createSessionStorage(context, request); + return storage.commitSession(session); } // Generate authorization URL -export function getAuthorizationUrl(state: string, redirectUri?: string) { +export function getAuthorizationUrl(state: string, redirectUri?: string, context?: any) { + const oauthApp = createOAuthApp(context); return oauthApp.getWebFlowAuthorizationUrl({ state, redirectUrl: redirectUri, @@ -116,18 +180,23 @@ export function getAuthorizationUrl(state: string, redirectUri?: string) { } // Exchange code for token -export async function exchangeCodeForToken(code: string, state: string) { +export async function exchangeCodeForToken(code: string, state: string, context?: any) { try { + console.log('🔑 Token exchange: Starting with code length:', code?.length); + const oauthApp = createOAuthApp(context); + console.log('🔑 Token exchange: OAuth app created'); + const { authentication } = await oauthApp.createToken({ code, state, }); + console.log('🔑 Token exchange: GitHub responded successfully'); return { accessToken: authentication.token, }; } catch (error) { - console.error('Error exchanging code for token:', error); + console.error('🔑 Token exchange: Failed -', error); throw new AuthError('Failed to exchange code for token'); } } @@ -135,18 +204,24 @@ export async function exchangeCodeForToken(code: string, state: string) { // Fetch user data from GitHub API export async function fetchGitHubUser(accessToken: string): Promise { try { + console.log('👤 User fetch: Starting with token length:', accessToken?.length); const response = await fetch('https://api.github.com/user', { headers: { Accept: 'application/vnd.github.v3+json', - Authorization: `token ${accessToken}`, + Authorization: `Bearer ${accessToken}`, + 'User-Agent': 'Buildify-App/1.0', }, }); + console.log('👤 User fetch: GitHub API response status:', response.status); if (!response.ok) { - throw new Error(`GitHub API responded with ${response.status}`); + const errorText = await response.text(); + console.error('👤 User fetch: GitHub API error response:', errorText); + throw new Error(`GitHub API responded with ${response.status}: ${errorText}`); } const userData = await response.json() as GitHubUserResponse; + console.log('👤 User fetch: User data received for:', userData.login); // If email is not public, try to get primary email let email = userData.email; @@ -154,7 +229,8 @@ export async function fetchGitHubUser(accessToken: string): Promise const emailsResponse = await fetch('https://api.github.com/user/emails', { headers: { Accept: 'application/vnd.github.v3+json', - Authorization: `token ${accessToken}`, + Authorization: `Bearer ${accessToken}`, + 'User-Agent': 'Buildify-App/1.0', }, }); @@ -165,7 +241,7 @@ export async function fetchGitHubUser(accessToken: string): Promise } } - return { + const user = { id: userData.id, login: userData.login, name: userData.name, @@ -173,69 +249,88 @@ export async function fetchGitHubUser(accessToken: string): Promise avatar_url: userData.avatar_url, html_url: userData.html_url, }; + console.log('👤 User fetch: Successfully processed user data'); + return user; } catch (error) { - console.error('Error fetching GitHub user:', error); + console.error('👤 User fetch: Failed -', error); throw new AuthError('Failed to fetch user data from GitHub'); } } // Create user session -export async function createUserSession(request: Request, authSession: AuthSession, redirectTo: string) { - const session = await getSession(request); - - // Store user data in session - session.set('auth:user', authSession.user); - session.set('auth:accessToken', authSession.accessToken); - - // Commit session and redirect - return redirect(redirectTo, { - headers: { - 'Set-Cookie': await sessionStorage.commitSession(session, { - maxAge: 60 * 60 * 24 * 7, // 1 week - }), - }, - }); +export async function createUserSession(request: Request, authSession: AuthSession, redirectTo: string, context?: any) { + try { + console.log('💾 Session create: Starting for user:', authSession.user.login); + const session = await getSession(request, context); + console.log('💾 Session create: Session retrieved'); + + // Store user data in session + session.set('auth:user', authSession.user); + session.set('auth:accessToken', authSession.accessToken); + console.log('💾 Session create: User data stored in session'); + + // Commit session and redirect + const storage = createSessionStorage(context, request); + console.log('💾 Session create: Session storage created'); + + const result = redirect(redirectTo, { + headers: { + 'Set-Cookie': await storage.commitSession(session, { + maxAge: 60 * 60 * 24 * 7, // 1 week + }), + }, + }); + console.log('💾 Session create: Redirect prepared to:', redirectTo); + return result; + } catch (error) { + console.error('💾 Session create: Failed -', error); + throw new AuthError('Failed to create user session'); + } } // Get user from session -export async function getUserFromSession(request: Request): Promise { - const session = await getSession(request); +export async function getUserFromSession(request: Request, context?: any): Promise { + const session = await getSession(request, context); const user = session.get('auth:user'); return user || null; } // Get access token from session -export async function getAccessToken(request: Request): Promise { - const session = await getSession(request); +export async function getAccessToken(request: Request, context?: any): Promise { + const session = await getSession(request, context); const accessToken = session.get('auth:accessToken'); return accessToken || null; } // Check if user is authenticated -export async function isAuthenticated(request: Request): Promise { - const user = await getUserFromSession(request); - return user !== null; +export async function isAuthenticated(request: Request, context?: any): Promise { + const user = await getUserFromSession(request, context); + const result = user !== null; + + + return result; } // Require authentication -export async function requireAuthentication(request: Request, redirectTo: string = '/login') { - const authenticated = await isAuthenticated(request); +export async function requireAuthentication(request: Request, redirectTo: string = '/login', context?: any) { + const authenticated = await isAuthenticated(request, context); if (!authenticated) { const searchParams = new URLSearchParams([['redirectTo', request.url]]); throw redirect(`${redirectTo}?${searchParams}`); } - return await getUserFromSession(request); + return await getUserFromSession(request, context); } // Logout - destroy session -export async function logout(request: Request, redirectTo: string = '/') { - const session = await getSession(request); +export async function logout(request: Request, redirectTo: string = '/', context?: any) { + const session = await getSession(request, context); + const storage = createSessionStorage(context, request); return redirect(redirectTo, { headers: { - 'Set-Cookie': await sessionStorage.destroySession(session), + 'Set-Cookie': await storage.destroySession(session), }, }); } diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index b61cfb25..8d23a88d 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -14,9 +14,9 @@ export const meta: MetaFunction = () => { * Root loader that checks authentication status * If user is not authenticated, redirect to the login page */ -export async function loader({ request }: LoaderFunctionArgs) { +export async function loader({ request, context }: LoaderFunctionArgs) { // Check if user is authenticated - const authenticated = await isAuthenticated(request); + const authenticated = await isAuthenticated(request, context); // If not authenticated, redirect to login page if (!authenticated) { diff --git a/app/routes/_public.auth.callback.tsx b/app/routes/_public.auth.callback.tsx deleted file mode 100644 index 296fb160..00000000 --- a/app/routes/_public.auth.callback.tsx +++ /dev/null @@ -1,36 +0,0 @@ -// @ts-nocheck -import { json, redirect, type LoaderFunctionArgs } from '@remix-run/cloudflare'; -import { createUserSession, exchangeCodeForToken, fetchGitHubUser, verifyState } from '~/lib/auth/github-oauth.server'; - -export async function loader({ request }: LoaderFunctionArgs) { - const url = new URL(request.url); - const code = url.searchParams.get('code'); - const state = url.searchParams.get('state'); - - // Check if code and state are present - if (!code || !state) { - return json({ error: 'Missing required OAuth parameters' }, { status: 400 }); - } - - try { - // Verify state parameter to prevent CSRF attacks - const cookie = await verifyState(request, state); - - // Exchange code for access token - const { accessToken } = await exchangeCodeForToken(code, state); - - // Fetch user data from GitHub API - const user = await fetchGitHubUser(accessToken); - - // Create user session and redirect to home - return createUserSession( - request, - { user, accessToken }, - '/', // Redirect to home page after successful login - ); - } catch (error) { - console.error('Authentication error:', error); - - return redirect('/login?error=authentication_failed'); - } -} diff --git a/app/routes/_public.login.tsx b/app/routes/_public.login.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/app/routes/auth.callback.tsx b/app/routes/auth.callback.tsx index 1fbd3efc..027d32c1 100644 --- a/app/routes/auth.callback.tsx +++ b/app/routes/auth.callback.tsx @@ -16,7 +16,7 @@ export const meta: MetaFunction = () => { ]; }; -export async function loader({ request }: LoaderFunctionArgs) { +export async function loader({ request, context }: LoaderFunctionArgs) { // Get URL parameters const url = new URL(request.url); const code = url.searchParams.get('code'); @@ -39,35 +39,51 @@ export async function loader({ request }: LoaderFunctionArgs) { // Validate required parameters if (!code || !state) { - return json({ - success: false, - error: 'invalid_request', - errorDescription: 'Missing required parameters', - redirectTo: '/login', - }); + const errorParams = new URLSearchParams([ + ['error', 'invalid_request'], + ['error_description', 'Missing required parameters'] + ]); + return redirect(`/auth/login?${errorParams}`); } try { + console.log('=== CALLBACK FLOW DEBUG ==='); + console.log('Step 1: Starting state verification...'); + // Verify state parameter to prevent CSRF attacks - const cookieHeader = await verifyState(request, state); + const cookieHeader = await verifyState(request, state, context); + console.log('Step 1: ✅ State verification successful'); + console.log('Step 2: Starting token exchange...'); // Exchange authorization code for access token - const { accessToken } = await exchangeCodeForToken(code, state); + const { accessToken } = await exchangeCodeForToken(code, state, context); + console.log('Step 2: ✅ Token exchange successful'); + console.log('Step 3: Starting user data fetch...'); // Fetch user data from GitHub API const user = await fetchGitHubUser(accessToken); + console.log('Step 3: ✅ User data fetch successful'); + console.log('Step 4: Creating user session...'); // Create user session and redirect - return createUserSession( + const result = await createUserSession( request, { accessToken, user, }, - redirectTo + redirectTo, + context ); + console.log('Step 4: ✅ User session created successfully'); + console.log('============================'); + return result; } catch (error) { - console.error('Authentication error:', error); + console.error('=== AUTHENTICATION FAILURE ==='); + console.error('Error type:', error.constructor.name); + console.error('Error message:', error.message); + console.error('Error stack:', error.stack); + console.error('==============================='); let errorMessage = 'An unexpected error occurred during authentication'; let errorCode = 'server_error'; @@ -77,12 +93,13 @@ export async function loader({ request }: LoaderFunctionArgs) { errorCode = 'auth_error'; } - return json({ - success: false, - error: errorCode, - errorDescription: errorMessage, - redirectTo: '/login', - }); + // For authentication failures, redirect to login with error params + const errorParams = new URLSearchParams([ + ['error', errorCode], + ['error_description', errorMessage] + ]); + + return redirect(`/auth/login?${errorParams}`); } } diff --git a/app/routes/auth.login.tsx b/app/routes/auth.login.tsx index 661657ca..d0633777 100644 --- a/app/routes/auth.login.tsx +++ b/app/routes/auth.login.tsx @@ -17,9 +17,9 @@ export const meta: MetaFunction = () => { ]; }; -export async function loader({ request }: LoaderFunctionArgs) { +export async function loader({ request, context }: LoaderFunctionArgs) { // Check if user is already authenticated - const authenticated = await isAuthenticated(request); + const authenticated = await isAuthenticated(request, context); if (authenticated) { // Redirect to home page if already logged in return redirect('/'); @@ -28,25 +28,35 @@ export async function loader({ request }: LoaderFunctionArgs) { // Get redirect URL from query params (if any) const url = new URL(request.url); const redirectTo = url.searchParams.get('redirectTo') || '/'; + + // Check for authentication error parameters + const authError = url.searchParams.get('error'); + const authErrorDescription = url.searchParams.get('error_description'); - // Check if GitHub OAuth is configured - const clientId = process.env.GITHUB_CLIENT_ID; - const clientSecret = process.env.GITHUB_CLIENT_SECRET; + // Check if GitHub OAuth is configured using context + const clientId = (context?.cloudflare?.env?.GITHUB_CLIENT_ID) || (context?.env?.GITHUB_CLIENT_ID) || process.env.GITHUB_CLIENT_ID; + const clientSecret = (context?.cloudflare?.env?.GITHUB_CLIENT_SECRET) || (context?.env?.GITHUB_CLIENT_SECRET) || process.env.GITHUB_CLIENT_SECRET; const isConfigured = Boolean(clientId && clientSecret); + + // Determine the error message to display + let errorMessage = null; + if (authError) { + errorMessage = authErrorDescription || 'Authentication failed. Please try again.'; + } else if (!isConfigured) { + errorMessage = 'GitHub OAuth is not configured. Please set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment variables.'; + } return json({ redirectTo, isConfigured, - error: isConfigured - ? null - : 'GitHub OAuth is not configured. Please set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment variables.', + error: errorMessage, }); } -export async function action({ request }: ActionFunctionArgs) { - // Check if GitHub OAuth is configured - const clientId = process.env.GITHUB_CLIENT_ID; - const clientSecret = process.env.GITHUB_CLIENT_SECRET; +export async function action({ request, context }: ActionFunctionArgs) { + // Check if GitHub OAuth is configured using context + const clientId = (context?.cloudflare?.env?.GITHUB_CLIENT_ID) || (context?.env?.GITHUB_CLIENT_ID) || process.env.GITHUB_CLIENT_ID; + const clientSecret = (context?.cloudflare?.env?.GITHUB_CLIENT_SECRET) || (context?.env?.GITHUB_CLIENT_SECRET) || process.env.GITHUB_CLIENT_SECRET; if (!clientId || !clientSecret) { return json( @@ -71,10 +81,10 @@ export async function action({ request }: ActionFunctionArgs) { const callbackUrl = `${url.origin}/auth/callback`; // Generate authorization URL - const { url: authorizationUrl } = getAuthorizationUrl(state, callbackUrl); + const { url: authorizationUrl } = getAuthorizationUrl(state, callbackUrl, context); // Store state in session - const cookie = await storeState(request, state); + const cookie = await storeState(request, state, context); // Redirect to GitHub authorization URL return redirect(authorizationUrl, { diff --git a/app/routes/auth.logout.tsx b/app/routes/auth.logout.tsx index d2a42255..ab78ec7b 100644 --- a/app/routes/auth.logout.tsx +++ b/app/routes/auth.logout.tsx @@ -12,13 +12,13 @@ export const meta: MetaFunction = () => { ]; }; -export async function loader({ request }: LoaderFunctionArgs) { +export async function loader({ request, context }: LoaderFunctionArgs) { // Get URL parameters const url = new URL(request.url); const redirectTo = url.searchParams.get('redirectTo') || '/'; // Get user data to display in the confirmation page - const user = await getUserFromSession(request); + const user = await getUserFromSession(request, context); return json({ redirectTo, @@ -26,13 +26,13 @@ export async function loader({ request }: LoaderFunctionArgs) { }); } -export async function action({ request }: ActionFunctionArgs) { +export async function action({ request, context }: ActionFunctionArgs) { // Get form data const formData = await request.formData(); const redirectTo = formData.get('redirectTo')?.toString() || '/'; // Perform logout and redirect - return logout(request, redirectTo); + return logout(request, redirectTo, context); } export default function Logout() { diff --git a/docker-compose.yaml b/docker-compose.yaml index 5793e580..1f9a8ff0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -27,6 +27,10 @@ services: - VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug} - DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768} - RUNNING_IN_DOCKER=true + # GitHub OAuth environment variables + - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID} + - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET} + - SESSION_SECRET=${SESSION_SECRET} extra_hosts: - 'host.docker.internal:host-gateway' command: pnpm run dockerstart @@ -60,6 +64,10 @@ services: - VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug} - DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768} - RUNNING_IN_DOCKER=true + # GitHub OAuth environment variables + - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID} + - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET} + - SESSION_SECRET=${SESSION_SECRET} extra_hosts: - 'host.docker.internal:host-gateway' volumes: diff --git a/k8s/configmap.yaml b/k8s/configmap.yaml index c9fae732..f529f165 100644 --- a/k8s/configmap.yaml +++ b/k8s/configmap.yaml @@ -5,5 +5,6 @@ metadata: namespace: buildify data: RUNNING_IN_DOCKER: "true" + NODE_ENV: "production" VITE_LOG_LEVEL: "info" # Add other non-sensitive configuration here \ No newline at end of file diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 89cc86a1..bb55a6bf 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -23,7 +23,7 @@ spec: serviceAccountName: ecr-service-account containers: - name: buildify - image: 891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:development + image: 891377135844.dkr.ecr.us-east-1.amazonaws.com/buildify:sha-placeholder imagePullPolicy: Always ports: - containerPort: 5173 diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index b2ae1ce7..23c65f9f 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -18,4 +18,7 @@ interface Env { XAI_API_KEY: string; PERPLEXITY_API_KEY: string; AWS_BEDROCK_CONFIG: string; + GITHUB_CLIENT_ID: string; + GITHUB_CLIENT_SECRET: string; + SESSION_SECRET: string; }