@aifabrix/builder 2.40.2 → 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.
Files changed (103) hide show
  1. package/README.md +6 -4
  2. package/integration/hubspot/test.js +1 -1
  3. package/lib/api/credential.api.js +40 -0
  4. package/lib/api/dev.api.js +423 -0
  5. package/lib/api/types/credential.types.js +23 -0
  6. package/lib/api/types/dev.types.js +140 -0
  7. package/lib/app/config.js +21 -0
  8. package/lib/app/down.js +2 -1
  9. package/lib/app/index.js +9 -0
  10. package/lib/app/push.js +36 -12
  11. package/lib/app/readme.js +1 -3
  12. package/lib/app/run-env-compose.js +201 -0
  13. package/lib/app/run-helpers.js +121 -118
  14. package/lib/app/run.js +148 -28
  15. package/lib/app/show.js +5 -2
  16. package/lib/build/index.js +11 -3
  17. package/lib/cli/setup-app.js +140 -14
  18. package/lib/cli/setup-dev.js +180 -17
  19. package/lib/cli/setup-environment.js +4 -2
  20. package/lib/cli/setup-external-system.js +71 -21
  21. package/lib/cli/setup-infra.js +29 -2
  22. package/lib/cli/setup-secrets.js +52 -5
  23. package/lib/cli/setup-utility.js +12 -3
  24. package/lib/commands/app-install.js +172 -0
  25. package/lib/commands/app-shell.js +75 -0
  26. package/lib/commands/app-test.js +282 -0
  27. package/lib/commands/app.js +1 -1
  28. package/lib/commands/dev-cli-handlers.js +141 -0
  29. package/lib/commands/dev-down.js +114 -0
  30. package/lib/commands/dev-init.js +309 -0
  31. package/lib/commands/secrets-list.js +118 -0
  32. package/lib/commands/secrets-remove.js +97 -0
  33. package/lib/commands/secrets-set.js +30 -17
  34. package/lib/commands/secrets-validate.js +50 -0
  35. package/lib/commands/up-dataplane.js +2 -2
  36. package/lib/commands/up-miso.js +0 -25
  37. package/lib/commands/upload.js +26 -1
  38. package/lib/core/admin-secrets.js +96 -0
  39. package/lib/core/secrets-ensure.js +378 -0
  40. package/lib/core/secrets-env-write.js +157 -0
  41. package/lib/core/secrets.js +147 -81
  42. package/lib/datasource/field-reference-validator.js +91 -0
  43. package/lib/datasource/validate.js +21 -3
  44. package/lib/deployment/environment-config.js +137 -0
  45. package/lib/deployment/environment.js +21 -98
  46. package/lib/deployment/push.js +32 -2
  47. package/lib/external-system/download.js +7 -0
  48. package/lib/external-system/test-auth.js +7 -3
  49. package/lib/external-system/test.js +5 -1
  50. package/lib/generator/index.js +174 -25
  51. package/lib/generator/wizard.js +8 -0
  52. package/lib/infrastructure/helpers.js +103 -20
  53. package/lib/infrastructure/index.js +88 -10
  54. package/lib/infrastructure/services.js +70 -15
  55. package/lib/schema/application-schema.json +24 -3
  56. package/lib/schema/external-system.schema.json +435 -413
  57. package/lib/utils/api.js +3 -3
  58. package/lib/utils/app-register-auth.js +25 -3
  59. package/lib/utils/cli-utils.js +20 -0
  60. package/lib/utils/compose-generator.js +76 -75
  61. package/lib/utils/compose-handlebars-helpers.js +43 -0
  62. package/lib/utils/compose-vector-helper.js +18 -0
  63. package/lib/utils/config-paths.js +127 -2
  64. package/lib/utils/credential-secrets-env.js +267 -0
  65. package/lib/utils/dev-cert-helper.js +122 -0
  66. package/lib/utils/device-code-helpers.js +224 -0
  67. package/lib/utils/device-code.js +37 -336
  68. package/lib/utils/docker-build.js +40 -8
  69. package/lib/utils/env-copy.js +83 -13
  70. package/lib/utils/env-map.js +35 -5
  71. package/lib/utils/env-template.js +6 -5
  72. package/lib/utils/error-formatters/http-status-errors.js +20 -1
  73. package/lib/utils/help-builder.js +15 -2
  74. package/lib/utils/infra-status.js +30 -1
  75. package/lib/utils/local-secrets.js +7 -52
  76. package/lib/utils/mutagen-install.js +195 -0
  77. package/lib/utils/mutagen.js +146 -0
  78. package/lib/utils/paths.js +43 -33
  79. package/lib/utils/port-resolver.js +28 -16
  80. package/lib/utils/remote-dev-auth.js +38 -0
  81. package/lib/utils/remote-docker-env.js +43 -0
  82. package/lib/utils/remote-secrets-loader.js +60 -0
  83. package/lib/utils/secrets-generator.js +94 -6
  84. package/lib/utils/secrets-helpers.js +33 -25
  85. package/lib/utils/secrets-path.js +2 -2
  86. package/lib/utils/secrets-utils.js +52 -1
  87. package/lib/utils/secrets-validation.js +84 -0
  88. package/lib/utils/ssh-key-helper.js +116 -0
  89. package/lib/utils/token-manager-messages.js +90 -0
  90. package/lib/utils/token-manager.js +5 -4
  91. package/lib/utils/variable-transformer.js +3 -3
  92. package/lib/validation/validator.js +65 -0
  93. package/package.json +2 -2
  94. package/scripts/install-local.js +34 -15
  95. package/templates/README.md +0 -1
  96. package/templates/applications/README.md.hbs +4 -4
  97. package/templates/applications/dataplane/application.yaml +5 -4
  98. package/templates/applications/dataplane/env.template +12 -7
  99. package/templates/applications/keycloak/env.template +2 -0
  100. package/templates/applications/miso-controller/application.yaml +1 -0
  101. package/templates/applications/miso-controller/env.template +11 -9
  102. package/templates/python/docker-compose.hbs +49 -23
  103. package/templates/typescript/docker-compose.hbs +48 -22
@@ -7,7 +7,7 @@
7
7
  # =============================================================================
8
8
 
9
9
  # HTTP port for the app
10
- PORT=3001
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-urlKeyVault
34
- DATAPLANE_INTERNAL_URL=kv://dataplane-internal-server-urlKeyVault
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-urlKeyVault
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-urlKeyVault
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-urlKeyVault
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=http://${MISO_HOST}:${MISO_PORT}
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=${NODE_ENV}
53
- PORT=${MISO_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
- # Azure Entra SSO during onboarding: true = skip (default), false = onboard Azure Entra SSO client in Keycloak
109
- # (onboarding Azure SSO requires Entra admin consent and Azure app credentials).
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-urlKeyVault
114
- KEYCLOAK_INTERNAL_SERVER_URL=kv://keycloak-internal-server-urlKeyVault
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-urlKeyVault
291
- MISO_CONTROLLER_URL=kv://miso-controller-internal-server-urlKeyVault
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
@@ -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
- - ${ADMIN_SECRETS_PATH}
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 databases}}
73
- {{#each databases}}
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
- export PGHOST=postgres PGPORT=5432 PGUSER=pgadmin &&
89
- export PGPASSWORD="${POSTGRES_PASSWORD}" &&
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 [ ${counter:-0} -lt 30 ]; do
93
- if pg_isready -h postgres -p 5432 -U pgadmin >/dev/null 2>&1; then
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=$((${counter:-0} + 1))
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$'; then
105
- echo 'Database "{{name}}" already exists, all ok.'
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 'CREATE USER "{{pgUserName name}}" WITH PASSWORD '\''${DB_{{@index}}_PASSWORD}'\'';' &&
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$'; then
123
- echo 'Database "{{app.key}}" already exists, all ok.'
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 'CREATE USER "{{pgUserName app.key}}" WITH PASSWORD '\''${DB_0_PASSWORD:-${DB_PASSWORD}}'\'';' &&
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
- - ${ADMIN_SECRETS_PATH}
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 databases}}
73
- {{#each databases}}
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
- export PGHOST=postgres PGPORT=5432 PGUSER=pgadmin &&
89
- export PGPASSWORD="${POSTGRES_PASSWORD}" &&
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 [ ${counter:-0} -lt 30 ]; do
93
- if pg_isready -h postgres -p 5432 -U pgadmin >/dev/null 2>&1; then
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=$((${counter:-0} + 1))
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$'; then
105
- echo 'Database "{{name}}" already exists, all ok.'
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 'CREATE USER "{{pgUserName name}}" WITH PASSWORD '\''${DB_{{@index}}_PASSWORD}'\'';' &&
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$'; then
123
- echo 'Database "{{app.key}}" already exists, all ok.'
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 'CREATE USER "{{pgUserName app.key}}" WITH PASSWORD '\''${DB_0_PASSWORD:-${DB_PASSWORD}}'\'';' &&
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}}\";" &&