fix: runtime API URL resolution and pin Docker base image

- Add apiUrl/wsUrl to brand config for runtime resolution
- Auth and OAuth callback now use brand's apiUrl instead of baked env var
- Pin node:22-alpine to specific digest for supply chain security
This commit is contained in:
2026-02-09 20:48:43 -08:00
parent e708a40f4b
commit df10ab5f5e
4 changed files with 21 additions and 2 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
# Bootnode Web Dashboard
# Next.js 15 with React 19
FROM node:22-alpine AS base
# Pinned digest for supply chain security - update periodically
FROM node:22-alpine@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34 AS base
# Install dependencies only when needed
FROM base AS deps
+5 -1
View File
@@ -4,6 +4,7 @@
import { Suspense, useEffect, useState } from "react"
import { useRouter, useSearchParams } from "next/navigation"
import { useAuth } from "@/lib/auth"
import { getBrand } from "@/lib/brand"
function CallbackContent() {
const [status, setStatus] = useState<"loading" | "success" | "error">("loading")
@@ -40,7 +41,10 @@ function CallbackContent() {
}
// Exchange code for token via our API
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"
const brand = getBrand()
const apiUrl = (typeof window !== "undefined" && window.location.hostname !== "localhost")
? brand.apiUrl
: (process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000")
const response = await fetch(`${apiUrl}/v1/auth/oauth/callback`, {
method: "POST",
headers: {
+4
View File
@@ -7,6 +7,7 @@
import { createContext, useContext, useEffect, useState, useCallback } from "react"
import { useRouter } from "next/navigation"
import { toast } from "sonner"
import { getBrand } from "@/lib/brand"
interface BootnodeUser {
id: string
@@ -59,6 +60,9 @@ export function AuthProvider({ children }: AuthProviderProps) {
const isProduction = isProductionMode()
const getApiUrl = useCallback(() => {
if (typeof window !== "undefined" && window.location.hostname !== "localhost") {
return getBrand().apiUrl
}
return process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"
}, [])
+10
View File
@@ -10,6 +10,8 @@ export type BrandConfig = {
logoWhite: string
favicon: string
domain: string
apiUrl: string
wsUrl: string
statusUrl: string
defaultTheme: "light" | "dark"
colors: {
@@ -46,6 +48,8 @@ const brands: Record<string, BrandConfig> = {
logoWhite: "/logo/bootnode-logo-white.svg",
favicon: "/logo/bootnode-icon.svg",
domain: "bootno.de",
apiUrl: "https://api.bootno.de",
wsUrl: "wss://ws.bootno.de",
statusUrl: "https://status.bootno.de",
defaultTheme: "light",
colors: {
@@ -77,6 +81,8 @@ const brands: Record<string, BrandConfig> = {
logoWhite: "/logo/hanzo-logo-white.svg",
favicon: "/logo/hanzo-icon.svg",
domain: "web3.hanzo.ai",
apiUrl: "https://api.web3.hanzo.ai",
wsUrl: "wss://ws.web3.hanzo.ai",
statusUrl: "https://status.hanzo.ai",
defaultTheme: "dark",
colors: {
@@ -112,6 +118,8 @@ const brands: Record<string, BrandConfig> = {
logoWhite: "/logo/lux-wordmark-white.svg",
favicon: "/logo/lux-icon.svg",
domain: "cloud.lux.network",
apiUrl: "https://api.cloud.lux.network",
wsUrl: "wss://ws.cloud.lux.network",
statusUrl: "https://status.lux.network",
defaultTheme: "dark",
colors: {
@@ -147,6 +155,8 @@ const brands: Record<string, BrandConfig> = {
logoWhite: "/logo/zoo-logo-white.svg",
favicon: "/logo/zoo-icon.svg",
domain: "web3.zoo.ngo",
apiUrl: "https://api.web3.zoo.ngo",
wsUrl: "wss://ws.web3.zoo.ngo",
statusUrl: "https://status.zoo.ngo",
defaultTheme: "dark",
colors: {