@aifabrix/builder 2.40.0 → 2.41.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/README.md +7 -5
- package/integration/hubspot/test.js +1 -1
- package/jest.config.manual.js +29 -0
- package/lib/api/credential.api.js +40 -0
- package/lib/api/dev.api.js +423 -0
- package/lib/api/types/credential.types.js +23 -0
- package/lib/api/types/dev.types.js +140 -0
- package/lib/app/config.js +21 -0
- package/lib/app/down.js +2 -1
- package/lib/app/index.js +9 -0
- package/lib/app/push.js +36 -12
- package/lib/app/readme.js +1 -3
- package/lib/app/run-env-compose.js +201 -0
- package/lib/app/run-helpers.js +121 -118
- package/lib/app/run.js +148 -28
- package/lib/app/show.js +5 -2
- package/lib/build/index.js +11 -3
- package/lib/cli/setup-app.js +140 -14
- package/lib/cli/setup-auth.js +1 -0
- package/lib/cli/setup-dev.js +180 -17
- package/lib/cli/setup-environment.js +4 -2
- package/lib/cli/setup-external-system.js +71 -21
- package/lib/cli/setup-infra.js +29 -2
- package/lib/cli/setup-secrets.js +52 -5
- package/lib/cli/setup-utility.js +19 -4
- package/lib/commands/app-install.js +172 -0
- package/lib/commands/app-shell.js +75 -0
- package/lib/commands/app-test.js +282 -0
- package/lib/commands/app.js +1 -1
- package/lib/commands/auth-status.js +36 -3
- package/lib/commands/dev-cli-handlers.js +141 -0
- package/lib/commands/dev-down.js +114 -0
- package/lib/commands/dev-init.js +309 -0
- package/lib/commands/secrets-list.js +118 -0
- package/lib/commands/secrets-remove.js +97 -0
- package/lib/commands/secrets-set.js +30 -17
- package/lib/commands/secrets-validate.js +50 -0
- package/lib/commands/up-dataplane.js +2 -2
- package/lib/commands/up-miso.js +0 -25
- package/lib/commands/upload.js +26 -1
- package/lib/core/admin-secrets.js +96 -0
- package/lib/core/secrets-ensure.js +378 -0
- package/lib/core/secrets-env-write.js +157 -0
- package/lib/core/secrets.js +147 -81
- package/lib/datasource/field-reference-validator.js +91 -0
- package/lib/datasource/validate.js +21 -3
- package/lib/deployment/environment-config.js +137 -0
- package/lib/deployment/environment.js +21 -98
- package/lib/deployment/push.js +32 -2
- package/lib/external-system/download.js +7 -0
- package/lib/external-system/test-auth.js +7 -3
- package/lib/external-system/test.js +5 -1
- package/lib/generator/index.js +174 -25
- package/lib/generator/wizard.js +13 -1
- package/lib/infrastructure/helpers.js +103 -20
- package/lib/infrastructure/index.js +88 -10
- package/lib/infrastructure/services.js +70 -15
- package/lib/schema/application-schema.json +24 -3
- package/lib/schema/external-system.schema.json +435 -413
- package/lib/utils/api.js +3 -3
- package/lib/utils/app-register-auth.js +25 -3
- package/lib/utils/cli-utils.js +20 -0
- package/lib/utils/compose-generator.js +76 -75
- package/lib/utils/compose-handlebars-helpers.js +43 -0
- package/lib/utils/compose-vector-helper.js +18 -0
- package/lib/utils/config-paths.js +127 -2
- package/lib/utils/credential-secrets-env.js +267 -0
- package/lib/utils/dev-cert-helper.js +122 -0
- package/lib/utils/device-code-helpers.js +224 -0
- package/lib/utils/device-code.js +37 -336
- package/lib/utils/docker-build.js +40 -8
- package/lib/utils/env-copy.js +83 -13
- package/lib/utils/env-map.js +35 -5
- package/lib/utils/env-template.js +6 -5
- package/lib/utils/error-formatters/http-status-errors.js +20 -1
- package/lib/utils/help-builder.js +15 -2
- package/lib/utils/infra-status.js +30 -1
- package/lib/utils/local-secrets.js +7 -52
- package/lib/utils/mutagen-install.js +195 -0
- package/lib/utils/mutagen.js +146 -0
- package/lib/utils/paths.js +49 -33
- package/lib/utils/port-resolver.js +28 -16
- package/lib/utils/remote-dev-auth.js +38 -0
- package/lib/utils/remote-docker-env.js +43 -0
- package/lib/utils/remote-secrets-loader.js +60 -0
- package/lib/utils/secrets-generator.js +94 -6
- package/lib/utils/secrets-helpers.js +33 -25
- package/lib/utils/secrets-path.js +2 -2
- package/lib/utils/secrets-utils.js +52 -1
- package/lib/utils/secrets-validation.js +84 -0
- package/lib/utils/ssh-key-helper.js +116 -0
- package/lib/utils/token-manager-messages.js +90 -0
- package/lib/utils/token-manager.js +5 -4
- package/lib/utils/variable-transformer.js +3 -3
- package/lib/validation/validate.js +1 -1
- package/lib/validation/validator.js +65 -0
- package/package.json +4 -2
- package/scripts/install-local.js +34 -15
- package/templates/README.md +0 -1
- package/templates/applications/README.md.hbs +4 -4
- package/templates/applications/dataplane/application.yaml +5 -4
- package/templates/applications/dataplane/env.template +12 -7
- package/templates/applications/keycloak/env.template +2 -0
- package/templates/applications/miso-controller/application.yaml +1 -0
- package/templates/applications/miso-controller/env.template +11 -9
- package/templates/external-system/external-system.json.hbs +1 -16
- package/templates/python/docker-compose.hbs +49 -23
- package/templates/typescript/docker-compose.hbs +48 -22
|
@@ -48,11 +48,12 @@ authentication:
|
|
|
48
48
|
# Build Configuration
|
|
49
49
|
# Dataplane builds from published image; context is project root (like miso-controller)
|
|
50
50
|
build:
|
|
51
|
-
context: ../..
|
|
51
|
+
context: ../.. # Docker build context (relative to builder/dataplane/)
|
|
52
52
|
dockerfile: builder/dataplane/Dockerfile # Dockerfile path (relative to project root)
|
|
53
|
-
envOutputPath: ../../.env
|
|
54
|
-
localPort: 3011
|
|
55
|
-
language: python
|
|
53
|
+
envOutputPath: ../../.env # Copy to repo root for local dev
|
|
54
|
+
localPort: 3011 # Port for local development (different from Docker port)
|
|
55
|
+
language: python # Runtime language for template selection (typescript or python)
|
|
56
|
+
reloadStart: uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-3001} --reload # PORT set from port above at run time; default 3001 must match port
|
|
56
57
|
|
|
57
58
|
# =============================================================================
|
|
58
59
|
# Portal Input Configuration (Deployment Wizard)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# =============================================================================
|
|
8
8
|
|
|
9
9
|
# HTTP port for the app
|
|
10
|
-
PORT
|
|
10
|
+
PORT=${PORT}
|
|
11
11
|
# development | staging | production
|
|
12
12
|
ENVIRONMENT=development
|
|
13
13
|
# Enable debug mode
|
|
@@ -30,8 +30,8 @@ API_KEY=kv://miso-controller-api-key-secretKeyVault
|
|
|
30
30
|
API_V1_STR=/api/v1
|
|
31
31
|
VERSION=1.7.0
|
|
32
32
|
# Base URL for the dataplane web server (used for default OAuth2 callback URL when redirectUri is omitted)
|
|
33
|
-
DATAPLANE_WEB_SERVER_URL=kv://dataplane-web-server-
|
|
34
|
-
DATAPLANE_INTERNAL_URL=kv://dataplane-internal-server-
|
|
33
|
+
DATAPLANE_WEB_SERVER_URL=kv://dataplane-web-server-url
|
|
34
|
+
DATAPLANE_INTERNAL_URL=kv://dataplane-internal-server-url
|
|
35
35
|
|
|
36
36
|
# CORS Configuration
|
|
37
37
|
ALLOWED_ORIGINS=http://localhost:*
|
|
@@ -43,6 +43,11 @@ ENCRYPTION_KEY=kv://secrets-encryptionKeyVault
|
|
|
43
43
|
# =============================================================================
|
|
44
44
|
# DATABASE CONFIGURATION
|
|
45
45
|
# =============================================================================
|
|
46
|
+
# Multiple-database layout: set all four URL env vars for four separate databases
|
|
47
|
+
# (dataplane, dataplane-vector, dataplane-logs, dataplane-records). If any
|
|
48
|
+
# dedicated URL is unset, that database's tables use DATABASE_URL (main).
|
|
49
|
+
# See docs/DATABASE_TABLES_LOCATION.md for table-to-database mapping.
|
|
50
|
+
# =============================================================================
|
|
46
51
|
|
|
47
52
|
# Primary app database URL
|
|
48
53
|
DATABASE_URL=kv://databases-dataplane-0-urlKeyVault
|
|
@@ -89,18 +94,18 @@ MISO_CLIENTSECRET=kv://dataplane-client-secretKeyVault
|
|
|
89
94
|
|
|
90
95
|
# Keycloak Configuration (for OAuth2 endpoints)
|
|
91
96
|
# Public: used by OpenAPI OAuth2 / browser (authorizationUrl, tokenUrl).
|
|
92
|
-
KEYCLOAK_SERVER_URL=kv://keycloak-server-
|
|
97
|
+
KEYCLOAK_SERVER_URL=kv://keycloak-server-url
|
|
93
98
|
# Internal (same role as MISO_CONTROLLER_URL): future server-side Keycloak (e.g. JWKS). Not used by dataplane today.
|
|
94
|
-
KEYCLOAK_INTERNAL_SERVER_URL=kv://keycloak-internal-server-
|
|
99
|
+
KEYCLOAK_INTERNAL_SERVER_URL=kv://keycloak-internal-server-url
|
|
95
100
|
KEYCLOAK_REALM=aifabrix
|
|
96
101
|
|
|
97
102
|
# =============================================================================
|
|
98
103
|
# MISO CONTROLLER CONFIGURATION
|
|
99
104
|
# =============================================================================
|
|
100
105
|
# Public: browser redirects and CORS for client_token; set when controller is behind a different public URL.
|
|
101
|
-
MISO_WEB_SERVER_URL=kv://miso-controller-web-server-
|
|
106
|
+
MISO_WEB_SERVER_URL=kv://miso-controller-web-server-url
|
|
102
107
|
# Internal: server-to-controller API calls (auth, pipeline, status, RBAC).
|
|
103
|
-
MISO_CONTROLLER_URL=
|
|
108
|
+
MISO_CONTROLLER_URL=kv://miso-controller-internal-server-url
|
|
104
109
|
|
|
105
110
|
# Pipeline env key for controller URLs: /api/v1/pipeline/{envKey}/validate and /deploy.
|
|
106
111
|
# Set MISO_PIPELINE_ENV_KEY=dev when controller uses dev (e.g. MISO_CLIENTID=miso-controller-dev-dataplane).
|
|
@@ -39,6 +39,8 @@ KC_HEALTH_ENABLED=true
|
|
|
39
39
|
# Expose health endpoints on main HTTP port (like Keycloak 24.0)
|
|
40
40
|
# Set to false to expose on main port instead of management port (9000)
|
|
41
41
|
KC_HTTP_MANAGEMENT_HEALTH_ENABLED=false
|
|
42
|
+
# Single-instance: use local cache so /health/ready passes (avoids Infinispan cluster check)
|
|
43
|
+
KC_CACHE=local
|
|
42
44
|
|
|
43
45
|
# =============================================================================
|
|
44
46
|
# DATABASE CONFIGURATION
|
|
@@ -47,6 +47,7 @@ build:
|
|
|
47
47
|
envOutputPath: ../../packages/miso-controller/.env # Copy .env to repo root for local dev (relative to builder/) (if null, no .env file is copied) (if empty, .env file is copied to repo root)
|
|
48
48
|
localPort: 3010 # Port for local development (different from Docker port)
|
|
49
49
|
language: typescript # Runtime language for template selection (typescript or python)
|
|
50
|
+
reloadStart: pnpm run start:reload # When running with --reload
|
|
50
51
|
|
|
51
52
|
# =============================================================================
|
|
52
53
|
# Portal Input Configuration (Deployment Wizard)
|
|
@@ -49,8 +49,8 @@ ONBOARDING_CREATE_DEV_ENV=true
|
|
|
49
49
|
|
|
50
50
|
# NODE_ENV: production for Docker (serves pre-built static files), development for local dev
|
|
51
51
|
# In Docker, this should be production to prevent Vite dev server initialization
|
|
52
|
-
NODE_ENV
|
|
53
|
-
PORT=${
|
|
52
|
+
NODE_ENV=dev
|
|
53
|
+
PORT=${PORT}
|
|
54
54
|
AUTO_CREATE_TABLES=true
|
|
55
55
|
FAST_STARTUP=false
|
|
56
56
|
ALLOWED_ORIGINS=http://localhost:*
|
|
@@ -105,13 +105,12 @@ REDIS_PERMISSIONS_TTL=900
|
|
|
105
105
|
# (KeycloakConfiguration + Application url/internalUrl). Sync env->DB at startup via
|
|
106
106
|
# sync-application-urls-from-env.service.
|
|
107
107
|
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
KEYCLOAK_SKIP_AZURE_ENTRA_SSO=false
|
|
108
|
+
# NOTE: Do NOT onboard Azure Entra SSO in Keycloak during onboarding (skipAzureEntraSso=true).
|
|
109
|
+
# KEYCLOAK_SKIP_AZURE_ENTRA_SSO=false
|
|
111
110
|
|
|
112
111
|
KEYCLOAK_REALM=aifabrix
|
|
113
|
-
KEYCLOAK_SERVER_URL=kv://keycloak-server-
|
|
114
|
-
KEYCLOAK_INTERNAL_SERVER_URL=kv://keycloak-internal-server-
|
|
112
|
+
KEYCLOAK_SERVER_URL=kv://keycloak-server-url
|
|
113
|
+
KEYCLOAK_INTERNAL_SERVER_URL=kv://keycloak-internal-server-url
|
|
115
114
|
KEYCLOAK_CLIENT_ID=miso-controller
|
|
116
115
|
KEYCLOAK_CLIENT_SECRET=kv://keycloak-client-secretKeyVault
|
|
117
116
|
KEYCLOAK_ADMIN_USERNAME=admin
|
|
@@ -279,6 +278,9 @@ JWT_SECRET=kv://miso-controller-jwt-secretKeyVault
|
|
|
279
278
|
# When API_KEY is set, a matching Bearer token bypasses OAuth2 validation
|
|
280
279
|
API_KEY=kv://miso-controller-api-key-secretKeyVault
|
|
281
280
|
|
|
281
|
+
# NPM token for private package (npmjs.org)
|
|
282
|
+
NPM_TOKEN=kv://npm-token-secretKeyVault
|
|
283
|
+
|
|
282
284
|
# =============================================================================
|
|
283
285
|
# MISO CONTROLLER CONFIGURATION
|
|
284
286
|
# =============================================================================
|
|
@@ -287,8 +289,8 @@ API_KEY=kv://miso-controller-api-key-secretKeyVault
|
|
|
287
289
|
# Used to generate correct server URLs in OpenAPI spec and Keycloak callback URLs
|
|
288
290
|
# For Docker: use localhost with mapped port (e.g., localhost:3100)
|
|
289
291
|
# For production: use public domain (e.g., https://miso.example.com)
|
|
290
|
-
MISO_WEB_SERVER_URL=kv://miso-controller-web-server-
|
|
291
|
-
MISO_CONTROLLER_URL=kv://miso-controller-internal-server-
|
|
292
|
+
MISO_WEB_SERVER_URL=kv://miso-controller-web-server-url
|
|
293
|
+
MISO_CONTROLLER_URL=kv://miso-controller-internal-server-url
|
|
292
294
|
|
|
293
295
|
# MISO Environment Configuration (miso, dev, tst, pro)
|
|
294
296
|
MISO_ENVIRONMENT=miso
|
|
@@ -30,22 +30,7 @@
|
|
|
30
30
|
"toolPrefix": "{{systemKey}}"
|
|
31
31
|
}{{/if}},
|
|
32
32
|
"tags": [],
|
|
33
|
-
"configuration": [
|
|
34
|
-
{
|
|
35
|
-
"name": "BASE_URL",
|
|
36
|
-
"value": "{{#if baseUrl}}{{baseUrl}}{{else}}https://api.example.com{{/if}}",
|
|
37
|
-
"location": "variable",
|
|
38
|
-
"required": true,
|
|
39
|
-
"portalInput": {
|
|
40
|
-
"field": "text",
|
|
41
|
-
"label": "Base URL",
|
|
42
|
-
"placeholder": "https://api.example.com",
|
|
43
|
-
"validation": {
|
|
44
|
-
"required": true
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
]{{#if roles}},
|
|
33
|
+
"configuration": []{{#if roles}},
|
|
49
34
|
"roles": [
|
|
50
35
|
{{#each roles}}
|
|
51
36
|
{
|
|
@@ -25,23 +25,39 @@ services:
|
|
|
25
25
|
- "traefik.http.routers.{{app.key}}.middlewares={{app.key}}-stripprefix"
|
|
26
26
|
{{/unless}}
|
|
27
27
|
{{/if}}
|
|
28
|
+
environment:
|
|
29
|
+
- MISO_ENVIRONMENT={{misoEnvironment}}
|
|
30
|
+
{{#if reloadStartCommand}}
|
|
31
|
+
- PORT={{containerPort}}
|
|
32
|
+
{{/if}}
|
|
28
33
|
{{#if traefik.enabled}}
|
|
29
34
|
{{#unless (eq traefik.path "/")}}
|
|
30
|
-
environment:
|
|
31
35
|
- BASE_PATH={{traefik.path}}
|
|
32
36
|
- X_FORWARDED_PREFIX={{traefik.path}}
|
|
33
37
|
{{/unless}}
|
|
34
38
|
{{/if}}
|
|
35
39
|
env_file:
|
|
36
40
|
- {{envFile}}
|
|
41
|
+
{{#if reloadStartCommand}}
|
|
42
|
+
command: ["sh", "-c", "cd /app && {{reloadStartCommand}}"]
|
|
43
|
+
{{/if}}
|
|
37
44
|
ports:
|
|
38
45
|
- "{{hostPort}}:{{containerPort}}"
|
|
39
46
|
networks:
|
|
40
47
|
- {{networkName}}
|
|
48
|
+
{{#if devMountPath}}
|
|
49
|
+
volumes:
|
|
50
|
+
- {{devMountPath}}:/app
|
|
51
|
+
{{#if requiresStorage}}
|
|
52
|
+
- {{#if (eq devId 0)}}aifabrix_{{app.key}}_data{{else}}aifabrix_dev{{devId}}_{{app.key}}_data{{/if}}:/mnt/data
|
|
53
|
+
{{/if}}
|
|
54
|
+
user: "${AIFABRIX_UID:-1000}:${AIFABRIX_GID:-1000}"
|
|
55
|
+
{{else}}
|
|
41
56
|
{{#if requiresStorage}}
|
|
42
57
|
volumes:
|
|
43
58
|
- {{#if (eq devId 0)}}aifabrix_{{app.key}}_data{{else}}aifabrix_dev{{devId}}_{{app.key}}_data{{/if}}:/mnt/data
|
|
44
59
|
{{/if}}
|
|
60
|
+
{{/if}}
|
|
45
61
|
healthcheck:
|
|
46
62
|
test: ["CMD", "curl", "-f", "http://localhost:{{port}}{{healthCheck.path}}"]
|
|
47
63
|
interval: {{healthCheck.interval}}s
|
|
@@ -56,78 +72,88 @@ services:
|
|
|
56
72
|
{{/if}}
|
|
57
73
|
|
|
58
74
|
{{#if requiresDatabase}}
|
|
59
|
-
# Database Initialization
|
|
75
|
+
# Database Initialization (uses infra pgpass when available: ~/.aifabrix/infra/pgpass)
|
|
76
|
+
# env_file: .env.run.admin only (POSTGRES_PASSWORD + DB_*); admin secrets never in app container
|
|
60
77
|
db-init:
|
|
61
78
|
image: pgvector/pgvector:pg15
|
|
62
79
|
container_name: {{containerName}}-db-init
|
|
63
80
|
entrypoint: []
|
|
64
81
|
env_file:
|
|
65
|
-
-
|
|
66
|
-
- {{envFile}}
|
|
82
|
+
- {{#if dbInitEnvFile}}{{dbInitEnvFile}}{{else}}{{envFile}}{{/if}}
|
|
67
83
|
environment:
|
|
68
84
|
POSTGRES_DB: postgres
|
|
69
85
|
PGHOST: postgres
|
|
70
86
|
PGPORT: "5432"
|
|
71
87
|
PGUSER: pgadmin
|
|
72
|
-
{{#if
|
|
73
|
-
|
|
74
|
-
DB_{{@index}}_PASSWORD: {{lookup ../databasePasswords.array @index}}
|
|
75
|
-
{{/each}}
|
|
76
|
-
{{else}}
|
|
77
|
-
DB_PASSWORD: {{lookup databasePasswords.array 0}}
|
|
88
|
+
{{#if useInfraPgpass}}
|
|
89
|
+
PGPASSFILE: /run/pgpass
|
|
78
90
|
{{/if}}
|
|
79
91
|
networks:
|
|
80
92
|
- {{networkName}}
|
|
81
|
-
volumes:
|
|
93
|
+
volumes:
|
|
94
|
+
{{#if useInfraPgpass}}
|
|
95
|
+
- {{infraPgpassPath}}:/run/pgpass:ro
|
|
96
|
+
{{else}}
|
|
97
|
+
[]
|
|
98
|
+
{{/if}}
|
|
82
99
|
tmpfs:
|
|
83
100
|
- /var/lib/postgresql/data
|
|
84
101
|
command:
|
|
85
102
|
- sh
|
|
86
103
|
- -c
|
|
87
104
|
- |
|
|
88
|
-
|
|
89
|
-
export PGPASSWORD="
|
|
105
|
+
{{#unless useInfraPgpass}}
|
|
106
|
+
export PGPASSWORD="$${POSTGRES_PASSWORD}" &&
|
|
107
|
+
{{/unless}}
|
|
90
108
|
echo 'Waiting for PostgreSQL to be ready...' &&
|
|
91
109
|
counter=0 &&
|
|
92
|
-
while [
|
|
93
|
-
if pg_isready
|
|
110
|
+
while [ $${counter:-0} -lt 30 ]; do
|
|
111
|
+
if pg_isready >/dev/null 2>&1; then
|
|
94
112
|
echo 'PostgreSQL is ready!'
|
|
95
113
|
break
|
|
96
114
|
fi
|
|
97
115
|
echo 'Waiting for PostgreSQL...'
|
|
98
116
|
sleep 1
|
|
99
|
-
counter
|
|
117
|
+
counter=$$(($${counter:-0} + 1))
|
|
100
118
|
done &&
|
|
101
119
|
{{#if databases}}
|
|
102
120
|
{{#each databases}}
|
|
103
121
|
echo 'Creating {{name}} database and user...' &&
|
|
104
|
-
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{name}}'" 2>/dev/null | grep -q '^1
|
|
105
|
-
echo 'Database "{{name}}" already exists,
|
|
122
|
+
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{name}}'" 2>/dev/null | grep -q '^1$$'; then
|
|
123
|
+
echo 'Database "{{name}}" already exists, syncing user password...' &&
|
|
124
|
+
psql -d postgres -c "ALTER USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
|
|
125
|
+
echo 'Database "{{name}}" ok.'
|
|
106
126
|
else
|
|
107
127
|
echo 'Creating database "{{name}}"...' &&
|
|
108
128
|
psql -d postgres -c "CREATE DATABASE \"{{name}}\";" &&
|
|
109
129
|
echo 'Dropping old user if exists...' &&
|
|
110
130
|
psql -d postgres -c "DROP USER IF EXISTS \"{{pgUserOld name}}\";" || true &&
|
|
111
131
|
echo 'Creating user "{{pgUserName name}}"...' &&
|
|
112
|
-
psql -d postgres -c
|
|
132
|
+
psql -d postgres -c "CREATE USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
|
|
113
133
|
echo 'Granting privileges...' &&
|
|
114
134
|
psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"{{name}}\" TO \"{{pgUserName name}}\";" &&
|
|
115
135
|
psql -d {{name}} -c "ALTER SCHEMA public OWNER TO \"{{pgUserName name}}\";" &&
|
|
116
136
|
psql -d {{name}} -c "GRANT ALL ON SCHEMA public TO \"{{pgUserName name}}\";" &&
|
|
117
137
|
echo 'Database "{{name}}" created successfully!'
|
|
118
138
|
fi &&
|
|
139
|
+
{{#if (isVectorDatabase name)}}
|
|
140
|
+
psql -d {{name}} -c "CREATE EXTENSION IF NOT EXISTS vector;" &&
|
|
141
|
+
echo 'pgvector extension enabled on "{{name}}".' &&
|
|
142
|
+
{{/if}}
|
|
119
143
|
{{/each}}
|
|
120
144
|
{{else}}
|
|
121
145
|
echo 'Creating {{app.key}} database and user...' &&
|
|
122
|
-
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{app.key}}'" 2>/dev/null | grep -q '^1
|
|
123
|
-
echo 'Database "{{app.key}}" already exists,
|
|
146
|
+
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{app.key}}'" 2>/dev/null | grep -q '^1$$'; then
|
|
147
|
+
echo 'Database "{{app.key}}" already exists, syncing user password...' &&
|
|
148
|
+
psql -d postgres -c "ALTER USER \"{{pgUserName app.key}}\" WITH PASSWORD '"$${DB_0_PASSWORD:-$$DB_PASSWORD}"';" &&
|
|
149
|
+
echo 'Database "{{app.key}}" ok.'
|
|
124
150
|
else
|
|
125
151
|
echo 'Creating database "{{app.key}}"...' &&
|
|
126
152
|
psql -d postgres -c "CREATE DATABASE \"{{app.key}}\";" &&
|
|
127
153
|
echo 'Dropping old user if exists...' &&
|
|
128
154
|
psql -d postgres -c "DROP USER IF EXISTS \"{{pgUserOld app.key}}\";" || true &&
|
|
129
155
|
echo 'Creating user "{{pgUserName app.key}}"...' &&
|
|
130
|
-
psql -d postgres -c
|
|
156
|
+
psql -d postgres -c "CREATE USER \"{{pgUserName app.key}}\" WITH PASSWORD '"$${DB_0_PASSWORD:-$$DB_PASSWORD}"';" &&
|
|
131
157
|
echo 'Granting privileges...' &&
|
|
132
158
|
psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"{{app.key}}\" TO \"{{pgUserName app.key}}\";" &&
|
|
133
159
|
psql -d {{app.key}} -c "ALTER SCHEMA public OWNER TO \"{{pgUserName app.key}}\";" &&
|
|
@@ -154,4 +180,4 @@ volumes:
|
|
|
154
180
|
|
|
155
181
|
networks:
|
|
156
182
|
{{networkName}}:
|
|
157
|
-
external: true
|
|
183
|
+
external: true
|
|
@@ -25,23 +25,39 @@ services:
|
|
|
25
25
|
- "traefik.http.routers.{{app.key}}.middlewares={{app.key}}-stripprefix"
|
|
26
26
|
{{/unless}}
|
|
27
27
|
{{/if}}
|
|
28
|
+
environment:
|
|
29
|
+
- MISO_ENVIRONMENT={{misoEnvironment}}
|
|
30
|
+
{{#if reloadStartCommand}}
|
|
31
|
+
- PORT={{containerPort}}
|
|
32
|
+
{{/if}}
|
|
28
33
|
{{#if traefik.enabled}}
|
|
29
34
|
{{#unless (eq traefik.path "/")}}
|
|
30
|
-
environment:
|
|
31
35
|
- BASE_PATH={{traefik.path}}
|
|
32
36
|
- X_FORWARDED_PREFIX={{traefik.path}}
|
|
33
37
|
{{/unless}}
|
|
34
38
|
{{/if}}
|
|
35
39
|
env_file:
|
|
36
40
|
- {{envFile}}
|
|
41
|
+
{{#if reloadStartCommand}}
|
|
42
|
+
command: ["sh", "-c", "cd /app && {{reloadStartCommand}}"]
|
|
43
|
+
{{/if}}
|
|
37
44
|
ports:
|
|
38
45
|
- "{{hostPort}}:{{containerPort}}"
|
|
39
46
|
networks:
|
|
40
47
|
- {{networkName}}
|
|
48
|
+
{{#if devMountPath}}
|
|
49
|
+
volumes:
|
|
50
|
+
- {{devMountPath}}:/app
|
|
51
|
+
{{#if requiresStorage}}
|
|
52
|
+
- {{#if (eq devId 0)}}aifabrix_{{app.key}}_data{{else}}aifabrix_dev{{devId}}_{{app.key}}_data{{/if}}:/mnt/data
|
|
53
|
+
{{/if}}
|
|
54
|
+
user: "${AIFABRIX_UID:-1000}:${AIFABRIX_GID:-1000}"
|
|
55
|
+
{{else}}
|
|
41
56
|
{{#if requiresStorage}}
|
|
42
57
|
volumes:
|
|
43
58
|
- {{#if (eq devId 0)}}aifabrix_{{app.key}}_data{{else}}aifabrix_dev{{devId}}_{{app.key}}_data{{/if}}:/mnt/data
|
|
44
59
|
{{/if}}
|
|
60
|
+
{{/if}}
|
|
45
61
|
healthcheck:
|
|
46
62
|
test: ["CMD", "curl", "-f", "http://localhost:{{port}}{{healthCheck.path}}"]
|
|
47
63
|
interval: {{healthCheck.interval}}s
|
|
@@ -56,78 +72,88 @@ services:
|
|
|
56
72
|
{{/if}}
|
|
57
73
|
|
|
58
74
|
{{#if requiresDatabase}}
|
|
59
|
-
# Database Initialization
|
|
75
|
+
# Database Initialization (uses infra pgpass when available: ~/.aifabrix/infra/pgpass)
|
|
76
|
+
# env_file: .env.run.admin only (POSTGRES_PASSWORD + DB_*); admin secrets never in app container
|
|
60
77
|
db-init:
|
|
61
78
|
image: pgvector/pgvector:pg15
|
|
62
79
|
container_name: {{containerName}}-db-init
|
|
63
80
|
entrypoint: []
|
|
64
81
|
env_file:
|
|
65
|
-
-
|
|
66
|
-
- {{envFile}}
|
|
82
|
+
- {{#if dbInitEnvFile}}{{dbInitEnvFile}}{{else}}{{envFile}}{{/if}}
|
|
67
83
|
environment:
|
|
68
84
|
POSTGRES_DB: postgres
|
|
69
85
|
PGHOST: postgres
|
|
70
86
|
PGPORT: "5432"
|
|
71
87
|
PGUSER: pgadmin
|
|
72
|
-
{{#if
|
|
73
|
-
|
|
74
|
-
DB_{{@index}}_PASSWORD: {{lookup ../databasePasswords.array @index}}
|
|
75
|
-
{{/each}}
|
|
76
|
-
{{else}}
|
|
77
|
-
DB_PASSWORD: {{lookup databasePasswords.array 0}}
|
|
88
|
+
{{#if useInfraPgpass}}
|
|
89
|
+
PGPASSFILE: /run/pgpass
|
|
78
90
|
{{/if}}
|
|
79
91
|
networks:
|
|
80
92
|
- {{networkName}}
|
|
81
|
-
volumes:
|
|
93
|
+
volumes:
|
|
94
|
+
{{#if useInfraPgpass}}
|
|
95
|
+
- {{infraPgpassPath}}:/run/pgpass:ro
|
|
96
|
+
{{else}}
|
|
97
|
+
[]
|
|
98
|
+
{{/if}}
|
|
82
99
|
tmpfs:
|
|
83
100
|
- /var/lib/postgresql/data
|
|
84
101
|
command:
|
|
85
102
|
- sh
|
|
86
103
|
- -c
|
|
87
104
|
- |
|
|
88
|
-
|
|
89
|
-
export PGPASSWORD="
|
|
105
|
+
{{#unless useInfraPgpass}}
|
|
106
|
+
export PGPASSWORD="$${POSTGRES_PASSWORD}" &&
|
|
107
|
+
{{/unless}}
|
|
90
108
|
echo 'Waiting for PostgreSQL to be ready...' &&
|
|
91
109
|
counter=0 &&
|
|
92
|
-
while [
|
|
93
|
-
if pg_isready
|
|
110
|
+
while [ $${counter:-0} -lt 30 ]; do
|
|
111
|
+
if pg_isready >/dev/null 2>&1; then
|
|
94
112
|
echo 'PostgreSQL is ready!'
|
|
95
113
|
break
|
|
96
114
|
fi
|
|
97
115
|
echo 'Waiting for PostgreSQL...'
|
|
98
116
|
sleep 1
|
|
99
|
-
counter
|
|
117
|
+
counter=$$(($${counter:-0} + 1))
|
|
100
118
|
done &&
|
|
101
119
|
{{#if databases}}
|
|
102
120
|
{{#each databases}}
|
|
103
121
|
echo 'Creating {{name}} database and user...' &&
|
|
104
|
-
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{name}}'" 2>/dev/null | grep -q '^1
|
|
105
|
-
echo 'Database "{{name}}" already exists,
|
|
122
|
+
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{name}}'" 2>/dev/null | grep -q '^1$$'; then
|
|
123
|
+
echo 'Database "{{name}}" already exists, syncing user password...' &&
|
|
124
|
+
psql -d postgres -c "ALTER USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
|
|
125
|
+
echo 'Database "{{name}}" ok.'
|
|
106
126
|
else
|
|
107
127
|
echo 'Creating database "{{name}}"...' &&
|
|
108
128
|
psql -d postgres -c "CREATE DATABASE \"{{name}}\";" &&
|
|
109
129
|
echo 'Dropping old user if exists...' &&
|
|
110
130
|
psql -d postgres -c "DROP USER IF EXISTS \"{{pgUserOld name}}\";" || true &&
|
|
111
131
|
echo 'Creating user "{{pgUserName name}}"...' &&
|
|
112
|
-
psql -d postgres -c
|
|
132
|
+
psql -d postgres -c "CREATE USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
|
|
113
133
|
echo 'Granting privileges...' &&
|
|
114
134
|
psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"{{name}}\" TO \"{{pgUserName name}}\";" &&
|
|
115
135
|
psql -d {{name}} -c "ALTER SCHEMA public OWNER TO \"{{pgUserName name}}\";" &&
|
|
116
136
|
psql -d {{name}} -c "GRANT ALL ON SCHEMA public TO \"{{pgUserName name}}\";" &&
|
|
117
137
|
echo 'Database "{{name}}" created successfully!'
|
|
118
138
|
fi &&
|
|
139
|
+
{{#if (isVectorDatabase name)}}
|
|
140
|
+
psql -d {{name}} -c "CREATE EXTENSION IF NOT EXISTS vector;" &&
|
|
141
|
+
echo 'pgvector extension enabled on "{{name}}".' &&
|
|
142
|
+
{{/if}}
|
|
119
143
|
{{/each}}
|
|
120
144
|
{{else}}
|
|
121
145
|
echo 'Creating {{app.key}} database and user...' &&
|
|
122
|
-
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{app.key}}'" 2>/dev/null | grep -q '^1
|
|
123
|
-
echo 'Database "{{app.key}}" already exists,
|
|
146
|
+
if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{app.key}}'" 2>/dev/null | grep -q '^1$$'; then
|
|
147
|
+
echo 'Database "{{app.key}}" already exists, syncing user password...' &&
|
|
148
|
+
psql -d postgres -c "ALTER USER \"{{pgUserName app.key}}\" WITH PASSWORD '"$${DB_0_PASSWORD:-$$DB_PASSWORD}"';" &&
|
|
149
|
+
echo 'Database "{{app.key}}" ok.'
|
|
124
150
|
else
|
|
125
151
|
echo 'Creating database "{{app.key}}"...' &&
|
|
126
152
|
psql -d postgres -c "CREATE DATABASE \"{{app.key}}\";" &&
|
|
127
153
|
echo 'Dropping old user if exists...' &&
|
|
128
154
|
psql -d postgres -c "DROP USER IF EXISTS \"{{pgUserOld app.key}}\";" || true &&
|
|
129
155
|
echo 'Creating user "{{pgUserName app.key}}"...' &&
|
|
130
|
-
psql -d postgres -c
|
|
156
|
+
psql -d postgres -c "CREATE USER \"{{pgUserName app.key}}\" WITH PASSWORD '"$${DB_0_PASSWORD:-$$DB_PASSWORD}"';" &&
|
|
131
157
|
echo 'Granting privileges...' &&
|
|
132
158
|
psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"{{app.key}}\" TO \"{{pgUserName app.key}}\";" &&
|
|
133
159
|
psql -d {{app.key}} -c "ALTER SCHEMA public OWNER TO \"{{pgUserName app.key}}\";" &&
|