@aifabrix/builder 2.61.2 → 2.63.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 (90) hide show
  1. package/lib/api/applications.api.js +22 -2
  2. package/lib/api/bootstrap-snapshot.api.js +115 -0
  3. package/lib/api/onboarding-status.api.js +117 -0
  4. package/lib/app/deploy.js +14 -5
  5. package/lib/app/register.js +24 -2
  6. package/lib/app/run-env-compose.js +44 -8
  7. package/lib/app/run-env-recovery.js +1 -0
  8. package/lib/app/run-helpers.js +1 -1
  9. package/lib/app/run.js +6 -4
  10. package/lib/build/standard-docker-build.js +4 -0
  11. package/lib/channels/channel-artifact-generator.js +13 -3
  12. package/lib/cli/infra-guided-footers.js +10 -8
  13. package/lib/cli/infra-guided.js +60 -12
  14. package/lib/cli/setup-infra-up-platform-action.js +14 -1
  15. package/lib/cli/setup-platform.js +20 -3
  16. package/lib/commands/auth-config.js +2 -0
  17. package/lib/commands/login.js +4 -0
  18. package/lib/commands/repair-datasource-apply.js +3 -1
  19. package/lib/commands/repair-datasource-legacy.js +94 -0
  20. package/lib/commands/setup-image-refresh.js +26 -0
  21. package/lib/commands/setup-modes.js +9 -2
  22. package/lib/commands/setup-onboarding-readiness.js +83 -0
  23. package/lib/commands/setup-prompts-platform-mode.js +34 -0
  24. package/lib/commands/setup.js +35 -10
  25. package/lib/commands/up-builder-api.js +24 -8
  26. package/lib/commands/up-common.js +16 -1
  27. package/lib/commands/up-dataplane-bootstrap.js +149 -16
  28. package/lib/commands/up-dataplane-credentials.js +21 -0
  29. package/lib/commands/up-dataplane.js +26 -34
  30. package/lib/commands/up-integration-server.js +112 -0
  31. package/lib/commands/wizard-config-normalizer.js +5 -1
  32. package/lib/core/admin-secrets-env-overlay.js +8 -3
  33. package/lib/core/environment-access-policy.js +121 -0
  34. package/lib/core/environment-mode-policy.js +177 -0
  35. package/lib/core/local-env-overrides.js +149 -0
  36. package/lib/core/secrets-ensure.js +4 -2
  37. package/lib/core/secrets-env-content.js +12 -9
  38. package/lib/core/secrets-env-write.js +1 -1
  39. package/lib/datasource/capability/capability-manifest.js +1 -0
  40. package/lib/deployment/installation/index.js +14 -1
  41. package/lib/deployment/installation/infra-catalog.js +3 -0
  42. package/lib/deployment/installation/local-environment-stage.js +285 -0
  43. package/lib/deployment/installation/local-installation.js +76 -0
  44. package/lib/deployment/installation/stage-input.js +5 -1
  45. package/lib/generator/builders.js +3 -1
  46. package/lib/generator/index.js +32 -9
  47. package/lib/generator/split-variables.js +2 -2
  48. package/lib/parameters/database-adoption.js +125 -0
  49. package/lib/parameters/physical-database-naming.js +136 -0
  50. package/lib/parameters/physical-secret-name.js +194 -0
  51. package/lib/parameters/rsa-secret-values.js +165 -0
  52. package/lib/programmatic/run-channel-install-artifacts.js +28 -2
  53. package/lib/programmatic/run-channel-package.js +3 -1
  54. package/lib/programmatic/workspace-context.js +37 -2
  55. package/lib/schema/infra.parameter.yaml +61 -27
  56. package/lib/schema/infrastructure-schema.json +213 -120
  57. package/lib/utils/compose-generate-docker-compose.js +2 -2
  58. package/lib/utils/compose-generator.js +4 -7
  59. package/lib/utils/compose-miso-env.js +2 -2
  60. package/lib/utils/compose-traefik-ingress-base.js +3 -4
  61. package/lib/utils/dataplane-dimension-abac-setting.js +120 -0
  62. package/lib/utils/declarative-url-ports.js +3 -0
  63. package/lib/utils/env-environment-file-paths.js +105 -0
  64. package/lib/utils/environment-scoped-resources.js +48 -14
  65. package/lib/utils/log-redaction.js +4 -1
  66. package/lib/utils/paths-system-builder-keys.js +7 -1
  67. package/lib/utils/paths.js +7 -2
  68. package/lib/utils/postgres-platform-bootstrap.js +35 -1
  69. package/lib/utils/redis-env-scope.js +21 -1
  70. package/lib/utils/registry-auth-sources.js +154 -0
  71. package/lib/utils/registry-credentials.js +131 -14
  72. package/lib/utils/secrets-generator.js +30 -21
  73. package/lib/utils/secrets-helpers.js +5 -7
  74. package/lib/utils/secrets-kv-scope.js +127 -28
  75. package/lib/utils/secrets-materialize-local.js +9 -0
  76. package/lib/utils/secrets-missing-error.js +35 -1
  77. package/lib/utils/token-manager.js +14 -8
  78. package/lib/utils/url-public-path-prefix.js +6 -10
  79. package/package.json +4 -2
  80. package/templates/README.md +6 -0
  81. package/templates/applications/builder-api/application.yaml +1 -1
  82. package/templates/applications/dataplane/application.yaml +2 -2
  83. package/templates/applications/dataplane/env.template +1 -1
  84. package/templates/applications/integration-server/application.yaml +91 -0
  85. package/templates/applications/integration-server/env.template +215 -0
  86. package/templates/applications/mirrored-templates.json +52 -0
  87. package/templates/applications/miso-controller/application.yaml +43 -1
  88. package/templates/applications/miso-controller/env.template +45 -39
  89. package/templates/marketplace/createUiDefinition.json +52 -4
  90. package/templates/marketplace/main.json +85 -7
@@ -5,7 +5,7 @@
5
5
  "_generator": {
6
6
  "name": "bicep",
7
7
  "version": "0.47.16.16243",
8
- "templateHash": "8811550299172477333"
8
+ "templateHash": "703508813427294425"
9
9
  }
10
10
  },
11
11
  "parameters": {
@@ -165,6 +165,13 @@
165
165
  "description": "Mori licence issuer public key in SPKI PEM form. Empty leaves the installation unpinned, and Miso then refuses a licence rather than trusting a key carried inside it."
166
166
  }
167
167
  },
168
+ "moriPolicyPublicKey": {
169
+ "type": "string",
170
+ "defaultValue": "",
171
+ "metadata": {
172
+ "description": "Mori policy signing anchor public key in SPKI PEM form. A different pair from the licence key. Empty leaves the policy bundle without an independent anchor, so it can only be checked against the key it carries."
173
+ }
174
+ },
168
175
  "moriLicenseIssuer": {
169
176
  "type": "string",
170
177
  "defaultValue": "mori-controller",
@@ -214,6 +221,21 @@
214
221
  "description": "License the installation requests from Mori during tenant activation: an edition name (COMMUNITY, STANDARD, ENTERPRISE) or an Azure Marketplace subscription ID (UUID). Plain string — Miso validates it. Emitted as LICENSE_EDITION."
215
222
  }
216
223
  },
224
+ "adminEmail": {
225
+ "type": "string",
226
+ "minLength": 3,
227
+ "metadata": {
228
+ "description": "Email of the initial platform administrator, used for the installation welcome."
229
+ }
230
+ },
231
+ "installationResourceModel": {
232
+ "type": "string",
233
+ "defaultValue": "shared",
234
+ "allowedValues": ["shared", "dedicated"],
235
+ "metadata": {
236
+ "description": "Initial installation topology, protected by Azure application configuration: shared for CE/SE; dedicated for EE DEV. Does not grant later licence entitlements."
237
+ }
238
+ },
217
239
  "onboardingMode": {
218
240
  "type": "string",
219
241
  "defaultValue": "customerOwned",
@@ -2216,7 +2238,7 @@
2216
2238
  "_generator": {
2217
2239
  "name": "bicep",
2218
2240
  "version": "0.47.16.16243",
2219
- "templateHash": "10929433789276981779"
2241
+ "templateHash": "6426728474798954933"
2220
2242
  }
2221
2243
  },
2222
2244
  "parameters": {
@@ -2409,7 +2431,7 @@
2409
2431
  "appCommandLine": "start --optimized=false",
2410
2432
  "healthCheckPath": "[variables('keycloakHealthCheckPath')]",
2411
2433
  "alwaysOn": true,
2412
- "appSettings": "[concat(createArray(createObject('name', 'WEBSITES_ENABLE_APP_SERVICE_STORAGE', 'value', 'false'), createObject('name', 'WEBSITES_PORT', 'value', '8080'), createObject('name', 'KEYCLOAK_ADMIN', 'value', parameters('keycloakAdminUser')), createObject('name', 'KEYCLOAK_ADMIN_PASSWORD', 'value', format('@Microsoft.KeyVault(SecretUri={0})', reference(resourceId('Microsoft.KeyVault/vaults/secrets', last(split(parameters('keyVaultId'), '/')), format('{0}-keycloak-admin-password', parameters('prefix'))), '2023-07-01').secretUriWithVersion)), createObject('name', 'KC_DB', 'value', 'postgres'), createObject('name', 'KC_DB_URL_HOST', 'value', parameters('postgresServerFqdn')), createObject('name', 'KC_DB_URL_DATABASE', 'value', parameters('postgresDatabaseName')), createObject('name', 'KC_DB_URL_PORT', 'value', '5432'), createObject('name', 'KC_DB_URL', 'value', format('jdbc:postgresql://{0}:5432/{1}', parameters('postgresServerFqdn'), parameters('postgresDatabaseName'))), createObject('name', 'KC_DB_USERNAME', 'value', parameters('postgresAdminLogin')), createObject('name', 'KC_DB_PASSWORD', 'value', format('@Microsoft.KeyVault(SecretUri={0})', reference(resourceId('Microsoft.KeyVault/vaults/secrets', last(split(parameters('keyVaultId'), '/')), format('{0}-postgres-admin-password', parameters('prefix'))), '2023-07-01').secretUriWithVersion)), createObject('name', 'KC_HOSTNAME', 'value', format('{0}.azurewebsites.net', parameters('name'))), createObject('name', 'KC_HOSTNAME_URL', 'value', format('https://{0}.azurewebsites.net', parameters('name'))), createObject('name', 'KC_HOSTNAME_ADMIN_URL', 'value', format('https://{0}.azurewebsites.net', parameters('name'))), createObject('name', 'KC_HOSTNAME_STRICT', 'value', 'false'), createObject('name', 'KC_HOSTNAME_STRICT_BACKEND', 'value', 'false'), createObject('name', 'KC_HOSTNAME_STRICT_HTTPS', 'value', 'false'), createObject('name', 'KC_HTTP_ENABLED', 'value', 'true'), createObject('name', 'KC_HTTP_RELATIVE_PATH', 'value', variables('keycloakHttpRelativePath')), createObject('name', 'KC_HTTP_MANAGEMENT_ENABLED', 'value', 'true'), createObject('name', 'KC_HTTP_MANAGEMENT_PORT', 'value', '9000'), createObject('name', 'KC_HTTP_MANAGEMENT_HEALTH_ENABLED', 'value', 'false'), createObject('name', 'KC_PROXY', 'value', 'edge'), createObject('name', 'KC_PROXY_HEADERS', 'value', 'xforwarded'), createObject('name', 'KC_PROXY_HEADERS_FORWARDED', 'value', 'true'), createObject('name', 'KC_HEALTH_ENABLED', 'value', 'true'), createObject('name', 'KC_CACHE', 'value', 'local'), createObject('name', 'KC_FEATURES', 'value', 'preview,cimd'), createObject('name', 'KC_SPI_EMAIL_SENDER__PROVIDER', 'value', 'mori'), createObject('name', 'KC_METRICS_ENABLED', 'value', 'true'), createObject('name', 'WEBSITE_VNET_ROUTE_ALL', 'value', if(parameters('enablePostgresPublicAccess'), '0', '1')), createObject('name', 'WEBSITE_DNS_SERVER', 'value', '168.63.129.16'), createObject('name', 'WEBSITES_CONTAINER_START_TIME_LIMIT', 'value', '1800'), createObject('name', 'KC_LOG', 'value', 'console'), createObject('name', 'KC_LOG_LEVEL', 'value', 'INFO')), variables('appInsightsAppSettings'), variables('acrRegistryUrlAppSettings'), variables('acrRegistryCredentialAppSettings'))]",
2434
+ "appSettings": "[concat(createArray(createObject('name', 'WEBSITES_ENABLE_APP_SERVICE_STORAGE', 'value', 'false'), createObject('name', 'WEBSITES_PORT', 'value', '8080'), createObject('name', 'KEYCLOAK_ADMIN', 'value', parameters('keycloakAdminUser')), createObject('name', 'KEYCLOAK_ADMIN_PASSWORD', 'value', format('@Microsoft.KeyVault(SecretUri={0})', reference(resourceId('Microsoft.KeyVault/vaults/secrets', last(split(parameters('keyVaultId'), '/')), format('{0}-keycloak-admin-password', parameters('prefix'))), '2023-07-01').secretUriWithVersion)), createObject('name', 'KC_DB', 'value', 'postgres'), createObject('name', 'KC_DB_URL_HOST', 'value', parameters('postgresServerFqdn')), createObject('name', 'KC_DB_URL_DATABASE', 'value', parameters('postgresDatabaseName')), createObject('name', 'KC_DB_URL_PORT', 'value', '5432'), createObject('name', 'KC_DB_URL', 'value', format('jdbc:postgresql://{0}:5432/{1}', parameters('postgresServerFqdn'), parameters('postgresDatabaseName'))), createObject('name', 'KC_DB_USERNAME', 'value', parameters('postgresAdminLogin')), createObject('name', 'KC_DB_PASSWORD', 'value', format('@Microsoft.KeyVault(SecretUri={0})', reference(resourceId('Microsoft.KeyVault/vaults/secrets', last(split(parameters('keyVaultId'), '/')), format('{0}-postgres-admin-password', parameters('prefix'))), '2023-07-01').secretUriWithVersion)), createObject('name', 'KC_HOSTNAME_STRICT', 'value', 'false'), createObject('name', 'KC_HOSTNAME_BACKCHANNEL_DYNAMIC', 'value', 'false'), createObject('name', 'KC_HOSTNAME_STRICT_BACKEND', 'value', 'false'), createObject('name', 'KC_HOSTNAME_STRICT_HTTPS', 'value', 'false'), createObject('name', 'KC_HTTP_ENABLED', 'value', 'true'), createObject('name', 'KC_HTTP_RELATIVE_PATH', 'value', variables('keycloakHttpRelativePath')), createObject('name', 'KC_HTTP_MANAGEMENT_ENABLED', 'value', 'true'), createObject('name', 'KC_HTTP_MANAGEMENT_PORT', 'value', '9000'), createObject('name', 'KC_HTTP_MANAGEMENT_HEALTH_ENABLED', 'value', 'false'), createObject('name', 'KC_PROXY', 'value', 'edge'), createObject('name', 'KC_PROXY_HEADERS', 'value', 'xforwarded'), createObject('name', 'KC_PROXY_HEADERS_FORWARDED', 'value', 'true'), createObject('name', 'KC_HEALTH_ENABLED', 'value', 'true'), createObject('name', 'KC_CACHE', 'value', 'local'), createObject('name', 'KC_FEATURES', 'value', 'preview,cimd'), createObject('name', 'KC_SPI_EMAIL_SENDER__PROVIDER', 'value', 'mori'), createObject('name', 'KC_METRICS_ENABLED', 'value', 'true'), createObject('name', 'WEBSITE_VNET_ROUTE_ALL', 'value', if(parameters('enablePostgresPublicAccess'), '0', '1')), createObject('name', 'WEBSITE_DNS_SERVER', 'value', '168.63.129.16'), createObject('name', 'WEBSITES_CONTAINER_START_TIME_LIMIT', 'value', '1800'), createObject('name', 'KC_LOG', 'value', 'console'), createObject('name', 'KC_LOG_LEVEL', 'value', 'INFO')), variables('appInsightsAppSettings'), variables('acrRegistryUrlAppSettings'), variables('acrRegistryCredentialAppSettings'))]",
2413
2435
  "vnetRouteAllEnabled": "[not(parameters('enablePostgresPublicAccess'))]"
2414
2436
  },
2415
2437
  "vnetRouteAllEnabled": "[not(parameters('enablePostgresPublicAccess'))]"
@@ -2524,6 +2546,9 @@
2524
2546
  "moriLicensePublicKey": {
2525
2547
  "value": "[parameters('moriLicensePublicKey')]"
2526
2548
  },
2549
+ "moriPolicyPublicKey": {
2550
+ "value": "[parameters('moriPolicyPublicKey')]"
2551
+ },
2527
2552
  "moriBaseUrl": {
2528
2553
  "value": "[parameters('moriBaseUrl')]"
2529
2554
  }
@@ -2535,7 +2560,7 @@
2535
2560
  "_generator": {
2536
2561
  "name": "bicep",
2537
2562
  "version": "0.47.16.16243",
2538
- "templateHash": "445562478593270876"
2563
+ "templateHash": "4650500285752133401"
2539
2564
  }
2540
2565
  },
2541
2566
  "parameters": {
@@ -2618,6 +2643,13 @@
2618
2643
  "description": "Mori licence issuer public key (SPKI PEM). Empty leaves the installation unpinned."
2619
2644
  }
2620
2645
  },
2646
+ "moriPolicyPublicKey": {
2647
+ "type": "string",
2648
+ "defaultValue": "",
2649
+ "metadata": {
2650
+ "description": "Mori policy signing anchor public key (SPKI PEM). Empty leaves the policy bundle without an independent anchor."
2651
+ }
2652
+ },
2621
2653
  "moriBaseUrl": {
2622
2654
  "type": "string",
2623
2655
  "defaultValue": "",
@@ -2735,6 +2767,15 @@
2735
2767
  "value": "[parameters('moriLicensePublicKey')]"
2736
2768
  }
2737
2769
  },
2770
+ {
2771
+ "condition": "[not(empty(parameters('moriPolicyPublicKey')))]",
2772
+ "type": "Microsoft.KeyVault/vaults/secrets",
2773
+ "apiVersion": "2023-07-01",
2774
+ "name": "[format('{0}/{1}', parameters('keyVaultName'), 'mori-policy-public-keyKeyVault')]",
2775
+ "properties": {
2776
+ "value": "[parameters('moriPolicyPublicKey')]"
2777
+ }
2778
+ },
2738
2779
  {
2739
2780
  "condition": "[not(empty(parameters('moriBaseUrl')))]",
2740
2781
  "type": "Microsoft.KeyVault/vaults/secrets",
@@ -2856,9 +2897,15 @@
2856
2897
  "entraIdTenantId": {
2857
2898
  "value": "[variables('effectiveEntraIdTenantId')]"
2858
2899
  },
2900
+ "adminEmail": {
2901
+ "value": "[parameters('adminEmail')]"
2902
+ },
2859
2903
  "licenseEdition": {
2860
2904
  "value": "[parameters('licenseEdition')]"
2861
2905
  },
2906
+ "installationResourceModel": {
2907
+ "value": "[parameters('installationResourceModel')]"
2908
+ },
2862
2909
  "onboardingMode": {
2863
2910
  "value": "[parameters('onboardingMode')]"
2864
2911
  },
@@ -2879,7 +2926,7 @@
2879
2926
  "_generator": {
2880
2927
  "name": "bicep",
2881
2928
  "version": "0.47.16.16243",
2882
- "templateHash": "13342696621269025420"
2929
+ "templateHash": "9991546815810387946"
2883
2930
  }
2884
2931
  },
2885
2932
  "parameters": {
@@ -3110,6 +3157,21 @@
3110
3157
  "description": "Requested license: edition name (COMMUNITY, STANDARD, ENTERPRISE) or Azure Marketplace subscription ID (UUID). Validated by Miso. Emitted as LICENSE_EDITION."
3111
3158
  }
3112
3159
  },
3160
+ "adminEmail": {
3161
+ "type": "string",
3162
+ "defaultValue": "",
3163
+ "metadata": {
3164
+ "description": "Initial platform administrator email."
3165
+ }
3166
+ },
3167
+ "installationResourceModel": {
3168
+ "type": "string",
3169
+ "defaultValue": "shared",
3170
+ "allowedValues": ["shared", "dedicated"],
3171
+ "metadata": {
3172
+ "description": "Initial installation topology, protected by Azure application configuration: shared for CE/SE; dedicated for EE DEV. Does not grant later licence entitlements."
3173
+ }
3174
+ },
3113
3175
  "onboardingMode": {
3114
3176
  "type": "string",
3115
3177
  "defaultValue": "customerOwned",
@@ -3206,7 +3268,7 @@
3206
3268
  "acrUseManagedIdentityCreds": "[not(parameters('registryPasswordConfigured'))]",
3207
3269
  "healthCheckPath": "/health",
3208
3270
  "alwaysOn": true,
3209
- "appSettings": "[concat(createArray(createObject('name', 'WEBSITES_ENABLE_APP_SERVICE_STORAGE', 'value', 'false'), createObject('name', 'WEBSITES_CONTAINER_START_TIME_LIMIT', 'value', '1800'), createObject('name', 'DATABASE_URL', 'value', variables('databaseUrlAppSettingValue')), createObject('name', 'JWT_SECRET', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-secrets-jwtKeyVault)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'NODE_ENV', 'value', 'production'), createObject('name', 'LOCATION', 'value', parameters('location')), createObject('name', 'PORT', 'value', '3000'), createObject('name', 'ALLOWED_ORIGINS', 'value', format('http://localhost:*,http://127.0.0.1:*,https://{0}.azurewebsites.net', parameters('name'))), createObject('name', 'WEBSITE_VNET_ROUTE_ALL', 'value', if(parameters('enablePostgresPublicAccess'), '0', '1')), createObject('name', 'WEBSITE_DNS_SERVER', 'value', '168.63.129.16'), createObject('name', 'DATABASELOG_URL', 'value', variables('databaseLogUrlAppSettingValue')), createObject('name', 'KEY_VAULT_ENABLED', 'value', 'true'), createObject('name', 'SECURITY_STORAGE_MODE', 'value', 'keyvault'), createObject('name', 'KEY_VAULT_URL', 'value', format('https://{0}.vault.azure.net/', last(split(parameters('keyVaultId'), '/')))), createObject('name', 'ENCRYPTION_KEY', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-encryption-keyKeyVault)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'AUTO_CREATE_TABLES', 'value', if(parameters('autoCreateTables'), 'true', 'false')), createObject('name', 'KEYCLOAK_REALM', 'value', parameters('keycloakRealm')), createObject('name', 'KEYCLOAK_CLIENT_ID', 'value', parameters('keycloakClientId')), createObject('name', 'KEYCLOAK_ADMIN_USERNAME', 'value', parameters('keycloakAdminUsername')), createObject('name', 'KEYCLOAK_ADMIN_PASSWORD', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-keycloak-admin-password)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'ONBOARDING_ADMIN_PASSWORD', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-onboarding-admin-password)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'KEYCLOAK_SERVER_URL', 'value', variables('keycloakPublicUrl')), createObject('name', 'KEYCLOAK_INTERNAL_SERVER_URL', 'value', variables('keycloakInternalUrl')), createObject('name', 'KEYCLOAK_TOKEN_TIMEOUT', 'value', '5000'), createObject('name', 'KEYCLOAK_VERIFY_AUDIENCE', 'value', if(parameters('keycloakVerifyAudience'), 'true', 'false')), createObject('name', 'DISABLE_RATE_LIMIT', 'value', variables('shouldDisableRateLimit')), createObject('name', 'SKIP_DB_REDEPLOY', 'value', 'true'), createObject('name', 'MISO_WEB_SERVER_URL', 'value', variables('misoPublicUrl')), createObject('name', 'MISO_CONTROLLER_URL', 'value', variables('misoInternalUrl')), createObject('name', 'MISO_RELATIVE_PATH', 'value', variables('misoVdirValue')), createObject('name', 'CONTROLLER_BASE_URL', 'value', if(not(empty(parameters('misoControllerUrl'))), parameters('misoControllerUrl'), format('https://{0}.azurewebsites.net', parameters('name')))), createObject('name', 'AZURE_SUBSCRIPTION_ID', 'value', subscription().subscriptionId), createObject('name', 'TENANT_ID', 'value', subscription().tenantId), createObject('name', 'DEPLOYMENT', 'value', 'azure'), createObject('name', 'AZURE_RESOURCE_GROUP_NAME', 'value', parameters('resourceGroupName')), createObject('name', 'INFRASTRUCTURE_NAME', 'value', parameters('prefix')), createObject('name', 'ENTRA_ID_TENANT_ID', 'value', parameters('entraIdTenantId')), createObject('name', 'MISO_CLIENTID', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-miso-clientIdKeyVault)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'MISO_CLIENTSECRET', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName=miso-controller-client-secretKeyVault)', last(split(parameters('keyVaultId'), '/')))), createObject('name', 'MORI_BASE_URL', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName=mori-base-urlKeyVault)', last(split(parameters('keyVaultId'), '/')))), createObject('name', 'MORI_LICENSE_PUBLIC_KEY', 'value', if(empty(parameters('moriLicensePublicKey')), '', format('@Microsoft.KeyVault(VaultName={0};SecretName=mori-license-public-keyKeyVault)', last(split(parameters('keyVaultId'), '/'))))), createObject('name', 'MORI_LICENSE_ISSUER', 'value', parameters('moriLicenseIssuer')), createObject('name', 'ENTRA_GRAPH_DELEGATED_REDIRECT_URI', 'value', variables('moriEntraGraphDelegatedRedirectUri')), createObject('name', 'ENTRA_ID_CENTRAL_CALLBACK_URI', 'value', variables('moriEntraCentralCallbackUri')), createObject('name', 'DOCKER_ENABLE_CI', 'value', 'true'), createObject('name', 'DOCKER_REGISTRY_SERVER_URL', 'value', if(not(empty(parameters('acrLoginServer'))), format('https://{0}', parameters('acrLoginServer')), '')), createObject('name', 'ONBOARDING_CREATE_PIPELINE_CREDENTIALS', 'value', 'true'), createObject('name', 'BOOTSTRAP_APPKEYS', 'value', parameters('bootstrapAppKeys')), createObject('name', 'LICENSE_JWT', 'value', parameters('licenseJwt')), createObject('name', 'LICENSE_EDITION', 'value', parameters('licenseEdition')), createObject('name', 'ONBOARDING_MODE', 'value', parameters('onboardingMode')), createObject('name', 'INSTALLATION_CAPACITY_PROFILE', 'value', parameters('capacityProfile'))), variables('registryCredentialAppSettings'))]",
3271
+ "appSettings": "[concat(createArray(createObject('name', 'WEBSITES_ENABLE_APP_SERVICE_STORAGE', 'value', 'false'), createObject('name', 'WEBSITES_CONTAINER_START_TIME_LIMIT', 'value', '1800'), createObject('name', 'DATABASE_URL', 'value', variables('databaseUrlAppSettingValue')), createObject('name', 'JWT_SECRET', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-secrets-jwtKeyVault)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'NODE_ENV', 'value', 'production'), createObject('name', 'LOCATION', 'value', parameters('location')), createObject('name', 'PORT', 'value', '3000'), createObject('name', 'ALLOWED_ORIGINS', 'value', format('http://localhost:*,http://127.0.0.1:*,https://{0}.azurewebsites.net', parameters('name'))), createObject('name', 'WEBSITE_VNET_ROUTE_ALL', 'value', if(parameters('enablePostgresPublicAccess'), '0', '1')), createObject('name', 'WEBSITE_DNS_SERVER', 'value', '168.63.129.16'), createObject('name', 'DATABASELOG_URL', 'value', variables('databaseLogUrlAppSettingValue')), createObject('name', 'KEY_VAULT_ENABLED', 'value', 'true'), createObject('name', 'SECURITY_STORAGE_MODE', 'value', 'keyvault'), createObject('name', 'KEY_VAULT_URL', 'value', format('https://{0}.vault.azure.net/', last(split(parameters('keyVaultId'), '/')))), createObject('name', 'ENCRYPTION_KEY', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-encryption-keyKeyVault)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'AUTO_CREATE_TABLES', 'value', if(parameters('autoCreateTables'), 'true', 'false')), createObject('name', 'KEYCLOAK_REALM', 'value', parameters('keycloakRealm')), createObject('name', 'KEYCLOAK_CLIENT_ID', 'value', parameters('keycloakClientId')), createObject('name', 'KEYCLOAK_ADMIN_USERNAME', 'value', parameters('keycloakAdminUsername')), createObject('name', 'KEYCLOAK_ADMIN_PASSWORD', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-keycloak-admin-password)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'ONBOARDING_ADMIN_PASSWORD', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-onboarding-admin-password)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'ONBOARDING_ADMIN_EMAIL', 'value', parameters('adminEmail')), createObject('name', 'KEYCLOAK_SERVER_URL', 'value', variables('keycloakPublicUrl')), createObject('name', 'KEYCLOAK_INTERNAL_SERVER_URL', 'value', variables('keycloakInternalUrl')), createObject('name', 'KEYCLOAK_TOKEN_TIMEOUT', 'value', '5000'), createObject('name', 'KEYCLOAK_VERIFY_AUDIENCE', 'value', if(parameters('keycloakVerifyAudience'), 'true', 'false')), createObject('name', 'DISABLE_RATE_LIMIT', 'value', variables('shouldDisableRateLimit')), createObject('name', 'SKIP_DB_REDEPLOY', 'value', 'true'), createObject('name', 'MISO_WEB_SERVER_URL', 'value', variables('misoPublicUrl')), createObject('name', 'MISO_CONTROLLER_URL', 'value', variables('misoInternalUrl')), createObject('name', 'MISO_RELATIVE_PATH', 'value', variables('misoVdirValue')), createObject('name', 'CONTROLLER_BASE_URL', 'value', if(not(empty(parameters('misoControllerUrl'))), parameters('misoControllerUrl'), format('https://{0}.azurewebsites.net', parameters('name')))), createObject('name', 'AZURE_SUBSCRIPTION_ID', 'value', subscription().subscriptionId), createObject('name', 'TENANT_ID', 'value', subscription().tenantId), createObject('name', 'DEPLOYMENT', 'value', 'azure'), createObject('name', 'AZURE_RESOURCE_GROUP_NAME', 'value', parameters('resourceGroupName')), createObject('name', 'INFRASTRUCTURE_NAME', 'value', parameters('prefix')), createObject('name', 'ENTRA_ID_TENANT_ID', 'value', parameters('entraIdTenantId')), createObject('name', 'MISO_CLIENTID', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName={1}-miso-clientIdKeyVault)', last(split(parameters('keyVaultId'), '/')), parameters('prefix'))), createObject('name', 'MISO_CLIENTSECRET', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName=miso-controller-client-secretKeyVault)', last(split(parameters('keyVaultId'), '/')))), createObject('name', 'MORI_BASE_URL', 'value', format('@Microsoft.KeyVault(VaultName={0};SecretName=mori-base-urlKeyVault)', last(split(parameters('keyVaultId'), '/')))), createObject('name', 'MORI_LICENSE_PUBLIC_KEY', 'value', if(empty(parameters('moriLicensePublicKey')), '', format('@Microsoft.KeyVault(VaultName={0};SecretName=mori-license-public-keyKeyVault)', last(split(parameters('keyVaultId'), '/'))))), createObject('name', 'MORI_LICENSE_ISSUER', 'value', parameters('moriLicenseIssuer')), createObject('name', 'ENTRA_GRAPH_DELEGATED_REDIRECT_URI', 'value', variables('moriEntraGraphDelegatedRedirectUri')), createObject('name', 'ENTRA_ID_CENTRAL_CALLBACK_URI', 'value', variables('moriEntraCentralCallbackUri')), createObject('name', 'DOCKER_ENABLE_CI', 'value', 'true'), createObject('name', 'DOCKER_REGISTRY_SERVER_URL', 'value', if(not(empty(parameters('acrLoginServer'))), format('https://{0}', parameters('acrLoginServer')), '')), createObject('name', 'ONBOARDING_CREATE_PIPELINE_CREDENTIALS', 'value', 'true'), createObject('name', 'BOOTSTRAP_APPKEYS', 'value', parameters('bootstrapAppKeys')), createObject('name', 'LICENSE_JWT', 'value', parameters('licenseJwt')), createObject('name', 'INSTALLATION_RESOURCE_MODEL', 'value', parameters('installationResourceModel')), createObject('name', 'LICENSE_EDITION', 'value', parameters('licenseEdition')), createObject('name', 'ONBOARDING_MODE', 'value', parameters('onboardingMode')), createObject('name', 'INSTALLATION_CAPACITY_PROFILE', 'value', parameters('capacityProfile'))), variables('registryCredentialAppSettings'))]",
3210
3272
  "vnetRouteAllEnabled": "[not(parameters('enablePostgresPublicAccess'))]"
3211
3273
  },
3212
3274
  "vnetRouteAllEnabled": "[not(parameters('enablePostgresPublicAccess'))]"
@@ -3613,7 +3675,7 @@
3613
3675
  "_generator": {
3614
3676
  "name": "bicep",
3615
3677
  "version": "0.47.16.16243",
3616
- "templateHash": "445562478593270876"
3678
+ "templateHash": "4650500285752133401"
3617
3679
  }
3618
3680
  },
3619
3681
  "parameters": {
@@ -3696,6 +3758,13 @@
3696
3758
  "description": "Mori licence issuer public key (SPKI PEM). Empty leaves the installation unpinned."
3697
3759
  }
3698
3760
  },
3761
+ "moriPolicyPublicKey": {
3762
+ "type": "string",
3763
+ "defaultValue": "",
3764
+ "metadata": {
3765
+ "description": "Mori policy signing anchor public key (SPKI PEM). Empty leaves the policy bundle without an independent anchor."
3766
+ }
3767
+ },
3699
3768
  "moriBaseUrl": {
3700
3769
  "type": "string",
3701
3770
  "defaultValue": "",
@@ -3813,6 +3882,15 @@
3813
3882
  "value": "[parameters('moriLicensePublicKey')]"
3814
3883
  }
3815
3884
  },
3885
+ {
3886
+ "condition": "[not(empty(parameters('moriPolicyPublicKey')))]",
3887
+ "type": "Microsoft.KeyVault/vaults/secrets",
3888
+ "apiVersion": "2023-07-01",
3889
+ "name": "[format('{0}/{1}', parameters('keyVaultName'), 'mori-policy-public-keyKeyVault')]",
3890
+ "properties": {
3891
+ "value": "[parameters('moriPolicyPublicKey')]"
3892
+ }
3893
+ },
3816
3894
  {
3817
3895
  "condition": "[not(empty(parameters('moriBaseUrl')))]",
3818
3896
  "type": "Microsoft.KeyVault/vaults/secrets",