@aifabrix/builder 2.9.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/login.js +7 -1
- package/lib/schema/env-config.yaml +9 -1
- package/lib/templates.js +35 -4
- package/lib/utils/api-error-handler.js +12 -12
- package/lib/utils/device-code.js +65 -2
- package/lib/utils/env-template.js +5 -4
- package/package.json +1 -1
- package/templates/applications/keycloak/env.template +8 -2
- package/templates/applications/keycloak/variables.yaml +3 -3
- package/templates/applications/miso-controller/env.template +23 -10
- package/templates/applications/miso-controller/rbac.yaml +263 -213
- package/templates/applications/miso-controller/variables.yaml +3 -3
package/lib/commands/login.js
CHANGED
|
@@ -359,7 +359,13 @@ async function handleDeviceCodeLogin(controllerUrl, environment, offline, scope)
|
|
|
359
359
|
);
|
|
360
360
|
|
|
361
361
|
} catch (deviceError) {
|
|
362
|
-
|
|
362
|
+
// Display formatted error if available (includes detailed validation info)
|
|
363
|
+
if (deviceError.formattedError) {
|
|
364
|
+
logger.error(chalk.red('\n❌ Device code flow failed:'));
|
|
365
|
+
logger.log(deviceError.formattedError);
|
|
366
|
+
} else {
|
|
367
|
+
logger.error(chalk.red(`\n❌ Device code flow failed: ${deviceError.message}`));
|
|
368
|
+
}
|
|
363
369
|
process.exit(1);
|
|
364
370
|
}
|
|
365
371
|
}
|
|
@@ -11,6 +11,10 @@ environments:
|
|
|
11
11
|
MISO_PORT: 3000
|
|
12
12
|
KEYCLOAK_HOST: keycloak
|
|
13
13
|
KEYCLOAK_PORT: 8082
|
|
14
|
+
NODE_ENV: production
|
|
15
|
+
PYTHONUNBUFFERED: 1
|
|
16
|
+
PYTHONDONTWRITEBYTECODE: 1
|
|
17
|
+
PYTHONIOENCODING: utf-8
|
|
14
18
|
|
|
15
19
|
local:
|
|
16
20
|
DB_HOST: localhost
|
|
@@ -20,4 +24,8 @@ environments:
|
|
|
20
24
|
MISO_HOST: localhost
|
|
21
25
|
MISO_PORT: 3010
|
|
22
26
|
KEYCLOAK_HOST: localhost
|
|
23
|
-
KEYCLOAK_PORT: 8082
|
|
27
|
+
KEYCLOAK_PORT: 8082
|
|
28
|
+
NODE_ENV: development
|
|
29
|
+
PYTHONUNBUFFERED: 1
|
|
30
|
+
PYTHONDONTWRITEBYTECODE: 1
|
|
31
|
+
PYTHONIOENCODING: utf-8
|
package/lib/templates.js
CHANGED
|
@@ -134,13 +134,31 @@ function generateVariablesYaml(appName, config) {
|
|
|
134
134
|
*/
|
|
135
135
|
function buildCoreEnv(config) {
|
|
136
136
|
return {
|
|
137
|
-
'NODE_ENV': '
|
|
137
|
+
'NODE_ENV': '${NODE_ENV}',
|
|
138
138
|
'PORT': config.port || 3000,
|
|
139
139
|
'APP_NAME': config.appName || 'myapp',
|
|
140
140
|
'LOG_LEVEL': 'info'
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Builds Python-specific environment variables
|
|
146
|
+
* @param {Object} config - Configuration options
|
|
147
|
+
* @returns {Object} Python environment variables
|
|
148
|
+
*/
|
|
149
|
+
function buildPythonEnv(config) {
|
|
150
|
+
const language = config.language || 'typescript';
|
|
151
|
+
if (language !== 'python') {
|
|
152
|
+
return {};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
'PYTHONUNBUFFERED': '${PYTHONUNBUFFERED}',
|
|
157
|
+
'PYTHONDONTWRITEBYTECODE': '${PYTHONDONTWRITEBYTECODE}',
|
|
158
|
+
'PYTHONIOENCODING': '${PYTHONIOENCODING}'
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
144
162
|
function buildDatabaseEnv(config) {
|
|
145
163
|
if (!config.database) {
|
|
146
164
|
return {};
|
|
@@ -207,8 +225,9 @@ function buildMonitoringEnv(config) {
|
|
|
207
225
|
return {
|
|
208
226
|
'MISO_CONTROLLER_URL': config.controllerUrl || 'https://controller.aifabrix.ai',
|
|
209
227
|
'MISO_ENVIRONMENT': 'dev',
|
|
210
|
-
'MISO_CLIENTID': 'kv://miso-
|
|
211
|
-
'MISO_CLIENTSECRET': 'kv://miso-
|
|
228
|
+
'MISO_CLIENTID': 'kv://miso-controller-client-idKeyVault',
|
|
229
|
+
'MISO_CLIENTSECRET': 'kv://miso-controller-client-secretKeyVault',
|
|
230
|
+
'MISO_WEB_SERVER_URL': 'kv://miso-controller-web-server-url'
|
|
212
231
|
};
|
|
213
232
|
}
|
|
214
233
|
|
|
@@ -220,10 +239,17 @@ function buildMonitoringEnv(config) {
|
|
|
220
239
|
function addCoreVariables(lines, envVars) {
|
|
221
240
|
Object.entries(envVars).forEach(([key, value]) => {
|
|
222
241
|
if (key.startsWith('NODE_ENV') || key.startsWith('PORT') ||
|
|
223
|
-
key.startsWith('APP_NAME') || key.startsWith('LOG_LEVEL')
|
|
242
|
+
key.startsWith('APP_NAME') || key.startsWith('LOG_LEVEL') ||
|
|
243
|
+
key.startsWith('PYTHON')) {
|
|
224
244
|
lines.push(`${key}=${value}`);
|
|
225
245
|
}
|
|
226
246
|
});
|
|
247
|
+
|
|
248
|
+
// Add ALLOWED_ORIGINS and WEB_SERVER_URL after PORT variable
|
|
249
|
+
// ALLOWED_ORIGINS: My application public address
|
|
250
|
+
lines.push('ALLOWED_ORIGINS=http://localhost:*,');
|
|
251
|
+
// WEB_SERVER_URL: Miso public address (uses ${PORT} template variable)
|
|
252
|
+
lines.push('WEB_SERVER_URL=http://localhost:${PORT},');
|
|
227
253
|
}
|
|
228
254
|
|
|
229
255
|
function addMonitoringSection(lines, envVars) {
|
|
@@ -232,6 +258,10 @@ function addMonitoringSection(lines, envVars) {
|
|
|
232
258
|
lines.push(`MISO_ENVIRONMENT=${envVars['MISO_ENVIRONMENT']}`);
|
|
233
259
|
lines.push(`MISO_CLIENTID=${envVars['MISO_CLIENTID']}`);
|
|
234
260
|
lines.push(`MISO_CLIENTSECRET=${envVars['MISO_CLIENTSECRET']}`);
|
|
261
|
+
// MISO_WEB_SERVER_URL: Miso public address
|
|
262
|
+
if (envVars['MISO_WEB_SERVER_URL']) {
|
|
263
|
+
lines.push(`MISO_WEB_SERVER_URL=${envVars['MISO_WEB_SERVER_URL']}`);
|
|
264
|
+
}
|
|
235
265
|
}
|
|
236
266
|
|
|
237
267
|
function addDatabaseSection(lines, envVars) {
|
|
@@ -316,6 +346,7 @@ function addAuthenticationSection(lines, envVars) {
|
|
|
316
346
|
function generateEnvTemplate(config, existingEnv = {}) {
|
|
317
347
|
const envVars = {
|
|
318
348
|
...buildCoreEnv(config),
|
|
349
|
+
...buildPythonEnv(config),
|
|
319
350
|
...buildDatabaseEnv(config),
|
|
320
351
|
...buildRedisEnv(config),
|
|
321
352
|
...buildStorageEnv(config),
|
|
@@ -73,13 +73,11 @@ function formatPermissionError(errorData) {
|
|
|
73
73
|
|
|
74
74
|
const requiredPerms = extractRequiredPermissions(errorData);
|
|
75
75
|
addPermissionList(lines, requiredPerms, 'Required permissions');
|
|
76
|
-
|
|
77
76
|
const requestUrl = errorData.instance || errorData.url;
|
|
78
77
|
const method = errorData.method || 'POST';
|
|
79
78
|
if (requestUrl) {
|
|
80
79
|
lines.push(chalk.gray(`Request: ${method} ${requestUrl}`));
|
|
81
80
|
}
|
|
82
|
-
|
|
83
81
|
if (errorData.correlationId) {
|
|
84
82
|
lines.push(chalk.gray(`Correlation ID: ${errorData.correlationId}`));
|
|
85
83
|
}
|
|
@@ -97,18 +95,27 @@ function formatValidationError(errorData) {
|
|
|
97
95
|
lines.push(chalk.red('❌ Validation Error\n'));
|
|
98
96
|
|
|
99
97
|
// Handle RFC 7807 Problem Details format
|
|
100
|
-
// Priority: detail > title > message
|
|
98
|
+
// Priority: detail > title > errorDescription > message > error
|
|
101
99
|
if (errorData.detail) {
|
|
102
100
|
lines.push(chalk.yellow(errorData.detail));
|
|
103
101
|
lines.push('');
|
|
104
102
|
} else if (errorData.title) {
|
|
105
103
|
lines.push(chalk.yellow(errorData.title));
|
|
106
104
|
lines.push('');
|
|
105
|
+
} else if (errorData.errorDescription) {
|
|
106
|
+
// Handle Keycloak-style error format
|
|
107
|
+
lines.push(chalk.yellow(errorData.errorDescription));
|
|
108
|
+
if (errorData.error) {
|
|
109
|
+
lines.push(chalk.gray(`Error code: ${errorData.error}`));
|
|
110
|
+
}
|
|
111
|
+
lines.push('');
|
|
107
112
|
} else if (errorData.message) {
|
|
108
113
|
lines.push(chalk.yellow(errorData.message));
|
|
109
114
|
lines.push('');
|
|
115
|
+
} else if (errorData.error) {
|
|
116
|
+
lines.push(chalk.yellow(errorData.error));
|
|
117
|
+
lines.push('');
|
|
110
118
|
}
|
|
111
|
-
|
|
112
119
|
// Handle errors array - this is the most important part
|
|
113
120
|
if (errorData.errors && Array.isArray(errorData.errors) && errorData.errors.length > 0) {
|
|
114
121
|
lines.push(chalk.yellow('Validation errors:'));
|
|
@@ -124,17 +131,14 @@ function formatValidationError(errorData) {
|
|
|
124
131
|
});
|
|
125
132
|
lines.push('');
|
|
126
133
|
}
|
|
127
|
-
|
|
128
134
|
// Show instance (endpoint) if available (RFC 7807)
|
|
129
135
|
if (errorData.instance) {
|
|
130
136
|
lines.push(chalk.gray(`Endpoint: ${errorData.instance}`));
|
|
131
137
|
}
|
|
132
|
-
|
|
133
138
|
// Show correlation ID if available
|
|
134
139
|
if (errorData.correlationId) {
|
|
135
140
|
lines.push(chalk.gray(`Correlation ID: ${errorData.correlationId}`));
|
|
136
141
|
}
|
|
137
|
-
|
|
138
142
|
return lines.join('\n');
|
|
139
143
|
}
|
|
140
144
|
/**
|
|
@@ -145,7 +149,6 @@ function formatValidationError(errorData) {
|
|
|
145
149
|
function formatAuthenticationError(errorData) {
|
|
146
150
|
const lines = [];
|
|
147
151
|
lines.push(chalk.red('❌ Authentication Failed\n'));
|
|
148
|
-
|
|
149
152
|
if (errorData.message) {
|
|
150
153
|
lines.push(chalk.yellow(errorData.message));
|
|
151
154
|
} else {
|
|
@@ -153,11 +156,9 @@ function formatAuthenticationError(errorData) {
|
|
|
153
156
|
}
|
|
154
157
|
lines.push('');
|
|
155
158
|
lines.push(chalk.gray('Run: aifabrix login'));
|
|
156
|
-
|
|
157
159
|
if (errorData.correlationId) {
|
|
158
160
|
lines.push(chalk.gray(`Correlation ID: ${errorData.correlationId}`));
|
|
159
161
|
}
|
|
160
|
-
|
|
161
162
|
return lines.join('\n');
|
|
162
163
|
}
|
|
163
164
|
/**
|
|
@@ -379,7 +380,7 @@ function createErrorResult(type, message, formatted, data) {
|
|
|
379
380
|
* @returns {string} Error message
|
|
380
381
|
*/
|
|
381
382
|
function getErrorMessage(errorData, defaultMessage) {
|
|
382
|
-
return errorData.detail || errorData.title || errorData.message || defaultMessage;
|
|
383
|
+
return errorData.detail || errorData.title || errorData.errorDescription || errorData.message || errorData.error || defaultMessage;
|
|
383
384
|
}
|
|
384
385
|
|
|
385
386
|
/**
|
|
@@ -486,7 +487,6 @@ function formatApiError(apiResponse) {
|
|
|
486
487
|
const parsed = parseErrorResponse(errorResponse, statusCode, isNetworkError);
|
|
487
488
|
return parsed.formatted;
|
|
488
489
|
}
|
|
489
|
-
|
|
490
490
|
module.exports = {
|
|
491
491
|
parseErrorResponse,
|
|
492
492
|
formatApiError,
|
package/lib/utils/device-code.js
CHANGED
|
@@ -140,15 +140,61 @@ function parseTokenResponse(response) {
|
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Creates a validation error with detailed information
|
|
145
|
+
* @function createValidationError
|
|
146
|
+
* @param {Object} response - Full API response object
|
|
147
|
+
* @returns {Error} Validation error with formattedError and errorData attached
|
|
148
|
+
*/
|
|
149
|
+
function createValidationError(response) {
|
|
150
|
+
const validationError = new Error('Token polling failed: Validation error');
|
|
151
|
+
|
|
152
|
+
// Attach formatted error if available (includes detailed validation info with ANSI colors)
|
|
153
|
+
if (response && response.formattedError) {
|
|
154
|
+
validationError.formattedError = response.formattedError;
|
|
155
|
+
validationError.message = `Token polling failed:\n${response.formattedError}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Attach error data for programmatic access
|
|
159
|
+
if (response && response.errorData) {
|
|
160
|
+
validationError.errorData = response.errorData;
|
|
161
|
+
validationError.errorType = response.errorType || 'validation';
|
|
162
|
+
|
|
163
|
+
// Build detailed message if formattedError not available
|
|
164
|
+
if (!validationError.formattedError) {
|
|
165
|
+
const errorData = response.errorData;
|
|
166
|
+
const detail = errorData.detail || errorData.title || errorData.message || 'Validation error';
|
|
167
|
+
let errorMsg = `Token polling failed: ${detail}`;
|
|
168
|
+
// Add validation errors if available
|
|
169
|
+
if (errorData.errors && Array.isArray(errorData.errors) && errorData.errors.length > 0) {
|
|
170
|
+
errorMsg += '\n\nValidation errors:';
|
|
171
|
+
errorData.errors.forEach(err => {
|
|
172
|
+
const field = err.field || err.path || 'validation';
|
|
173
|
+
const message = err.message || 'Invalid value';
|
|
174
|
+
if (field === 'validation' || field === 'unknown') {
|
|
175
|
+
errorMsg += `\n • ${message}`;
|
|
176
|
+
} else {
|
|
177
|
+
errorMsg += `\n • ${field}: ${message}`;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
validationError.message = errorMsg;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return validationError;
|
|
186
|
+
}
|
|
187
|
+
|
|
143
188
|
/**
|
|
144
189
|
* Handles polling errors
|
|
145
190
|
* @function handlePollingErrors
|
|
146
191
|
* @param {string} error - Error code
|
|
147
192
|
* @param {number} status - HTTP status code
|
|
193
|
+
* @param {Object} response - Full API response object (for accessing formattedError and errorData)
|
|
148
194
|
* @throws {Error} For fatal errors
|
|
149
195
|
* @returns {boolean} True if should continue polling
|
|
150
196
|
*/
|
|
151
|
-
function handlePollingErrors(error, status) {
|
|
197
|
+
function handlePollingErrors(error, status, response) {
|
|
152
198
|
if (error === 'authorization_pending' || status === 202) {
|
|
153
199
|
return true;
|
|
154
200
|
}
|
|
@@ -166,6 +212,11 @@ function handlePollingErrors(error, status) {
|
|
|
166
212
|
return true;
|
|
167
213
|
}
|
|
168
214
|
|
|
215
|
+
// Handle validation errors with detailed message
|
|
216
|
+
if (error === 'validation_error' || status === 400) {
|
|
217
|
+
throw createValidationError(response);
|
|
218
|
+
}
|
|
219
|
+
|
|
169
220
|
throw new Error(`Token polling failed: ${error}`);
|
|
170
221
|
}
|
|
171
222
|
|
|
@@ -187,6 +238,18 @@ async function waitForNextPoll(interval, slowDown) {
|
|
|
187
238
|
* @returns {string} Error code or 'Unknown error'
|
|
188
239
|
*/
|
|
189
240
|
function extractPollingError(response) {
|
|
241
|
+
// Check for structured error data first (from api-error-handler)
|
|
242
|
+
if (response.errorData) {
|
|
243
|
+
const errorData = response.errorData;
|
|
244
|
+
// For validation errors, return the error type so we can handle it specially
|
|
245
|
+
if (response.errorType === 'validation') {
|
|
246
|
+
return 'validation_error';
|
|
247
|
+
}
|
|
248
|
+
// Return the error message from structured error
|
|
249
|
+
return errorData.detail || errorData.title || errorData.message || errorData.error || response.error || 'Unknown error';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Fallback to original extraction logic
|
|
190
253
|
const apiResponse = response.data || {};
|
|
191
254
|
const errorData = typeof apiResponse === 'object' ? apiResponse : {};
|
|
192
255
|
return errorData.error || response.error || 'Unknown error';
|
|
@@ -229,7 +292,7 @@ async function processPollingResponse(response, interval) {
|
|
|
229
292
|
}
|
|
230
293
|
|
|
231
294
|
const error = extractPollingError(response);
|
|
232
|
-
const shouldContinue = handlePollingErrors(error, response.status);
|
|
295
|
+
const shouldContinue = handlePollingErrors(error, response.status, response);
|
|
233
296
|
|
|
234
297
|
if (shouldContinue) {
|
|
235
298
|
const slowDown = error === 'slow_down';
|
|
@@ -20,10 +20,11 @@ const logger = require('../utils/logger');
|
|
|
20
20
|
* @param {string} appKey - Application key
|
|
21
21
|
* @param {string} clientIdKey - Secret key for client ID (e.g., 'myapp-client-idKeyVault')
|
|
22
22
|
* @param {string} clientSecretKey - Secret key for client secret (e.g., 'myapp-client-secretKeyVault')
|
|
23
|
-
* @param {string}
|
|
23
|
+
* @param {string} _controllerUrl - Controller URL (e.g., 'http://localhost:3010' or 'https://controller.aifabrix.ai')
|
|
24
|
+
* Note: This parameter is accepted for compatibility but the template format http://${MISO_HOST}:${MISO_PORT} is used instead
|
|
24
25
|
* @returns {Promise<void>} Resolves when template is updated
|
|
25
26
|
*/
|
|
26
|
-
async function updateEnvTemplate(appKey, clientIdKey, clientSecretKey,
|
|
27
|
+
async function updateEnvTemplate(appKey, clientIdKey, clientSecretKey, _controllerUrl) {
|
|
27
28
|
const envTemplatePath = path.join(process.cwd(), 'builder', appKey, 'env.template');
|
|
28
29
|
|
|
29
30
|
if (!fsSync.existsSync(envTemplatePath)) {
|
|
@@ -49,7 +50,7 @@ async function updateEnvTemplate(appKey, clientIdKey, clientSecretKey, controlle
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
if (hasControllerUrl) {
|
|
52
|
-
content = content.replace(/^MISO_CONTROLLER_URL\s*=.*$/m,
|
|
53
|
+
content = content.replace(/^MISO_CONTROLLER_URL\s*=.*$/m, 'MISO_CONTROLLER_URL=http://${MISO_HOST}:${MISO_PORT}');
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
// Add missing entries
|
|
@@ -62,7 +63,7 @@ async function updateEnvTemplate(appKey, clientIdKey, clientSecretKey, controlle
|
|
|
62
63
|
missingEntries.push(`MISO_CLIENTSECRET=kv://${clientSecretKey}`);
|
|
63
64
|
}
|
|
64
65
|
if (!hasControllerUrl) {
|
|
65
|
-
missingEntries.push(
|
|
66
|
+
missingEntries.push('MISO_CONTROLLER_URL=http://${MISO_HOST}:${MISO_PORT}');
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
const misoSection = `# MISO Application Client Credentials (per application)
|
package/package.json
CHANGED
|
@@ -26,13 +26,19 @@ KC_HTTP_MANAGEMENT_HEALTH_ENABLED=false
|
|
|
26
26
|
# =============================================================================
|
|
27
27
|
# DATABASE CONFIGURATION
|
|
28
28
|
# =============================================================================
|
|
29
|
+
|
|
30
|
+
# MISO Application Client Credentials (per application)
|
|
31
|
+
MISO_CLIENTID=kv://keycloak-client-idKeyVault
|
|
32
|
+
MISO_CLIENTSECRET=kv://keycloak-client-secretKeyVault
|
|
33
|
+
MISO_CONTROLLER_URL=http://${MISO_HOST}:${MISO_PORT}
|
|
34
|
+
MISO_WEB_SERVER_URL=kv://miso-controller-web-server-url
|
|
35
|
+
|
|
29
36
|
# Connects to postgres service in Docker network (postgres) or localhost (local)
|
|
30
37
|
|
|
31
38
|
KC_DB=postgres
|
|
32
39
|
KC_DB_URL_HOST=${DB_HOST}
|
|
33
|
-
KC_DB_URL_PORT
|
|
40
|
+
KC_DB_URL_PORT=${DB_PORT}
|
|
34
41
|
KC_DB_URL_DATABASE=keycloak
|
|
35
42
|
KC_DB_USERNAME=keycloak_user
|
|
36
43
|
KC_DB_PASSWORD=kv://databases-keycloak-0-passwordKeyVault
|
|
37
44
|
DB_0_PASSWORD=kv://databases-keycloak-0-passwordKeyVault
|
|
38
|
-
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Application Metadata
|
|
2
2
|
app:
|
|
3
3
|
key: keycloak
|
|
4
|
-
displayName:
|
|
5
|
-
description:
|
|
4
|
+
displayName: 'AI Fabrix Keycloak'
|
|
5
|
+
description: 'Identity and Access Management'
|
|
6
6
|
type: webapp
|
|
7
7
|
|
|
8
8
|
# Image Configuration
|
|
9
9
|
image:
|
|
10
10
|
name: aifabrix/keycloak
|
|
11
|
-
tag:
|
|
11
|
+
tag: 'latest'
|
|
12
12
|
registry: devflowiseacr.azurecr.io
|
|
13
13
|
registryMode: acr
|
|
14
14
|
|
|
@@ -28,13 +28,21 @@ ONBOARDING_ADMIN_EMAIL=kv://miso-controller-admin-emailKeyVault
|
|
|
28
28
|
# APPLICATION ENVIRONMENT
|
|
29
29
|
# =============================================================================
|
|
30
30
|
|
|
31
|
-
NODE_ENV
|
|
32
|
-
|
|
31
|
+
# NODE_ENV: production for Docker (serves pre-built static files), development for local dev
|
|
32
|
+
# In Docker, this should be production to prevent Vite dev server initialization
|
|
33
|
+
NODE_ENV=${NODE_ENV}
|
|
34
|
+
PORT=${MISO_PORT}
|
|
33
35
|
AUTO_CREATE_TABLES=true
|
|
34
36
|
FAST_STARTUP=false
|
|
35
|
-
ALLOWED_ORIGINS=http://localhost
|
|
37
|
+
ALLOWED_ORIGINS=http://localhost:*
|
|
36
38
|
ENABLE_API_DOCS=true
|
|
37
39
|
|
|
40
|
+
# Rate Limiting Configuration (for local development)
|
|
41
|
+
# Set DISABLE_RATE_LIMIT=true to disable rate limiting entirely (local development only)
|
|
42
|
+
DISABLE_RATE_LIMIT=true
|
|
43
|
+
# RATE_LIMIT_WINDOW_MS=900000 # 15 minutes in milliseconds (default: 900000)
|
|
44
|
+
# RATE_LIMIT_MAX=100 # Max requests per window (default: 100)
|
|
45
|
+
|
|
38
46
|
# Package Version (auto-set by npm/pnpm, optional override)
|
|
39
47
|
# npm_package_version=1.0.0
|
|
40
48
|
|
|
@@ -72,6 +80,7 @@ REDIS_PERMISSIONS_TTL=900
|
|
|
72
80
|
|
|
73
81
|
KEYCLOAK_REALM=aifabrix
|
|
74
82
|
KEYCLOAK_SERVER_URL=kv://keycloak-server-urlKeyVault
|
|
83
|
+
KEYCLOAK_PUBLIC_SERVER_URL=kv://keycloak-public-server-urlKeyVault
|
|
75
84
|
KEYCLOAK_CLIENT_ID=miso-controller
|
|
76
85
|
KEYCLOAK_CLIENT_SECRET=kv://keycloak-client-secretKeyVault
|
|
77
86
|
KEYCLOAK_ADMIN_USERNAME=admin
|
|
@@ -96,8 +105,9 @@ AZURE_SERVICE_NAME=kv://azure-service-nameKeyVault
|
|
|
96
105
|
AZURE_CLIENT_ID=kv://azure-client-idKeyVault
|
|
97
106
|
AZURE_CLIENT_SECRET=kv://azure-client-secretKeyVault
|
|
98
107
|
|
|
99
|
-
# Mock Mode (
|
|
100
|
-
MOCK=true
|
|
108
|
+
# Mock Mode (defaults to false - set to true only for testing/development)
|
|
109
|
+
# Set MOCK=true to prevent actual Azure resource creation (for testing)
|
|
110
|
+
MOCK=false
|
|
101
111
|
|
|
102
112
|
# =============================================================================
|
|
103
113
|
# SECURITY & ENCRYPTION
|
|
@@ -117,11 +127,14 @@ API_KEY=kv://miso-controller-api-key-secretKeyVault
|
|
|
117
127
|
# =============================================================================
|
|
118
128
|
|
|
119
129
|
# MISO Controller URL
|
|
120
|
-
MISO_CONTROLLER_URL=
|
|
121
|
-
|
|
122
|
-
# Web Server URL (for OpenAPI documentation server URLs)
|
|
123
|
-
#
|
|
124
|
-
|
|
130
|
+
MISO_CONTROLLER_URL=http://${MISO_HOST}:${MISO_PORT}
|
|
131
|
+
|
|
132
|
+
# Web Server URL (for OpenAPI documentation server URLs and Keycloak callbacks)
|
|
133
|
+
# This is the PUBLIC-FACING URL that browsers/users access (e.g., http://localhost:3100)
|
|
134
|
+
# Used to generate correct server URLs in OpenAPI spec and Keycloak callback URLs
|
|
135
|
+
# For Docker: use localhost with mapped port (e.g., localhost:3100)
|
|
136
|
+
# For production: use public domain (e.g., https://miso.example.com)
|
|
137
|
+
MISO_WEB_SERVER_URL=kv://miso-controller-web-server-url
|
|
125
138
|
|
|
126
139
|
# MISO Environment Configuration (miso, dev, tst, pro)
|
|
127
140
|
MISO_ENVIRONMENT=miso
|
|
@@ -1,230 +1,280 @@
|
|
|
1
1
|
roles:
|
|
2
|
-
- name:
|
|
3
|
-
value:
|
|
4
|
-
description:
|
|
5
|
-
Groups: [
|
|
6
|
-
|
|
7
|
-
- name:
|
|
8
|
-
value:
|
|
9
|
-
description:
|
|
10
|
-
Groups: [
|
|
11
|
-
|
|
12
|
-
- name:
|
|
13
|
-
value:
|
|
14
|
-
description:
|
|
15
|
-
Groups: [
|
|
16
|
-
|
|
17
|
-
- name:
|
|
18
|
-
value:
|
|
19
|
-
description:
|
|
20
|
-
Groups: [
|
|
21
|
-
|
|
22
|
-
- name:
|
|
23
|
-
value:
|
|
24
|
-
description:
|
|
25
|
-
Groups: [
|
|
26
|
-
|
|
27
|
-
- name:
|
|
28
|
-
value:
|
|
29
|
-
description:
|
|
30
|
-
Groups: [
|
|
31
|
-
|
|
32
|
-
- name:
|
|
33
|
-
value:
|
|
34
|
-
description:
|
|
35
|
-
Groups: [
|
|
2
|
+
- name: 'AI Fabrix Platform Admin'
|
|
3
|
+
value: 'aifabrix-platform-admin'
|
|
4
|
+
description: 'Full platform infrastructure management and enterprise controller access'
|
|
5
|
+
Groups: ['AI-Fabrix-Platform-Admins']
|
|
6
|
+
|
|
7
|
+
- name: 'AI Fabrix Security Admin'
|
|
8
|
+
value: 'aifabrix-security-admin'
|
|
9
|
+
description: 'Security and compliance management for enterprise controller'
|
|
10
|
+
Groups: ['AI-Fabrix-Security-Admins']
|
|
11
|
+
|
|
12
|
+
- name: 'AI Fabrix Infrastructure Admin'
|
|
13
|
+
value: 'aifabrix-infrastructure-admin'
|
|
14
|
+
description: 'Infrastructure deployment and management across environments'
|
|
15
|
+
Groups: ['AI-Fabrix-Infrastructure-Admins']
|
|
16
|
+
|
|
17
|
+
- name: 'AI Fabrix Deployment Admin'
|
|
18
|
+
value: 'aifabrix-deployment-admin'
|
|
19
|
+
description: 'Application deployment orchestration and environment management'
|
|
20
|
+
Groups: ['AI-Fabrix-Deployment-Admins']
|
|
21
|
+
|
|
22
|
+
- name: 'AI Fabrix Compliance Admin'
|
|
23
|
+
value: 'aifabrix-compliance-admin'
|
|
24
|
+
description: 'ISO 27001 compliance monitoring and audit management'
|
|
25
|
+
Groups: ['AI-Fabrix-Compliance-Admins']
|
|
26
|
+
|
|
27
|
+
- name: 'AI Fabrix Developer'
|
|
28
|
+
value: 'aifabrix-developer'
|
|
29
|
+
description: 'Developer access to deploy applications via GitHub Actions'
|
|
30
|
+
Groups: ['AI-Fabrix-Developers']
|
|
31
|
+
|
|
32
|
+
- name: 'AI Fabrix Observer'
|
|
33
|
+
value: 'aifabrix-observer'
|
|
34
|
+
description: 'Read-only access to monitoring, logs, and compliance reports'
|
|
35
|
+
Groups: ['AI-Fabrix-Observers']
|
|
36
36
|
|
|
37
37
|
permissions:
|
|
38
38
|
# Service User Management
|
|
39
|
-
- name:
|
|
40
|
-
roles: [
|
|
41
|
-
description:
|
|
42
|
-
|
|
43
|
-
- name:
|
|
44
|
-
roles: [
|
|
45
|
-
description:
|
|
46
|
-
|
|
47
|
-
- name:
|
|
48
|
-
roles: [
|
|
49
|
-
description:
|
|
50
|
-
|
|
51
|
-
- name:
|
|
52
|
-
roles: [
|
|
53
|
-
description:
|
|
54
|
-
|
|
39
|
+
- name: 'service-user:create'
|
|
40
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
41
|
+
description: 'Create service users and API clients'
|
|
42
|
+
|
|
43
|
+
- name: 'service-user:read'
|
|
44
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-observer']
|
|
45
|
+
description: 'View service users and their configurations'
|
|
46
|
+
|
|
47
|
+
- name: 'service-user:update'
|
|
48
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
49
|
+
description: 'Update service user configurations and regenerate secrets'
|
|
50
|
+
|
|
51
|
+
- name: 'service-user:delete'
|
|
52
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
53
|
+
description: 'Deactivate service users'
|
|
54
|
+
|
|
55
55
|
# User Management
|
|
56
|
-
- name:
|
|
57
|
-
roles: [
|
|
58
|
-
description:
|
|
59
|
-
|
|
60
|
-
- name:
|
|
61
|
-
roles: [
|
|
62
|
-
description:
|
|
63
|
-
|
|
64
|
-
- name:
|
|
65
|
-
roles: [
|
|
66
|
-
description:
|
|
67
|
-
|
|
68
|
-
- name:
|
|
69
|
-
roles: [
|
|
70
|
-
description:
|
|
71
|
-
|
|
56
|
+
- name: 'users:create'
|
|
57
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
58
|
+
description: 'Create new users'
|
|
59
|
+
|
|
60
|
+
- name: 'users:read'
|
|
61
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-observer']
|
|
62
|
+
description: 'View user information and profiles'
|
|
63
|
+
|
|
64
|
+
- name: 'users:update'
|
|
65
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
66
|
+
description: 'Update user information and manage group memberships'
|
|
67
|
+
|
|
68
|
+
- name: 'users:delete'
|
|
69
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
70
|
+
description: 'Delete users'
|
|
71
|
+
|
|
72
72
|
# Group Management
|
|
73
|
-
- name:
|
|
74
|
-
roles: [
|
|
75
|
-
description:
|
|
76
|
-
|
|
77
|
-
- name:
|
|
78
|
-
roles: [
|
|
79
|
-
description:
|
|
80
|
-
|
|
81
|
-
- name:
|
|
82
|
-
roles: [
|
|
83
|
-
description:
|
|
84
|
-
|
|
85
|
-
- name:
|
|
86
|
-
roles: [
|
|
87
|
-
description:
|
|
88
|
-
|
|
73
|
+
- name: 'groups:create'
|
|
74
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
75
|
+
description: 'Create new groups'
|
|
76
|
+
|
|
77
|
+
- name: 'groups:read'
|
|
78
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-observer']
|
|
79
|
+
description: 'View group information and members'
|
|
80
|
+
|
|
81
|
+
- name: 'groups:update'
|
|
82
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
83
|
+
description: 'Update group information'
|
|
84
|
+
|
|
85
|
+
- name: 'groups:delete'
|
|
86
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
87
|
+
description: 'Delete groups'
|
|
88
|
+
|
|
89
89
|
# Administrative Permissions
|
|
90
|
-
- name:
|
|
91
|
-
roles: [
|
|
92
|
-
description:
|
|
93
|
-
|
|
94
|
-
- name:
|
|
95
|
-
roles: [
|
|
96
|
-
description:
|
|
97
|
-
|
|
98
|
-
- name:
|
|
99
|
-
roles: [
|
|
100
|
-
description:
|
|
101
|
-
|
|
90
|
+
- name: 'admin:read'
|
|
91
|
+
roles: ['aifabrix-platform-admin']
|
|
92
|
+
description: 'Administrative read access to all resources'
|
|
93
|
+
|
|
94
|
+
- name: 'admin:write'
|
|
95
|
+
roles: ['aifabrix-platform-admin']
|
|
96
|
+
description: 'Administrative write access to all resources'
|
|
97
|
+
|
|
98
|
+
- name: 'admin:delete'
|
|
99
|
+
roles: ['aifabrix-platform-admin']
|
|
100
|
+
description: 'Administrative delete access to all resources'
|
|
101
|
+
|
|
102
102
|
# Template Applications (environment = null)
|
|
103
|
-
- name:
|
|
104
|
-
roles: [
|
|
105
|
-
description:
|
|
106
|
-
|
|
107
|
-
- name:
|
|
108
|
-
roles:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
103
|
+
- name: 'applications:create'
|
|
104
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin', 'aifabrix-deployment-admin']
|
|
105
|
+
description: 'Register new application templates'
|
|
106
|
+
|
|
107
|
+
- name: 'applications:read'
|
|
108
|
+
roles:
|
|
109
|
+
[
|
|
110
|
+
'aifabrix-platform-admin',
|
|
111
|
+
'aifabrix-infrastructure-admin',
|
|
112
|
+
'aifabrix-deployment-admin',
|
|
113
|
+
'aifabrix-developer',
|
|
114
|
+
'aifabrix-observer'
|
|
115
|
+
]
|
|
116
|
+
description: 'View application templates'
|
|
117
|
+
|
|
118
|
+
- name: 'applications:update'
|
|
119
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin', 'aifabrix-deployment-admin']
|
|
120
|
+
description: 'Update application templates'
|
|
121
|
+
|
|
122
|
+
- name: 'applications:delete'
|
|
123
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin']
|
|
124
|
+
description: 'Remove application templates'
|
|
125
|
+
|
|
119
126
|
# Environments
|
|
120
|
-
- name:
|
|
121
|
-
roles: [
|
|
122
|
-
description:
|
|
123
|
-
|
|
124
|
-
- name:
|
|
125
|
-
roles:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
127
|
+
- name: 'environments:create'
|
|
128
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin']
|
|
129
|
+
description: 'Create new environments (dev, tst, pro, miso)'
|
|
130
|
+
|
|
131
|
+
- name: 'environments:read'
|
|
132
|
+
roles:
|
|
133
|
+
[
|
|
134
|
+
'aifabrix-platform-admin',
|
|
135
|
+
'aifabrix-infrastructure-admin',
|
|
136
|
+
'aifabrix-deployment-admin',
|
|
137
|
+
'aifabrix-developer',
|
|
138
|
+
'aifabrix-observer'
|
|
139
|
+
]
|
|
140
|
+
description: 'View environments and their status'
|
|
141
|
+
|
|
142
|
+
- name: 'environments:update'
|
|
143
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin']
|
|
144
|
+
description: 'Update environment configuration'
|
|
145
|
+
|
|
146
|
+
- name: 'environments:delete'
|
|
147
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin']
|
|
148
|
+
description: 'Delete environments'
|
|
149
|
+
|
|
136
150
|
# Environment Applications
|
|
137
|
-
- name:
|
|
138
|
-
roles: [
|
|
139
|
-
description:
|
|
140
|
-
|
|
141
|
-
- name:
|
|
142
|
-
roles:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
- name: 'environments-applications:create'
|
|
152
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-deployment-admin', 'aifabrix-developer']
|
|
153
|
+
description: 'Create applications within environments'
|
|
154
|
+
|
|
155
|
+
- name: 'environments-applications:read'
|
|
156
|
+
roles:
|
|
157
|
+
[
|
|
158
|
+
'aifabrix-platform-admin',
|
|
159
|
+
'aifabrix-deployment-admin',
|
|
160
|
+
'aifabrix-developer',
|
|
161
|
+
'aifabrix-observer'
|
|
162
|
+
]
|
|
163
|
+
description: 'View applications within environments'
|
|
164
|
+
|
|
165
|
+
- name: 'environments-applications:update'
|
|
166
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-deployment-admin', 'aifabrix-developer']
|
|
167
|
+
description: 'Update applications within environments'
|
|
168
|
+
|
|
169
|
+
- name: 'environments-applications:delete'
|
|
170
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-deployment-admin']
|
|
171
|
+
description: 'Remove applications from environments'
|
|
172
|
+
|
|
153
173
|
# Pipeline & Deployment
|
|
154
|
-
- name:
|
|
155
|
-
roles: [
|
|
156
|
-
description:
|
|
157
|
-
|
|
158
|
-
- name:
|
|
159
|
-
roles:
|
|
160
|
-
|
|
161
|
-
|
|
174
|
+
- name: 'applications:deploy'
|
|
175
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-deployment-admin', 'aifabrix-developer']
|
|
176
|
+
description: 'Deploy applications to environments'
|
|
177
|
+
|
|
178
|
+
- name: 'deployments:read'
|
|
179
|
+
roles:
|
|
180
|
+
[
|
|
181
|
+
'aifabrix-platform-admin',
|
|
182
|
+
'aifabrix-deployment-admin',
|
|
183
|
+
'aifabrix-developer',
|
|
184
|
+
'aifabrix-observer'
|
|
185
|
+
]
|
|
186
|
+
description: 'View deployment history and status'
|
|
187
|
+
|
|
162
188
|
# Controller Operations
|
|
163
|
-
- name:
|
|
164
|
-
roles: [
|
|
165
|
-
description:
|
|
166
|
-
|
|
167
|
-
- name:
|
|
168
|
-
roles: [
|
|
169
|
-
description:
|
|
170
|
-
|
|
171
|
-
- name:
|
|
172
|
-
roles: [
|
|
173
|
-
description:
|
|
174
|
-
|
|
175
|
-
- name:
|
|
176
|
-
roles: [
|
|
177
|
-
description:
|
|
178
|
-
|
|
189
|
+
- name: 'controller:admin'
|
|
190
|
+
roles: ['aifabrix-platform-admin']
|
|
191
|
+
description: 'Full administrative access to controller operations'
|
|
192
|
+
|
|
193
|
+
- name: 'controller:deploy'
|
|
194
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin', 'aifabrix-deployment-admin']
|
|
195
|
+
description: 'Deploy infrastructure and manage environments'
|
|
196
|
+
|
|
197
|
+
- name: 'controller:monitor'
|
|
198
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-observer']
|
|
199
|
+
description: 'Monitor system health and view logs'
|
|
200
|
+
|
|
201
|
+
- name: 'controller:compliance'
|
|
202
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-compliance-admin']
|
|
203
|
+
description: 'Access compliance reports and audit logs'
|
|
204
|
+
|
|
179
205
|
# Authentication & Authorization
|
|
180
|
-
- name:
|
|
181
|
-
roles:
|
|
182
|
-
|
|
183
|
-
|
|
206
|
+
- name: 'auth:read'
|
|
207
|
+
roles:
|
|
208
|
+
[
|
|
209
|
+
'aifabrix-platform-admin',
|
|
210
|
+
'aifabrix-security-admin',
|
|
211
|
+
'aifabrix-developer',
|
|
212
|
+
'aifabrix-observer'
|
|
213
|
+
]
|
|
214
|
+
description: 'View user roles and permissions'
|
|
215
|
+
|
|
184
216
|
# Logs
|
|
185
|
-
- name:
|
|
186
|
-
roles:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
217
|
+
- name: 'logs:read'
|
|
218
|
+
roles:
|
|
219
|
+
[
|
|
220
|
+
'aifabrix-platform-admin',
|
|
221
|
+
'aifabrix-security-admin',
|
|
222
|
+
'aifabrix-compliance-admin',
|
|
223
|
+
'aifabrix-observer'
|
|
224
|
+
]
|
|
225
|
+
description: 'View application and audit logs'
|
|
226
|
+
|
|
227
|
+
- name: 'logs:write'
|
|
228
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-developer']
|
|
229
|
+
description: 'Write audit and error logs'
|
|
230
|
+
|
|
231
|
+
- name: 'logs:export'
|
|
232
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-compliance-admin']
|
|
233
|
+
description: 'Export logs for archival and compliance'
|
|
234
|
+
|
|
235
|
+
- name: 'audit:read'
|
|
236
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-compliance-admin']
|
|
237
|
+
description: 'View audit trail logs'
|
|
238
|
+
|
|
239
|
+
- name: 'jobs:read'
|
|
240
|
+
roles:
|
|
241
|
+
[
|
|
242
|
+
'aifabrix-platform-admin',
|
|
243
|
+
'aifabrix-infrastructure-admin',
|
|
244
|
+
'aifabrix-deployment-admin',
|
|
245
|
+
'aifabrix-observer'
|
|
246
|
+
]
|
|
247
|
+
description: 'View job and performance logs'
|
|
248
|
+
|
|
249
|
+
- name: 'admin:export'
|
|
250
|
+
roles: ['aifabrix-platform-admin']
|
|
251
|
+
description: 'Administrative export access to all data'
|
|
252
|
+
|
|
209
253
|
# Admin Operations
|
|
210
|
-
- name:
|
|
211
|
-
roles: [
|
|
212
|
-
description:
|
|
213
|
-
|
|
214
|
-
- name:
|
|
215
|
-
roles: [
|
|
216
|
-
description:
|
|
217
|
-
|
|
254
|
+
- name: 'admin:sync'
|
|
255
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-infrastructure-admin']
|
|
256
|
+
description: 'Full system synchronization operations'
|
|
257
|
+
|
|
258
|
+
- name: 'admin:keycloak'
|
|
259
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin']
|
|
260
|
+
description: 'Keycloak administration and configuration'
|
|
261
|
+
|
|
218
262
|
# Cache Management
|
|
219
|
-
- name:
|
|
220
|
-
roles: [
|
|
221
|
-
description:
|
|
222
|
-
|
|
223
|
-
- name:
|
|
224
|
-
roles: [
|
|
225
|
-
description:
|
|
226
|
-
|
|
263
|
+
- name: 'cache:read'
|
|
264
|
+
roles: ['aifabrix-platform-admin', 'aifabrix-security-admin', 'aifabrix-observer']
|
|
265
|
+
description: 'View cache statistics and performance metrics'
|
|
266
|
+
|
|
267
|
+
- name: 'cache:admin'
|
|
268
|
+
roles: ['aifabrix-platform-admin']
|
|
269
|
+
description: 'Manage cache (clear, invalidate patterns)'
|
|
270
|
+
|
|
227
271
|
# Dashboard
|
|
228
|
-
- name:
|
|
229
|
-
roles:
|
|
230
|
-
|
|
272
|
+
- name: 'dashboard:read'
|
|
273
|
+
roles:
|
|
274
|
+
[
|
|
275
|
+
'aifabrix-platform-admin',
|
|
276
|
+
'aifabrix-deployment-admin',
|
|
277
|
+
'aifabrix-developer',
|
|
278
|
+
'aifabrix-observer'
|
|
279
|
+
]
|
|
280
|
+
description: 'View dashboard summaries and aggregates'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Application Metadata
|
|
2
2
|
app:
|
|
3
3
|
key: miso-controller
|
|
4
|
-
displayName:
|
|
5
|
-
description:
|
|
4
|
+
displayName: 'Miso Controller'
|
|
5
|
+
description: 'AI Fabrix Miso Controller - Backend API and orchestration service'
|
|
6
6
|
type: webapp
|
|
7
7
|
|
|
8
8
|
# Image Configuration
|
|
@@ -34,7 +34,7 @@ healthCheck:
|
|
|
34
34
|
|
|
35
35
|
# Authentication
|
|
36
36
|
authentication:
|
|
37
|
-
type:
|
|
37
|
+
type: keycloak
|
|
38
38
|
enableSSO: true
|
|
39
39
|
requiredRoles:
|
|
40
40
|
- aifabrix-user
|