Merge pull request #26 from bayer-int/feature/fix-production-authentication

Feature/fix production authentication
This commit is contained in:
Nirmal Arya 2025-06-16 21:22:00 -04:00 committed by GitHub
commit 544199af79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 262 additions and 165 deletions

View File

@ -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."

View File

@ -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');
// Create session storage
const sessionStorage = createCookieSessionStorage({
cookie: {
name: 'buildify_auth_session',
httpOnly: true,
path: '/',
sameSite: 'lax',
secrets: [sessionSecret],
secure: process.env.NODE_ENV === 'production',
},
});
if (!clientId || !clientSecret) {
console.warn(
'GitHub OAuth is not configured properly. Please set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment variables.'
);
}
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<GitHubUser> {
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<GitHubUser>
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<GitHubUser>
}
}
return {
const user = {
id: userData.id,
login: userData.login,
name: userData.name,
@ -173,69 +249,88 @@ export async function fetchGitHubUser(accessToken: string): Promise<GitHubUser>
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);
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);
// 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
return redirect(redirectTo, {
headers: {
'Set-Cookie': await sessionStorage.commitSession(session, {
maxAge: 60 * 60 * 24 * 7, // 1 week
}),
},
});
// 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<GitHubUser | null> {
const session = await getSession(request);
export async function getUserFromSession(request: Request, context?: any): Promise<GitHubUser | null> {
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<string | null> {
const session = await getSession(request);
export async function getAccessToken(request: Request, context?: any): Promise<string | null> {
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<boolean> {
const user = await getUserFromSession(request);
return user !== null;
export async function isAuthenticated(request: Request, context?: any): Promise<boolean> {
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),
},
});
}

View File

@ -2,7 +2,6 @@ import type { LanguageModelV1 } from 'ai';
import type { ProviderInfo, ProviderConfig, ModelInfo } from './types';
import type { IProviderSetting } from '~/types/model';
import { createOpenAI } from '@ai-sdk/openai';
import { LLMManager } from './manager';
export abstract class BaseProvider implements ProviderInfo {
abstract name: string;
@ -26,7 +25,6 @@ export abstract class BaseProvider implements ProviderInfo {
}) {
const { apiKeys, providerSettings, serverEnv, defaultBaseUrlKey, defaultApiTokenKey } = options;
let settingsBaseUrl = providerSettings?.baseUrl;
const manager = LLMManager.getInstance();
if (settingsBaseUrl && settingsBaseUrl.length == 0) {
settingsBaseUrl = undefined;
@ -37,7 +35,6 @@ export abstract class BaseProvider implements ProviderInfo {
settingsBaseUrl ||
serverEnv?.[baseUrlKey] ||
process?.env?.[baseUrlKey] ||
manager.env?.[baseUrlKey] ||
this.config.baseUrl;
if (baseUrl && baseUrl.endsWith('/')) {
@ -46,7 +43,7 @@ export abstract class BaseProvider implements ProviderInfo {
const apiTokenKey = this.config.apiTokenKey || defaultApiTokenKey;
const apiKey =
apiKeys?.[this.name] || serverEnv?.[apiTokenKey] || process?.env?.[apiTokenKey] || manager.env?.[apiTokenKey];
apiKeys?.[this.name] || serverEnv?.[apiTokenKey] || process?.env?.[apiTokenKey];
return {
baseUrl,

View File

@ -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) {

View File

@ -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');
}
}

View File

@ -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}`);
}
}

View File

@ -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('/');
@ -29,24 +29,34 @@ export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const redirectTo = url.searchParams.get('redirectTo') || '/';
// Check if GitHub OAuth is configured
const clientId = process.env.GITHUB_CLIENT_ID;
const clientSecret = process.env.GITHUB_CLIENT_SECRET;
// Check for authentication error parameters
const authError = url.searchParams.get('error');
const authErrorDescription = url.searchParams.get('error_description');
// 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, {

View File

@ -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() {

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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;
}