Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ Controller v3.8 is a **greenfield** release aligned with **Edgelet**. There is *
- TCP bridge background provisioning resolves agent router mode via **`RouterManager.findOne`** (fixes **`TypeError`** when **`fakeTransaction`** is used in background jobs).
- TCP bridge / router provisioning **background error logging** uses pino object-first `{ err, msg, … }` so failures are no longer logged as empty errors.
- Router microservice **`siteConfig.platform`** defaults to **`edgelet`** (was **`docker`**) when the agent uses the Edgelet runtime.
- Boolean env vars (`TRUST_PROXY`, `SERVER_DEV_MODE`, `DB_USE_SSL`, `VAULT_ENABLED`, `ENABLE_TELEMETRY`, and other mapped flags) are parsed consistently from Kubernetes string values (`true`/`false`, `1`/`0`) via shared **`config.getBoolean()`** — fixes startup crash when **`TRUST_PROXY=true`** was passed as a string to Express.
- Postgres/MySQL SSL reads canonical **`DB_SSL_CA`** (via config) instead of undocumented **`DB_SSL_CA_B64`**; **`database.*.useSSL`** config key honored (was **`useSsl`** typo).

### Changed

Expand Down
2 changes: 1 addition & 1 deletion src/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ app:
server:
port: 51121 # Server port number
devMode: true
publicUrl: "" # Canonical external URL (CONTROLLER_PUBLIC_URL); https required in prod unless auth.insecureAllowHttp
publicUrl: "https://localhost:51121" # Canonical external URL (CONTROLLER_PUBLIC_URL); https required in prod unless auth.insecureAllowHttp
trustProxy: false # Honor X-Forwarded-* when behind reverse proxy (TRUST_PROXY)
webSocket:
perMessageDeflate: false
Expand Down
15 changes: 2 additions & 13 deletions src/config/embedded-oidc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const { createOidcProviderAdapterFactory } = require('../data/adapters/oidc-prov
const { buildUserAccessClaims } = require('../services/auth-token-service')
const { loadOidcProviderTtls } = require('./auth-oidc-ttl')
const { getPublicUrl, getConsoleUrl } = require('./auth-urls')
const { getTrustProxySetting } = require('./trust-proxy')

const DEFAULT_CONSOLE_CLIENT_ID = 'ecn-viewer'

Expand All @@ -40,11 +41,7 @@ function buildInteractionPolicy () {
}

function isConsoleClientEnabled () {
const envValue = process.env.AUTH_CONSOLE_CLIENT_ENABLED
if (envValue !== undefined && envValue !== null && envValue !== '') {
return envValue === 'true' || envValue === '1'
}
return config.get('auth.consoleClient.enabled', false) === true
return config.getBoolean('auth.consoleClient.enabled', false)
}

function getConsoleClientId () {
Expand Down Expand Up @@ -79,14 +76,6 @@ async function ensureConfidentialClientMetadata (db) {
}
}

function getTrustProxySetting () {
const trustProxy = process.env.TRUST_PROXY || config.get('server.trustProxy', false)
if (trustProxy === true || trustProxy === 'true' || trustProxy === 1 || trustProxy === '1') {
return true
}
return trustProxy || false
}

async function ensureConsoleClientMetadata (db) {
if (!isConsoleClientEnabled()) {
return null
Expand Down
17 changes: 14 additions & 3 deletions src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const nconf = require('nconf')
const path = require('path')
const fs = require('fs')
const yaml = require('js-yaml')
const { parseBoolean } = require('./parse-boolean')

class Config {
constructor () {
Expand Down Expand Up @@ -107,13 +108,23 @@ class Config {
}

parseEnvValue (value) {
// Handle different types
if (value === 'true') return true
if (value === 'false') return false
const bool = parseBoolean(value)
if (bool !== undefined) {
return bool
}
if (!isNaN(value) && value !== '') return Number(value)
return value
}

getBoolean (key, defaultValue = false) {
const value = this.get(key)
if (value === undefined) {
return defaultValue
}
const parsed = parseBoolean(value)
return parsed !== undefined ? parsed : defaultValue
}

formatValue (value) {
if (typeof value === 'boolean') {
return value.toString()
Expand Down
6 changes: 2 additions & 4 deletions src/config/oidc.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ function buildKauthGrant (claims, rawToken) {
}

function getDiscoveryOptions () {
const allowHttp = process.env.AUTH_INSECURE_ALLOW_HTTP !== undefined
? process.env.AUTH_INSECURE_ALLOW_HTTP === 'true'
: config.get('auth.insecureAllowHttp', false) === true
const allowHttp = config.getBoolean('auth.insecureAllowHttp', false)
if (!allowHttp) {
return undefined
}
Expand Down Expand Up @@ -199,7 +197,7 @@ function initOidc () {

// v3.9: read TLS client-auth policy when HTTPS + requestCert enabled (server.js listener)
if (!isAuthConfigured()) {
const isProduction = !config.get('server.devMode', true)
const isProduction = !config.getBoolean('server.devMode', true)
if (isProduction) {
const error = new Error('Auth configuration required in production mode')
logger.error('Failed to initialize OIDC:', error)
Expand Down
18 changes: 18 additions & 0 deletions src/config/parse-boolean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

function parseBoolean (value, defaultValue) {
if (value === true || value === 'true' || value === 1 || value === '1') {
return true
}
if (value === false || value === 'false' || value === 0 || value === '0') {
return false
}
if (value === undefined || value === null || value === '') {
return arguments.length >= 2 ? defaultValue : undefined
}
return arguments.length >= 2 ? defaultValue : undefined
}

module.exports = {
parseBoolean
}
10 changes: 7 additions & 3 deletions src/config/telemetry.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { NodeSDK } = require('@opentelemetry/sdk-node')
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http')
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http')
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express')
const config = require('./index')
const logger = require('../logger')

const sdk = new NodeSDK({
Expand All @@ -16,10 +17,13 @@ const sdk = new NodeSDK({
]
})

function isTelemetryEnabled () {
return config.getBoolean('otel.enabled', false)
}

// Start the SDK
async function startTelemetry () {
const isTelemetryEnabled = process.env.ENABLE_TELEMETRY === 'true'
if (!isTelemetryEnabled) {
if (!isTelemetryEnabled()) {
logger.info('Telemetry is disabled via ENABLE_TELEMETRY environment variable')
return
}
Expand All @@ -35,7 +39,7 @@ async function startTelemetry () {

// Handle process termination
process.on('SIGTERM', () => {
if (process.env.ENABLE_TELEMETRY !== 'true') return
if (!isTelemetryEnabled()) return

try {
sdk.shutdown()
Expand Down
17 changes: 17 additions & 0 deletions src/config/trust-proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict'

const config = require('./index')
const { parseBoolean } = require('./parse-boolean')

function getTrustProxySetting () {
const trustProxy = config.get('server.trustProxy', false)
const parsed = parseBoolean(trustProxy)
if (parsed !== undefined) {
return parsed
}
return trustProxy || false
}

module.exports = {
getTrustProxySetting
}
7 changes: 3 additions & 4 deletions src/data/migrations/mysql/db_migration_mysql_v3.8.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ CREATE TABLE IF NOT EXISTS Microservices (
name VARCHAR(255) DEFAULT 'New Microservice',
config_last_updated BIGINT,
rebuild BOOLEAN DEFAULT false,
root_host_access BOOLEAN DEFAULT false,
log_size BIGINT DEFAULT 0,
`delete` BOOLEAN DEFAULT false,
delete_with_cleanup BOOLEAN DEFAULT false,
Expand All @@ -228,6 +227,9 @@ CREATE TABLE IF NOT EXISTS Microservices (
registry_id INT DEFAULT 1,
iofog_uuid VARCHAR(36),
application_id INT,
run_as_user TEXT,
platform TEXT,
runtime TEXT,
annotations TEXT,
pid_mode VARCHAR(36),
ipc_mode VARCHAR(36),
Expand Down Expand Up @@ -280,7 +282,6 @@ CREATE TABLE IF NOT EXISTS MicroserviceExtraHost (
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
template_type TEXT,
name TEXT,
public_port INT,
template TEXT,
`value` TEXT,
microservice_uuid VARCHAR(36),
Expand All @@ -300,8 +301,6 @@ CREATE TABLE IF NOT EXISTS MicroservicePorts (
port_internal INT,
port_external INT,
is_udp BOOLEAN,
is_public BOOLEAN,
is_proxy BOOLEAN,
created_at DATETIME,
updated_at DATETIME,
microservice_uuid VARCHAR(36),
Expand Down
7 changes: 3 additions & 4 deletions src/data/migrations/postgres/db_migration_pg_v3.8.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ CREATE TABLE IF NOT EXISTS "Microservices" (
name VARCHAR(255) DEFAULT 'New Microservice',
config_last_updated BIGINT,
rebuild BOOLEAN DEFAULT false,
root_host_access BOOLEAN DEFAULT false,
log_size BIGINT DEFAULT 0,
delete BOOLEAN DEFAULT false,
delete_with_cleanup BOOLEAN DEFAULT false,
Expand All @@ -226,6 +225,9 @@ CREATE TABLE IF NOT EXISTS "Microservices" (
registry_id INT DEFAULT 1,
iofog_uuid VARCHAR(36),
application_id INT,
run_as_user TEXT,
platform TEXT,
runtime TEXT,
annotations TEXT,
pid_mode VARCHAR(36),
ipc_mode VARCHAR(36),
Expand Down Expand Up @@ -278,7 +280,6 @@ CREATE TABLE IF NOT EXISTS "MicroserviceExtraHost" (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
template_type TEXT,
name TEXT,
public_port INT,
template TEXT,
value TEXT,
microservice_uuid VARCHAR(36),
Expand All @@ -298,8 +299,6 @@ CREATE TABLE IF NOT EXISTS "MicroservicePorts" (
port_internal INT,
port_external INT,
is_udp BOOLEAN,
is_public BOOLEAN,
is_proxy BOOLEAN,
created_at TIMESTAMP(0),
updated_at TIMESTAMP(0),
microservice_uuid VARCHAR(36),
Expand Down
1 change: 0 additions & 1 deletion src/data/migrations/sqlite/db_migration_sqlite_v3.8.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ CREATE TABLE IF NOT EXISTS Microservices (
name VARCHAR(255) DEFAULT 'New Microservice',
config_last_updated BIGINT,
rebuild BOOLEAN DEFAULT false,
root_host_access BOOLEAN DEFAULT false,
log_size BIGINT DEFAULT 0,
`delete` BOOLEAN DEFAULT false,
delete_with_cleanup BOOLEAN DEFAULT false,
Expand Down
6 changes: 3 additions & 3 deletions src/data/providers/mysql.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ class MySqlDatabaseProvider extends DatabaseProvider {
}

// Configure SSL if enabled
const useSSL = process.env.DB_USE_SSL === 'true' || mysqlConfig.useSsl === true
const useSSL = config.getBoolean('database.mysql.useSSL', false)
if (useSSL) {
const caBase64 = process.env.DB_SSL_CA_B64
const caBase64 = config.get('database.mysql.sslCA', '')
const sslOptions = caBase64
? {
ca: Buffer.from(caBase64, 'base64').toString('utf-8'),
Expand All @@ -51,7 +51,7 @@ class MySqlDatabaseProvider extends DatabaseProvider {

// Add SSL configuration to Sequelize if enabled
if (useSSL) {
const caBase64 = process.env.DB_SSL_CA_B64
const caBase64 = config.get('database.mysql.sslCA', '')
sequelizeConfig.dialectOptions.ssl = caBase64
? {
ca: Buffer.from(caBase64, 'base64').toString('utf-8'),
Expand Down
6 changes: 3 additions & 3 deletions src/data/providers/postgres.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ class PostgresDatabaseProvider extends DatabaseProvider {
}

// Configure SSL if enabled
const useSSL = process.env.DB_USE_SSL === 'true' || postgresConfig.useSsl === true
const useSSL = config.getBoolean('database.postgres.useSSL', false)
if (useSSL) {
const caBase64 = process.env.DB_SSL_CA_B64
const caBase64 = config.get('database.postgres.sslCA', '')
const sslOptions = caBase64
? {
ca: Buffer.from(caBase64, 'base64').toString('utf-8'),
Expand All @@ -50,7 +50,7 @@ class PostgresDatabaseProvider extends DatabaseProvider {
}
// Add SSL configuration to Sequelize if enabled
if (useSSL) {
const caBase64 = process.env.DB_SSL_CA_B64
const caBase64 = config.get('database.postgres.sslCA', '')
sequelizeConfig.dialectOptions.ssl = caBase64
? {
ca: Buffer.from(caBase64, 'base64').toString('utf-8'),
Expand Down
2 changes: 1 addition & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const fetch = require('node-fetch-npm')

const isHTTPS = () => {
const sslKey = config.get('server.ssl.path.key', '')
const devMode = config.get('server.devMode', false)
const devMode = config.getBoolean('server.devMode', false)
const sslCert = config.get('server.ssl.path.cert', '')
return !devMode && sslKey && sslCert
}
Expand Down
2 changes: 1 addition & 1 deletion src/middlewares/auth-rate-limit-middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const rateLimits = new Map()

function getRateLimitConfig () {
return {
enabled: config.get('auth.rateLimit.enabled', true),
enabled: config.getBoolean('auth.rateLimit.enabled', true),
maxRequests: config.get('auth.rateLimit.maxRequestsPerWindow', 60),
windowMs: config.get('auth.rateLimit.windowMs', 60000)
}
Expand Down
2 changes: 1 addition & 1 deletion src/middlewares/event-audit-middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function eventAuditMiddleware (req, res, next) {

// Check if auditing is enabled (reads from YAML or env var)
// Use config.get() which properly parses boolean strings from env vars
const auditEnabled = config.get('settings.eventAuditEnabled', true)
const auditEnabled = config.getBoolean('settings.eventAuditEnabled', true)
if (!auditEnabled) {
return next()
}
Expand Down
2 changes: 1 addition & 1 deletion src/routes/capabilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = [

// Add rbacMiddleware.protect middleware to protect the route
await rbacMiddleware.protect()(req, res, async () => {
if (config.get('nats.enabled')) {
if (config.getBoolean('nats.enabled', false)) {
res.sendStatus(204)
return
}
Expand Down
11 changes: 6 additions & 5 deletions src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ initialize().then(() => {
resolveSessionSecret
} = require('./config/auth-session-store.js')
const { getPublicUrl, getConsoleUrl } = require('./config/auth-urls.js')
const { getTrustProxySetting } = require('./config/trust-proxy.js')

function resolveConsolePath () {
if (process.env.EDGEOPS_CONSOLE_PATH) {
Expand All @@ -49,20 +50,20 @@ initialize().then(() => {
const consoleApp = express()
const app = express()

const trustProxy = process.env.TRUST_PROXY || config.get('server.trustProxy', false)
const trustProxy = getTrustProxySetting()
if (trustProxy) {
app.set('trust proxy', trustProxy === true ? 1 : trustProxy)
consoleApp.set('trust proxy', trustProxy === true ? 1 : trustProxy)
}

function validateProductionPublicUrl () {
const devMode = process.env.DEV_MODE || config.get('server.devMode', true)
const devMode = config.getBoolean('server.devMode', true)
if (devMode) {
return
}

const publicUrl = process.env.CONTROLLER_PUBLIC_URL || config.get('server.publicUrl')
const insecureAllowHttp = config.get('auth.insecureAllowHttp', false)
const insecureAllowHttp = config.getBoolean('auth.insecureAllowHttp', false)

if (!publicUrl) {
throw new Error('CONTROLLER_PUBLIC_URL is required in production mode')
Expand All @@ -82,8 +83,8 @@ initialize().then(() => {

validateProductionPublicUrl()

const devMode = process.env.DEV_MODE || config.get('server.devMode', true)
const insecureAllowHttp = config.get('auth.insecureAllowHttp', false)
const devMode = config.getBoolean('server.devMode', true)
const insecureAllowHttp = config.getBoolean('auth.insecureAllowHttp', false)

const consoleURLForCors = getConsoleUrl()
app.use(cors({
Expand Down
2 changes: 1 addition & 1 deletion src/services/agent-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ async function _checkMicroservicesFogType (fog, archId, transaction) {
}

const getControllerCA = async function (fog, transaction) {
const devMode = process.env.DEV_MODE || config.get('server.devMode')
const devMode = config.getBoolean('server.devMode', false)
const sslCert = process.env.SSL_CERT || config.get('server.ssl.path.cert')
const intermedKey = process.env.INTERMEDIATE_CERT || config.get('server.ssl.path.intermediateCert')
const sslCertBase64 = config.get('server.ssl.base64.cert')
Expand Down
2 changes: 1 addition & 1 deletion src/services/auth-bootstrap-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function getBootstrapConfig () {
return {
username: (process.env.OIDC_BOOTSTRAP_ADMIN_USERNAME || config.get('auth.bootstrap.username') || '').trim(),
passwordRef: process.env.OIDC_BOOTSTRAP_ADMIN_PASSWORD || config.get('auth.bootstrap.password') || '',
allowBootstrapLog: config.get('auth.insecureAllowBootstrapLog', false) === true
allowBootstrapLog: config.getBoolean('auth.insecureAllowBootstrapLog', false)
}
}

Expand Down
Loading