mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
feat: standalone mpc-api deployment, implicit OAuth flow, E2E tests
- Separate mpc-api into its own Deployment with --cluster-url proxy to mpc-node-0 - Switch OAuth from authorization code flow to implicit flow (response_type=token) - Add Playwright E2E tests for Lux ID login flow and OIDC discovery - Update CI to apply api-deployment.yaml and wait for mpc-api rollout
This commit is contained in:
@@ -142,6 +142,7 @@ jobs:
|
||||
- name: Apply MPC nodes and API
|
||||
run: |
|
||||
kubectl apply -f k8s/api-service.yaml
|
||||
kubectl apply -f k8s/api-deployment.yaml
|
||||
kubectl apply -f k8s/mpc-statefulset.yaml
|
||||
|
||||
- name: Apply dashboard
|
||||
@@ -162,4 +163,5 @@ jobs:
|
||||
- name: Wait for rollout
|
||||
run: |
|
||||
kubectl rollout status statefulset/mpc-node -n lux-mpc --timeout=300s
|
||||
kubectl rollout status deployment/mpc-api -n lux-mpc --timeout=180s
|
||||
kubectl rollout status deployment/mpc-dashboard -n lux-mpc --timeout=180s
|
||||
|
||||
@@ -6,25 +6,33 @@ import { setTokens, setUserEmail } from '@/lib/auth'
|
||||
import { getBranding } from '@/lib/branding'
|
||||
import { api } from '@/lib/api'
|
||||
|
||||
function OidcCallbackInner() {
|
||||
function CallbackInner() {
|
||||
const router = useRouter()
|
||||
const params = useSearchParams()
|
||||
const searchParams = useSearchParams()
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [status, setStatus] = useState('Completing sign in…')
|
||||
|
||||
useEffect(() => {
|
||||
const code = params.get('code')
|
||||
const state = params.get('state')
|
||||
const oauthError = params.get('error')
|
||||
const oauthErrorDesc = params.get('error_description')
|
||||
|
||||
// Check for error in query params (OAuth error redirects)
|
||||
const oauthError = searchParams.get('error')
|
||||
const oauthErrorDesc = searchParams.get('error_description')
|
||||
if (oauthError) {
|
||||
setError(oauthErrorDesc ?? oauthError)
|
||||
return
|
||||
}
|
||||
|
||||
if (!code) return
|
||||
// Implicit flow: access_token is in the URL hash fragment
|
||||
const hash = window.location.hash.substring(1)
|
||||
const params = new URLSearchParams(hash)
|
||||
const accessToken = params.get('access_token')
|
||||
const state = params.get('state')
|
||||
|
||||
if (!accessToken) {
|
||||
setError('No access token received from identity provider')
|
||||
return
|
||||
}
|
||||
|
||||
// Validate state to prevent CSRF
|
||||
const savedState = sessionStorage.getItem('oidc_state')
|
||||
if (savedState && state !== savedState) {
|
||||
setError('Invalid state parameter — possible CSRF attack')
|
||||
@@ -33,49 +41,23 @@ function OidcCallbackInner() {
|
||||
sessionStorage.removeItem('oidc_state')
|
||||
|
||||
const branding = getBranding(window.location.hostname)
|
||||
const redirectUri = `${window.location.origin}/auth/callback`
|
||||
|
||||
setStatus('Exchanging authorization code…')
|
||||
setStatus('Authenticating with MPC API…')
|
||||
|
||||
// Step 1: Exchange code for Lux ID access token
|
||||
fetch(`${branding.iamUrl}/api/login/oauth/access_token`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
code,
|
||||
redirect_uri: redirectUri,
|
||||
client_id: branding.iamClientId,
|
||||
}),
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (!res.ok) {
|
||||
const body = await res.text()
|
||||
throw new Error(`Token exchange failed: ${body}`)
|
||||
}
|
||||
return res.json() as Promise<{
|
||||
access_token: string
|
||||
refresh_token?: string
|
||||
}>
|
||||
})
|
||||
.then(async (oidcData) => {
|
||||
setStatus('Authenticating with MPC API…')
|
||||
|
||||
// Step 2: Exchange the OIDC token for a local MPC API JWT
|
||||
const mpcAuth = await api.oidcExchange(oidcData.access_token, branding.iamUrl)
|
||||
|
||||
// Store the MPC API tokens (NOT the Lux ID token)
|
||||
// Exchange the OIDC access token for a local MPC API JWT
|
||||
api
|
||||
.oidcExchange(accessToken, branding.iamUrl)
|
||||
.then((mpcAuth) => {
|
||||
setTokens(mpcAuth.access_token, mpcAuth.refresh_token)
|
||||
if (mpcAuth.email) {
|
||||
setUserEmail(mpcAuth.email)
|
||||
}
|
||||
|
||||
router.replace('/dashboard')
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
setError(err instanceof Error ? err.message : 'Authentication failed')
|
||||
})
|
||||
}, [params, router])
|
||||
}, [searchParams, router])
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
@@ -114,7 +96,7 @@ export default function OidcCallbackPage() {
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<OidcCallbackInner />
|
||||
<CallbackInner />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ function buildLoginUrl(branding: Branding): string {
|
||||
sessionStorage.setItem('oidc_state', state)
|
||||
|
||||
const params = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
response_type: 'token',
|
||||
client_id: branding.iamClientId,
|
||||
redirect_uri: redirectUri,
|
||||
scope: 'openid profile email',
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const IAM_URL = process.env.IAM_URL ?? 'https://lux.id'
|
||||
|
||||
/**
|
||||
* E2E tests for the full Lux ID → MPC Dashboard OAuth login flow.
|
||||
*
|
||||
* Tests verify:
|
||||
* 1. Unauthenticated users are redirected to /login
|
||||
* 2. Login page renders correctly with Lux branding
|
||||
* 3. OAuth implicit flow redirects to Lux ID
|
||||
* 4. Lux ID login form accepts credentials and redirects back
|
||||
* 5. MPC Dashboard receives the token and shows /dashboard
|
||||
*
|
||||
* Usage:
|
||||
* TEST_PASSWORD='...' pnpm exec playwright test e2e/login-flow.spec.ts
|
||||
*/
|
||||
|
||||
test.describe('Lux ID Login Flow', () => {
|
||||
test('unauthenticated root redirects to /login', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await expect(page).toHaveURL(/\/login/)
|
||||
})
|
||||
|
||||
test('login page shows Lux branding and Continue button', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
await expect(page.getByRole('heading')).toContainText(/Lux/)
|
||||
|
||||
const continueBtn = page.getByRole('button', { name: /Continue with/i })
|
||||
await expect(continueBtn).toBeVisible()
|
||||
await expect(continueBtn).toContainText(/Lux ID/i)
|
||||
})
|
||||
|
||||
test('Continue button redirects to Lux ID authorize endpoint', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
const continueBtn = page.getByRole('button', { name: /Continue with/i })
|
||||
await continueBtn.click()
|
||||
|
||||
await page.waitForURL(/lux\.id\/login\/oauth\/authorize/, { timeout: 15_000 })
|
||||
|
||||
const url = new URL(page.url())
|
||||
expect(url.hostname).toBe('lux.id')
|
||||
expect(url.pathname).toBe('/login/oauth/authorize')
|
||||
expect(url.searchParams.get('response_type')).toBe('token')
|
||||
expect(url.searchParams.get('client_id')).toBe('lux-mpc')
|
||||
expect(url.searchParams.get('scope')).toContain('openid')
|
||||
})
|
||||
|
||||
test('Lux ID login page loads with email and password fields', async ({ page }) => {
|
||||
const authorizeUrl = new URL(`${IAM_URL}/login/oauth/authorize`)
|
||||
authorizeUrl.searchParams.set('response_type', 'token')
|
||||
authorizeUrl.searchParams.set('client_id', 'lux-mpc')
|
||||
authorizeUrl.searchParams.set('redirect_uri', 'https://mpc.lux.network/auth/callback')
|
||||
authorizeUrl.searchParams.set('scope', 'openid profile email')
|
||||
authorizeUrl.searchParams.set('state', 'e2e-test')
|
||||
|
||||
await page.goto(authorizeUrl.toString())
|
||||
|
||||
// The Lux ID login form has "Sign in to Lux" heading
|
||||
await expect(page.getByText('Sign in to Lux')).toBeVisible({ timeout: 15_000 })
|
||||
|
||||
// Email address and Password fields
|
||||
const emailInput = page.getByPlaceholder('[email protected]')
|
||||
const passwordInput = page.getByPlaceholder('Enter your password')
|
||||
|
||||
await expect(emailInput).toBeVisible()
|
||||
await expect(passwordInput).toBeVisible()
|
||||
|
||||
// Sign in button
|
||||
const signInBtn = page.getByRole('button', { name: /Sign in/i })
|
||||
await expect(signInBtn).toBeVisible()
|
||||
})
|
||||
|
||||
test('full login flow with [email protected]', async ({ page }) => {
|
||||
const password = process.env.TEST_PASSWORD
|
||||
test.skip(!password, 'TEST_PASSWORD env var required for login tests')
|
||||
|
||||
await page.goto('/login')
|
||||
|
||||
// Click continue to go to Lux ID
|
||||
await page.getByRole('button', { name: /Continue with/i }).click()
|
||||
|
||||
// Wait for Lux ID login page
|
||||
await page.waitForURL(/lux\.id/, { timeout: 15_000 })
|
||||
await expect(page.getByText('Sign in to Lux')).toBeVisible({ timeout: 15_000 })
|
||||
|
||||
// Fill in credentials
|
||||
await page.getByPlaceholder('[email protected]').fill('[email protected]')
|
||||
await page.getByPlaceholder('Enter your password').fill(password!)
|
||||
|
||||
// Click Sign in
|
||||
await page.getByRole('button', { name: /Sign in/i }).click()
|
||||
|
||||
// Should redirect back to MPC dashboard
|
||||
await page.waitForURL(/mpc\.lux\.network/, { timeout: 30_000 })
|
||||
|
||||
// Wait for auth callback to process and redirect to dashboard
|
||||
if (page.url().includes('/auth/callback')) {
|
||||
await page.waitForURL(/\/dashboard/, { timeout: 15_000 })
|
||||
}
|
||||
|
||||
await expect(page).toHaveURL(/\/dashboard/)
|
||||
})
|
||||
|
||||
test('full login flow with [email protected]', async ({ page }) => {
|
||||
const password = process.env.TEST_PASSWORD
|
||||
test.skip(!password, 'TEST_PASSWORD env var required for login tests')
|
||||
|
||||
await page.goto('/login')
|
||||
await page.getByRole('button', { name: /Continue with/i }).click()
|
||||
|
||||
await page.waitForURL(/lux\.id/, { timeout: 15_000 })
|
||||
await expect(page.getByText('Sign in to Lux')).toBeVisible({ timeout: 15_000 })
|
||||
|
||||
await page.getByPlaceholder('[email protected]').fill('[email protected]')
|
||||
await page.getByPlaceholder('Enter your password').fill(password!)
|
||||
|
||||
await page.getByRole('button', { name: /Sign in/i }).click()
|
||||
|
||||
await page.waitForURL(/mpc\.lux\.network/, { timeout: 30_000 })
|
||||
|
||||
if (page.url().includes('/auth/callback')) {
|
||||
await page.waitForURL(/\/dashboard/, { timeout: 15_000 })
|
||||
}
|
||||
|
||||
await expect(page).toHaveURL(/\/dashboard/)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('IAM OIDC Discovery', () => {
|
||||
test('OIDC discovery endpoint returns valid config', async ({ request }) => {
|
||||
// Use hanzo.id directly — lux.id sometimes returns login HTML on .well-known paths
|
||||
const response = await request.get('https://hanzo.id/.well-known/openid-configuration')
|
||||
expect(response.ok()).toBeTruthy()
|
||||
|
||||
const config = await response.json()
|
||||
expect(config.issuer).toBeTruthy()
|
||||
expect(config.authorization_endpoint).toContain('/login/oauth/authorize')
|
||||
expect(config.token_endpoint).toContain('/oauth/token')
|
||||
expect(config.userinfo_endpoint).toContain('/oauth/userinfo')
|
||||
expect(config.jwks_uri).toContain('/.well-known/jwks')
|
||||
expect(config.response_types_supported).toContain('token')
|
||||
})
|
||||
|
||||
test('JWKS endpoint returns valid keys', async ({ request }) => {
|
||||
// Use hanzo.id for JWKS since lux.id may proxy via login frontend
|
||||
const response = await request.get('https://hanzo.id/.well-known/jwks')
|
||||
expect(response.ok()).toBeTruthy()
|
||||
|
||||
const jwks = await response.json()
|
||||
expect(jwks.keys).toBeDefined()
|
||||
expect(jwks.keys.length).toBeGreaterThan(0)
|
||||
expect(jwks.keys[0].kty).toBeTruthy()
|
||||
})
|
||||
|
||||
test('app-lux-mpc application is accessible', async ({ request }) => {
|
||||
const response = await request.get('https://hanzo.id/api/get-application?id=admin/app-lux-mpc')
|
||||
expect(response.ok()).toBeTruthy()
|
||||
|
||||
const body = await response.json()
|
||||
expect(body.data).toBeTruthy()
|
||||
expect(body.data.clientId).toBe('lux-mpc')
|
||||
expect(body.data.organization).toBe('lux')
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('MPC API Health', () => {
|
||||
test('healthz endpoint returns ok', async ({ request }) => {
|
||||
const baseUrl = process.env.BASE_URL ?? 'https://mpc.lux.network'
|
||||
const response = await request.get(`${baseUrl}/healthz`)
|
||||
expect(response.ok()).toBeTruthy()
|
||||
|
||||
const body = await response.json()
|
||||
expect(body.status).toBe('ok')
|
||||
})
|
||||
})
|
||||
@@ -9,22 +9,23 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.60.0",
|
||||
"geist": "^1.3.0",
|
||||
"next": "^14.2.0",
|
||||
"react": "^18.3.0",
|
||||
"react-dom": "^18.3.0",
|
||||
"@tanstack/react-query": "^5.60.0",
|
||||
"zustand": "^5.0.0",
|
||||
"geist": "^1.3.0"
|
||||
"zustand": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.6.0",
|
||||
"@playwright/test": "^1.58.2",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/react": "^18.3.0",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"postcss": "^8.4.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "^14.2.0"
|
||||
"eslint-config-next": "^14.2.0",
|
||||
"postcss": "^8.4.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { defineConfig, devices } from '@playwright/test'
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './e2e',
|
||||
timeout: 60_000,
|
||||
expect: { timeout: 10_000 },
|
||||
fullyParallel: false,
|
||||
retries: 1,
|
||||
reporter: 'html',
|
||||
use: {
|
||||
baseURL: process.env.BASE_URL ?? 'https://mpc.lux.network',
|
||||
trace: 'on-first-retry',
|
||||
screenshot: 'only-on-failure',
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
],
|
||||
})
|
||||
Generated
+56
-5
@@ -13,10 +13,10 @@ importers:
|
||||
version: 5.90.21([email protected])
|
||||
geist:
|
||||
specifier: ^1.3.0
|
||||
version: 1.7.0([email protected]([email protected]([email protected]))([email protected]))
|
||||
version: 1.7.0([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]))
|
||||
next:
|
||||
specifier: ^14.2.0
|
||||
version: 14.2.35([email protected]([email protected]))([email protected])
|
||||
version: 14.2.35(@playwright/[email protected])([email protected]([email protected]))([email protected])
|
||||
react:
|
||||
specifier: ^18.3.0
|
||||
version: 18.3.1
|
||||
@@ -27,6 +27,9 @@ importers:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.11(@types/[email protected])([email protected])
|
||||
devDependencies:
|
||||
'@playwright/test':
|
||||
specifier: ^1.58.2
|
||||
version: 1.58.2
|
||||
'@types/node':
|
||||
specifier: ^22.0.0
|
||||
version: 22.19.13
|
||||
@@ -144,24 +147,28 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/[email protected]':
|
||||
resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/[email protected]':
|
||||
resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/[email protected]':
|
||||
resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/[email protected]':
|
||||
resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==}
|
||||
@@ -201,6 +208,11 @@ packages:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@playwright/[email protected]':
|
||||
resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
'@rtsao/[email protected]':
|
||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||
|
||||
@@ -342,41 +354,49 @@ packages:
|
||||
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/[email protected]':
|
||||
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
||||
@@ -884,6 +904,11 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@@ -1380,6 +1405,16 @@ packages:
|
||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1939,6 +1974,10 @@ snapshots:
|
||||
'@pkgjs/[email protected]':
|
||||
optional: true
|
||||
|
||||
'@playwright/[email protected]':
|
||||
dependencies:
|
||||
playwright: 1.58.2
|
||||
|
||||
'@rtsao/[email protected]': {}
|
||||
|
||||
'@rushstack/[email protected]': {}
|
||||
@@ -2781,6 +2820,9 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
optional: true
|
||||
|
||||
@@ -2797,9 +2839,9 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected]([email protected]([email protected]))([email protected])):
|
||||
[email protected]([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected])):
|
||||
dependencies:
|
||||
next: 14.2.35([email protected]([email protected]))([email protected])
|
||||
next: 14.2.35(@playwright/[email protected])([email protected]([email protected]))([email protected])
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
@@ -3151,7 +3193,7 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected]([email protected]))([email protected]):
|
||||
[email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]):
|
||||
dependencies:
|
||||
'@next/env': 14.2.35
|
||||
'@swc/helpers': 0.5.5
|
||||
@@ -3172,6 +3214,7 @@ snapshots:
|
||||
'@next/swc-win32-arm64-msvc': 14.2.33
|
||||
'@next/swc-win32-ia32-msvc': 14.2.33
|
||||
'@next/swc-win32-x64-msvc': 14.2.33
|
||||
'@playwright/test': 1.58.2
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
@@ -3285,6 +3328,14 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
playwright-core: 1.58.2
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected]):
|
||||
|
||||
+5
-12
@@ -23,17 +23,15 @@ spec:
|
||||
- name: mpc-api
|
||||
image: ghcr.io/luxfi/mpc-api:latest
|
||||
args:
|
||||
- start
|
||||
- --mode
|
||||
- consensus
|
||||
- --api-db
|
||||
- api
|
||||
- --db
|
||||
- $(DATABASE_URL)
|
||||
- --api-kv
|
||||
- $(KV_URL)
|
||||
- --api-listen
|
||||
- --listen
|
||||
- ":8081"
|
||||
- --jwt-secret
|
||||
- $(JWT_SECRET)
|
||||
- --cluster-url
|
||||
- http://mpc-node-0.mpc-node-headless.lux-mpc.svc:8081
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
name: api
|
||||
@@ -49,11 +47,6 @@ spec:
|
||||
secretKeyRef:
|
||||
name: mpc-secrets
|
||||
key: jwt-secret
|
||||
- name: KV_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mpc-secrets
|
||||
key: KV_URL
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
|
||||
@@ -14,5 +14,4 @@ spec:
|
||||
protocol: TCP
|
||||
name: api
|
||||
selector:
|
||||
app: mpc-node
|
||||
statefulset.kubernetes.io/pod-name: mpc-node-0
|
||||
app: mpc-api
|
||||
|
||||
Reference in New Issue
Block a user