@aifabrix/builder 2.59.0 → 2.60.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 (55) hide show
  1. package/lib/agent-kit/git-identity.js +180 -0
  2. package/lib/agent-kit/setup.js +3 -0
  3. package/lib/agent-kit/start.js +45 -1
  4. package/lib/api/role-assistant-test-job.api.js +60 -0
  5. package/lib/api/work-search.api.js +13 -6
  6. package/lib/app/deploy.js +8 -1
  7. package/lib/app/show-display.js +1 -0
  8. package/lib/app/show-online.js +15 -0
  9. package/lib/build/standard-docker-build.js +4 -1
  10. package/lib/cli/setup-app.js +14 -1
  11. package/lib/cli/setup-utility.js +24 -1
  12. package/lib/commands/role-assistant.js +7 -0
  13. package/lib/core/env-platform-expand.js +93 -0
  14. package/lib/core/secrets-env-content.js +37 -3
  15. package/lib/deployment/installation/azure-infra-stage.js +3 -1
  16. package/lib/deployment/installation/infra-catalog.js +2 -5
  17. package/lib/generator/builders.js +17 -0
  18. package/lib/generator/helpers.js +23 -2
  19. package/lib/generator/index.js +10 -6
  20. package/lib/role-assistant/test-cases-search.js +3 -0
  21. package/lib/role-assistant/test-job-runner.js +125 -0
  22. package/lib/role-assistant/test-runner-search.js +44 -2
  23. package/lib/schema/application-schema.json +193 -2
  24. package/lib/schema/infra-parameter.schema.json +139 -33
  25. package/lib/schema/infra.parameter.yaml +28 -28
  26. package/lib/schema/infrastructure-schema.json +10 -35
  27. package/lib/utils/compose-generate-docker-compose.js +12 -0
  28. package/lib/utils/docker-build.js +29 -8
  29. package/lib/utils/docker-manifest-public-port.js +36 -0
  30. package/lib/utils/platform-resolution.js +226 -0
  31. package/lib/utils/resolve-docker-image-ref.js +8 -3
  32. package/package.json +2 -2
  33. package/templates/README.md +2 -1
  34. package/templates/agent-kit/agent-kit.yaml +4 -1
  35. package/templates/agent-kit/instructions/AGENTKIT.md +1 -1
  36. package/templates/agent-kit/instructions/root.AGENTS.md +2 -0
  37. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +33 -1
  38. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/delivery-verdict.js +176 -0
  39. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +3 -0
  40. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +10 -3
  41. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +22 -0
  42. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +21 -0
  43. package/templates/agent-kit/skills/shared/feedback.md +31 -0
  44. package/templates/agent-kit/skills/shared/hosts.md +13 -3
  45. package/templates/agent-kit/skills/shared/status.md +85 -0
  46. package/templates/agent-kit/workspace/BUILDER_IMPROVEMENT_FINDINGS.md +27 -0
  47. package/templates/applications/builder-api/application.yaml +1 -1
  48. package/templates/applications/dataplane/application.yaml +30 -2
  49. package/templates/applications/dataplane/env.template +37 -4
  50. package/templates/applications/miso-controller/application.yaml +24 -1
  51. package/templates/applications/miso-controller/env.template +21 -34
  52. package/templates/marketplace/main.json +70 -222
  53. package/templates/python/Dockerfile.hbs +2 -0
  54. package/templates/typescript/Dockerfile.hbs +2 -0
  55. package/templates/typescript/docker-compose.hbs +12 -0
@@ -7,12 +7,12 @@
7
7
  "key": "application-schema",
8
8
  "name": "Application Configuration Schema",
9
9
  "description": "JSON schema for validating AI Fabrix application configuration files",
10
- "version": "1.7.0",
10
+ "version": "1.9.0",
11
11
  "type": "schema",
12
12
  "category": "infrastructure",
13
13
  "author": "AI Fabrix Team",
14
14
  "createdAt": "2024-01-01T00:00:00Z",
15
- "updatedAt": "2026-09-16T00:00:00Z",
15
+ "updatedAt": "2026-09-23T00:00:00Z",
16
16
  "compatibility": {
17
17
  "minVersion": "1.0.0",
18
18
  "maxVersion": "2.0.0",
@@ -30,6 +30,27 @@
30
30
  "external-datasource.schema.json"
31
31
  ],
32
32
  "changelog": [
33
+ {
34
+ "version": "1.9.0",
35
+ "date": "2026-09-23T00:00:00Z",
36
+ "breaking": false,
37
+ "changes": [
38
+ "Added optional platforms: the target Azure resource group is matched against resource patterns to yield {platform} and {platform.name}, and that entry's configuration resolves from them.",
39
+ "Added optional environments: per-environment configuration layered over the platform match, overriding by name.",
40
+ "Added optional portalInput.visible (default true) so a resolved or derived value stays out of the portal form.",
41
+ "Both sections are optional and independent; manifests without them are unchanged."
42
+ ]
43
+ },
44
+ {
45
+ "version": "1.8.0",
46
+ "date": "2026-09-21T00:00:00Z",
47
+ "changes": [
48
+ "Added optional build.target: the multi-stage Dockerfile stage to build (docker build --target). Omitted, Docker builds the final stage as before, so existing manifests are unaffected. Lets one Dockerfile and one source tree produce more than one image.",
49
+ "Added optional top-level runAsRoot: run the container as the image user (root) rather than the invoking host user. Absent or false keeps the existing behavior. Only for an application that administers its own operating system, such as creating Linux accounts or running sshd.",
50
+ "Added optional top-level additionalPorts: extra container ports to publish beside the main port, for an application serving a second protocol such as SSH from the same container. Each host port is derived as hostPort + developerId * 100, the same formula as the main port. A base below 1024 is permitted so a well-known port keeps its number. Absent keeps the existing single-port behavior."
51
+ ],
52
+ "breaking": false
53
+ },
33
54
  {
34
55
  "version": "1.7.0",
35
56
  "date": "2026-09-16T00:00:00Z",
@@ -210,6 +231,124 @@
210
231
  "type": "boolean",
211
232
  "description": "Whether application requires storage.Physical storage is mapped to /mnt/data/. Blob storage is mapped to SMB File share /data/{app-key}/."
212
233
  },
234
+ "platforms": {
235
+ "type": "array",
236
+ "description": "Platform resolution: the target Azure resource group is matched against these entries, yielding {platform} and {platform.name}. Optional and independent of environments.",
237
+ "items": {
238
+ "type": "object",
239
+ "required": ["resource", "name", "configuration"],
240
+ "additionalProperties": false,
241
+ "properties": {
242
+ "resource": {
243
+ "type": "string",
244
+ "description": "Resource-group pattern; {platform} marks the platform segment and * captures a name segment",
245
+ "minLength": 1
246
+ },
247
+ "name": {
248
+ "type": "string",
249
+ "description": "Platform name: a literal, or * to take the captured segment",
250
+ "minLength": 1
251
+ },
252
+ "options": {
253
+ "type": "array",
254
+ "description": "Allowed platform values; required when resource contains {platform}",
255
+ "minItems": 1,
256
+ "items": { "type": "string", "minLength": 1 }
257
+ },
258
+ "platform": {
259
+ "type": "string",
260
+ "description": "Declared platform for a resource pattern with no {platform} token; mutually exclusive with options",
261
+ "minLength": 1
262
+ },
263
+ "configuration": {
264
+ "type": "array",
265
+ "description": "Values resolved when this platform matches",
266
+ "items": {
267
+ "type": "object",
268
+ "required": ["name", "value"],
269
+ "additionalProperties": false,
270
+ "properties": {
271
+ "name": {
272
+ "type": "string",
273
+ "description": "Configuration variable name",
274
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
275
+ },
276
+ "value": {
277
+ "type": "string",
278
+ "description": "Literal, or a value containing {platform}, {platform.name} or {resourceGroup} tokens"
279
+ },
280
+ "location": {
281
+ "type": "string",
282
+ "description": "Where the value is stored",
283
+ "enum": ["variable", "keyvault"]
284
+ },
285
+ "required": {
286
+ "type": "boolean",
287
+ "description": "Whether this configuration is required"
288
+ },
289
+ "category": {
290
+ "type": "string",
291
+ "description": "Optional UI grouping label for portal/deployment wizard Configuration tab",
292
+ "minLength": 1,
293
+ "maxLength": 100
294
+ }
295
+ }
296
+ }
297
+ }
298
+ }
299
+ }
300
+ },
301
+ "environments": {
302
+ "type": "array",
303
+ "description": "Per-environment values layered over the platform match, overriding by name. Optional and independent of platforms.",
304
+ "items": {
305
+ "type": "object",
306
+ "required": ["environment", "configuration"],
307
+ "additionalProperties": false,
308
+ "properties": {
309
+ "environment": {
310
+ "type": "string",
311
+ "description": "Deployment environment key (for example miso, dev, tst, pro)",
312
+ "minLength": 1
313
+ },
314
+ "configuration": {
315
+ "type": "array",
316
+ "description": "Values resolved for this environment",
317
+ "items": {
318
+ "type": "object",
319
+ "required": ["name", "value"],
320
+ "additionalProperties": false,
321
+ "properties": {
322
+ "name": {
323
+ "type": "string",
324
+ "description": "Configuration variable name",
325
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
326
+ },
327
+ "value": {
328
+ "type": "string",
329
+ "description": "Literal, or a value containing {platform}, {platform.name} or {resourceGroup} tokens"
330
+ },
331
+ "location": {
332
+ "type": "string",
333
+ "description": "Where the value is stored",
334
+ "enum": ["variable", "keyvault"]
335
+ },
336
+ "required": {
337
+ "type": "boolean",
338
+ "description": "Whether this configuration is required"
339
+ },
340
+ "category": {
341
+ "type": "string",
342
+ "description": "Optional UI grouping label for portal/deployment wizard Configuration tab",
343
+ "minLength": 1,
344
+ "maxLength": 100
345
+ }
346
+ }
347
+ }
348
+ }
349
+ }
350
+ }
351
+ },
213
352
  "configuration": {
214
353
  "type": "array",
215
354
  "description": "Core application configuration",
@@ -274,6 +413,10 @@
274
413
  "type": "boolean",
275
414
  "description": "Whether to mask the input (for passwords)"
276
415
  },
416
+ "visible": {
417
+ "type": "boolean",
418
+ "description": "Whether the portal shows this input. Default true; false keeps a resolved or derived value out of the form."
419
+ },
277
420
  "validation": {
278
421
  "type": "object",
279
422
  "properties": {
@@ -413,6 +556,10 @@
413
556
  "type": "boolean",
414
557
  "description": "Whether to mask the input (for passwords)"
415
558
  },
559
+ "visible": {
560
+ "type": "boolean",
561
+ "description": "Whether the portal shows this input. Default true; false keeps a resolved or derived value out of the form."
562
+ },
416
563
  "validation": {
417
564
  "type": "object",
418
565
  "properties": {
@@ -806,6 +953,43 @@
806
953
  "minLength": 1,
807
954
  "maxLength": 200
808
955
  },
956
+ "additionalPorts": {
957
+ "type": "array",
958
+ "description": "Extra container ports to publish beside the main port. For an application that serves a second protocol from the same container, such as SSH alongside HTTP. Each host port is derived the same way as the main one: hostPort + developerId * 100 (developer id 0 keeps hostPort).",
959
+ "maxItems": 5,
960
+ "items": {
961
+ "type": "object",
962
+ "required": ["name", "containerPort", "hostPort"],
963
+ "additionalProperties": false,
964
+ "properties": {
965
+ "name": {
966
+ "type": "string",
967
+ "description": "What the port is for, e.g. 'ssh'. Used in generated compose comments and diagnostics.",
968
+ "pattern": "^[a-z][a-z0-9-]*$",
969
+ "minLength": 1,
970
+ "maxLength": 30
971
+ },
972
+ "containerPort": {
973
+ "type": "integer",
974
+ "description": "Port the process listens on inside the container.",
975
+ "minimum": 1,
976
+ "maximum": 65535
977
+ },
978
+ "hostPort": {
979
+ "type": "integer",
980
+ "description": "Base host port. The published port is hostPort + developerId * 100, so developers on one host do not collide. A base below 1024 is allowed so a well-known port can keep its number (SSH as 22, giving 122 for developer 1); the container engine binds it, not the application.",
981
+ "minimum": 1,
982
+ "maximum": 65535
983
+ }
984
+ }
985
+ }
986
+ },
987
+ "runAsRoot": {
988
+ "type": "boolean",
989
+ "default": false,
990
+ "description": "Run the container as the image user (root) instead of the invoking host user. Only for an application that administers its own operating system, such as creating Linux accounts or running sshd; files it writes to a bind mount will be root-owned. Absent or false keeps the existing behavior.",
991
+ "examples": [false]
992
+ },
809
993
  "runtimeVersion": {
810
994
  "type": "object",
811
995
  "description": "Runtime version configuration",
@@ -886,6 +1070,13 @@
886
1070
  "description": "Dockerfile name (empty or missing = use auto-generated template)",
887
1071
  "pattern": "^[^/].*"
888
1072
  },
1073
+ "target": {
1074
+ "type": "string",
1075
+ "description": "Multi-stage Dockerfile stage to build (docker build --target). Omit to build the final stage, which is the default. Lets one Dockerfile and one source tree produce more than one image, e.g. an application shipped in two installation variants.",
1076
+ "minLength": 1,
1077
+ "maxLength": 100,
1078
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$"
1079
+ },
889
1080
  "remoteSyncPath": {
890
1081
  "type": "string",
891
1082
  "description": "Relative path under user-mutagen-folder for remote sync and Docker -v; when unset, defaults to dev/<appKey>. No leading slash.",
@@ -3,7 +3,10 @@
3
3
  "$id": "aifabrix://schema/infra-parameter.schema.json",
4
4
  "title": "Infra parameter catalog",
5
5
  "type": "object",
6
- "required": ["version", "parameters"],
6
+ "required": [
7
+ "version",
8
+ "parameters"
9
+ ],
7
10
  "additionalProperties": false,
8
11
  "properties": {
9
12
  "version": {
@@ -12,7 +15,10 @@
12
15
  },
13
16
  "standardUpInfraEnsureKeys": {
14
17
  "type": "array",
15
- "items": { "type": "string", "minLength": 1 },
18
+ "items": {
19
+ "type": "string",
20
+ "minLength": 1
21
+ },
16
22
  "description": "Extra keys always merged on up-infra (e.g. default miso-controller DB pair when no workspace template lists them)."
17
23
  },
18
24
  "defaults": {
@@ -20,28 +26,47 @@
20
26
  "additionalProperties": false,
21
27
  "description": "Default values for {{adminPassword}}, {{adminEmail}}, {{userPassword}} in literal generator values; overridden by aifabrix up-infra flags.",
22
28
  "properties": {
23
- "adminEmail": { "type": "string" },
24
- "adminPassword": { "type": "string" },
25
- "userPassword": { "type": "string" }
29
+ "adminEmail": {
30
+ "type": "string"
31
+ },
32
+ "adminPassword": {
33
+ "type": "string"
34
+ },
35
+ "userPassword": {
36
+ "type": "string"
37
+ }
26
38
  }
27
39
  },
28
40
  "parameters": {
29
41
  "type": "array",
30
- "items": { "$ref": "#/definitions/parameterEntry" }
42
+ "items": {
43
+ "$ref": "#/definitions/parameterEntry"
44
+ }
31
45
  }
32
46
  },
33
47
  "definitions": {
34
48
  "ensureOnEnum": {
35
49
  "type": "string",
36
- "enum": ["upInfra", "resolveApp", "appRegister"]
50
+ "enum": [
51
+ "upInfra",
52
+ "resolveApp",
53
+ "appRegister"
54
+ ]
37
55
  },
38
56
  "scopeEnum": {
39
57
  "type": "string",
40
- "enum": ["infra", "app", "shared-service", "system"]
58
+ "enum": [
59
+ "infra",
60
+ "app",
61
+ "shared-service",
62
+ "system"
63
+ ]
41
64
  },
42
65
  "generator": {
43
66
  "type": "object",
44
- "required": ["type"],
67
+ "required": [
68
+ "type"
69
+ ],
45
70
  "additionalProperties": false,
46
71
  "properties": {
47
72
  "type": {
@@ -67,17 +92,47 @@
67
92
  "maximum": 512,
68
93
  "description": "For randomAlphanumeric: character count (default 32). For password: default 8. Charset [a-zA-Z0-9]."
69
94
  },
70
- "pairId": { "type": "string", "minLength": 1 },
71
- "part": { "type": "string", "enum": ["private", "public"] }
95
+ "pairId": {
96
+ "type": "string",
97
+ "minLength": 1
98
+ },
99
+ "part": {
100
+ "type": "string",
101
+ "enum": [
102
+ "private",
103
+ "public"
104
+ ]
105
+ }
72
106
  },
73
107
  "allOf": [
74
108
  {
75
- "if": { "properties": { "type": { "const": "literal" } } },
76
- "then": { "required": ["value"] }
109
+ "if": {
110
+ "properties": {
111
+ "type": {
112
+ "const": "literal"
113
+ }
114
+ }
115
+ },
116
+ "then": {
117
+ "required": [
118
+ "value"
119
+ ]
120
+ }
77
121
  },
78
122
  {
79
- "if": { "properties": { "type": { "const": "rsaKeyPair" } } },
80
- "then": { "required": ["pairId", "part"] }
123
+ "if": {
124
+ "properties": {
125
+ "type": {
126
+ "const": "rsaKeyPair"
127
+ }
128
+ }
129
+ },
130
+ "then": {
131
+ "required": [
132
+ "pairId",
133
+ "part"
134
+ ]
135
+ }
81
136
  }
82
137
  ]
83
138
  },
@@ -85,19 +140,32 @@
85
140
  "type": "object",
86
141
  "additionalProperties": false,
87
142
  "properties": {
88
- "vaultSecretName": { "type": "string" },
89
- "vaultSecretNamePattern": { "type": "string" },
143
+ "vaultSecretName": {
144
+ "type": "string"
145
+ },
146
+ "vaultSecretNamePattern": {
147
+ "type": "string"
148
+ },
90
149
  "legacyVaultSecretNames": {
91
150
  "type": "array",
92
- "items": { "type": "string", "minLength": 1 },
151
+ "items": {
152
+ "type": "string",
153
+ "minLength": 1
154
+ },
93
155
  "uniqueItems": true
94
156
  },
95
- "notes": { "type": "string" }
157
+ "notes": {
158
+ "type": "string"
159
+ }
96
160
  }
97
161
  },
98
162
  "parameterEntry": {
99
163
  "type": "object",
100
- "required": ["scope", "generator", "ensureOn"],
164
+ "required": [
165
+ "scope",
166
+ "generator",
167
+ "ensureOn"
168
+ ],
101
169
  "additionalProperties": false,
102
170
  "properties": {
103
171
  "key": {
@@ -108,8 +176,13 @@
108
176
  "type": "string",
109
177
  "minLength": 1
110
178
  },
111
- "category": { "type": "string", "minLength": 1 },
112
- "sensitive": { "type": "boolean" },
179
+ "category": {
180
+ "type": "string",
181
+ "minLength": 1
182
+ },
183
+ "sensitive": {
184
+ "type": "boolean"
185
+ },
113
186
  "valueSource": {
114
187
  "type": "string",
115
188
  "enum": [
@@ -120,31 +193,64 @@
120
193
  "optionalInput"
121
194
  ]
122
195
  },
123
- "requiredOnSystemOnboarding": { "type": "boolean" },
124
- "ownerAppKey": { "type": "string", "minLength": 1 },
196
+ "requiredOnSystemOnboarding": {
197
+ "type": "boolean"
198
+ },
199
+ "ownerAppKey": {
200
+ "type": "string",
201
+ "minLength": 1
202
+ },
125
203
  "sharedWithAppKeys": {
126
204
  "type": "array",
127
- "items": { "type": "string", "minLength": 1 },
205
+ "items": {
206
+ "type": "string",
207
+ "minLength": 1
208
+ },
128
209
  "minItems": 1,
129
210
  "uniqueItems": true,
130
211
  "description": "Named applications, other than ownerAppKey, that may read this value."
131
212
  },
132
- "scope": { "$ref": "#/definitions/scopeEnum" },
133
- "generator": { "$ref": "#/definitions/generator" },
213
+ "visibility": {
214
+ "type": "array",
215
+ "items": {
216
+ "type": "string"
217
+ },
218
+ "description": "App keys allowed to read this parameter. Canonical field in the Miso catalog that lib/schema/infra.parameter.yaml mirrors; sharedWithAppKeys is the older Builder spelling."
219
+ },
220
+ "scope": {
221
+ "$ref": "#/definitions/scopeEnum"
222
+ },
223
+ "generator": {
224
+ "$ref": "#/definitions/generator"
225
+ },
134
226
  "ensureOn": {
135
227
  "type": "array",
136
228
  "minItems": 1,
137
- "items": { "$ref": "#/definitions/ensureOnEnum" }
229
+ "items": {
230
+ "$ref": "#/definitions/ensureOnEnum"
231
+ }
232
+ },
233
+ "requiredForLocal": {
234
+ "type": "boolean"
235
+ },
236
+ "azure": {
237
+ "$ref": "#/definitions/azureBlock"
138
238
  },
139
- "requiredForLocal": { "type": "boolean" },
140
- "azure": { "$ref": "#/definitions/azureBlock" },
141
- "notes": { "type": "string" }
239
+ "notes": {
240
+ "type": "string"
241
+ }
142
242
  },
143
243
  "allOf": [
144
244
  {
145
245
  "if": {
146
- "required": ["scope"],
147
- "properties": { "scope": { "const": "system" } }
246
+ "required": [
247
+ "scope"
248
+ ],
249
+ "properties": {
250
+ "scope": {
251
+ "const": "system"
252
+ }
253
+ }
148
254
  },
149
255
  "then": {
150
256
  "required": [
@@ -29,7 +29,6 @@ standardUpInfraEnsureKeys:
29
29
  - databases-dataplane-3-urlKeyVault
30
30
  - databases-dataplane-3-passwordKeyVault
31
31
  # Miso-controller Entra onboarding (vendor app); required for aifabrix resolve miso-controller
32
- - entra-callback-state-secret
33
32
  - entra-callback-uri
34
33
  - entra-client-idKeyVault
35
34
  - entra-client-secretKeyVault
@@ -349,20 +348,6 @@ parameters:
349
348
 
350
349
  # Miso-controller Entra ID onboarding (vendor multi-tenant app). Empty client/callback values
351
350
  # allow local resolve and start-dev; set real values before Entra admin-consent flows.
352
- - key: entra-callback-state-secret
353
- category: Microsoft Entra ID
354
- sensitive: true
355
- valueSource: generated
356
- requiredOnSystemOnboarding: true
357
- scope: system
358
- generator:
359
- type: randomBytes32
360
- ensureOn: [upInfra, resolveApp]
361
- azure:
362
- notes: >-
363
- Shared HMAC secret (min 16 chars) for OAuth state between controller and Mori callback;
364
- maps to ENTRA_CALLBACK_STATE_SECRET in miso-controller env.template.
365
-
366
351
  - key: entra-callback-uri
367
352
  category: Microsoft Entra ID
368
353
  sensitive: false
@@ -441,8 +426,9 @@ parameters:
441
426
  # side is decrypted by the other. The read was already happening in the shipped template
442
427
  # and the policy denied it. Declared rather than silently permitted, and kept to the one
443
428
  # application that needs it instead of moving the key to a scope that grants everyone.
444
- sharedWithAppKeys:
429
+ visibility:
445
430
  - dataplane
431
+ - mori-controller
446
432
  scope: app
447
433
  generator:
448
434
  type: randomBytes32
@@ -454,6 +440,32 @@ parameters:
454
440
  notes: >-
455
441
  32-byte secret as base64; generated on first ensure. Rotate in production.
456
442
 
443
+ - key: integration-server-secrets-encryptionKeyVault
444
+ ownerAppKey: integration-server
445
+ # Deliberately NOT shared with any other app, which is the point of the row.
446
+ # An integrator installation hands this key to every developer it provisions: it is
447
+ # written into each managed ~/.aifabrix/config.yaml as `secrets-encryption`, so the
448
+ # CLI can decrypt what that installation's own secrets API encrypted. A key shared
449
+ # with another application would therefore be readable by everyone holding a shell
450
+ # in that container, and one leak would reach every installation using it.
451
+ # One installation, one key, so the blast radius stays inside it.
452
+ #
453
+ # Before this row existed, integration-server's env.template read
454
+ # `kv://builder-server-secrets-encryptionKeyVault` — another application's key.
455
+ # That resolves only by being granted, and granting it grants exactly the access
456
+ # above; without a grant it silently generated an unrelated value instead, so the
457
+ # two server types drifted apart with nothing reporting it.
458
+ scope: app
459
+ generator:
460
+ type: randomBytes32
461
+ ensureOn: [upInfra, resolveApp]
462
+ azure:
463
+ vaultSecretName: integration-server-secrets-encryptionKeyVault
464
+ notes: >-
465
+ 32-byte secret as base64; generated on first ensure, per installation. Rotating it
466
+ requires re-running configuration sync so every managed config.yaml is rewritten;
467
+ secrets already stored by that installation do not survive the rotation.
468
+
457
469
  # Local kv:// name matches miso-controller env.template (JWT_SECRET); not the generic {appKey}-secrets-jwtKeyVault Azure name.
458
470
  - key: miso-controller-jwt-secretKeyVault
459
471
  ownerAppKey: miso-controller
@@ -794,18 +806,6 @@ parameters:
794
806
  Optional local testing/development bearer bypass. A supplied local value is resolved; when absent,
795
807
  local and Azure application deployment resolve it as empty and do not fail.
796
808
 
797
- - key: mori-callback-api-keyKeyVault
798
- ownerAppKey: miso-controller
799
- scope: app
800
- generator:
801
- type: randomBytes32
802
- ensureOn: [resolveApp]
803
- azure:
804
- vaultSecretName: mori-callback-api-keyKeyVault
805
- legacyVaultSecretNames:
806
- - marketplace-mori-callback-api-key
807
- notes: Miso Controller callback credential; generated only when its resolved manifest requires it.
808
-
809
809
  # App semver when env.template / conversion yields kv://version (local secrets backfill).
810
810
  - key: version
811
811
  scope: app
@@ -7,12 +7,12 @@
7
7
  "key": "infrastructure-schema",
8
8
  "name": "Installation Infrastructure Manifest Schema",
9
9
  "description": "JSON schema for infrastructure/<resource-group>/environment-infra.json",
10
- "version": "2.0.0",
10
+ "version": "2.1.0",
11
11
  "type": "schema",
12
12
  "category": "infrastructure",
13
13
  "author": "AI Fabrix Team",
14
14
  "createdAt": "2024-01-01T00:00:00Z",
15
- "updatedAt": "2026-09-17T00:00:00Z",
15
+ "updatedAt": "2026-09-24T00:00:00Z",
16
16
  "compatibility": {
17
17
  "minVersion": "2.0.0",
18
18
  "maxVersion": "2.0.0",
@@ -26,6 +26,14 @@
26
26
  ],
27
27
  "dependencies": [],
28
28
  "changelog": [
29
+ {
30
+ "version": "2.1.0",
31
+ "date": "2026-09-24T00:00:00Z",
32
+ "breaking": false,
33
+ "changes": [
34
+ "Removed moriCallbackApiKey and entraCallbackStateSecret: the shipped Marketplace template no longer declares them. The installation receives its Mori key at licence registration, and Entra consent state is issued server-side (Mori 227.5)."
35
+ ]
36
+ },
29
37
  {
30
38
  "version": "2.0.0",
31
39
  "date": "2026-09-16T00:00:00Z",
@@ -501,8 +509,6 @@
501
509
  "acrResourceId",
502
510
  "deployRoleAssignments",
503
511
  "moriBaseUrl",
504
- "moriCallbackApiKey",
505
- "entraCallbackStateSecret",
506
512
  "entraIdClientId",
507
513
  "entraIdClientSecret",
508
514
  "entraIdTenantId",
@@ -1058,37 +1064,6 @@
1058
1064
  }
1059
1065
  }
1060
1066
  },
1061
- "moriCallbackApiKey": {
1062
- "$ref": "#/definitions/envReference"
1063
- },
1064
- "entraCallbackStateSecret": {
1065
- "type": "object",
1066
- "required": [
1067
- "value",
1068
- "source",
1069
- "description"
1070
- ],
1071
- "additionalProperties": false,
1072
- "properties": {
1073
- "value": {
1074
- "type": "null"
1075
- },
1076
- "source": {
1077
- "type": "string",
1078
- "minLength": 1
1079
- },
1080
- "description": {
1081
- "type": "string",
1082
- "minLength": 1
1083
- },
1084
- "required": {
1085
- "type": "boolean"
1086
- },
1087
- "requiredAt": {
1088
- "const": "tenantActivation"
1089
- }
1090
- }
1091
- },
1092
1067
  "entraIdClientId": {
1093
1068
  "type": "object",
1094
1069
  "required": [