@aifabrix/builder 2.60.0 → 2.62.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 +14 -11
- package/docs/README.md +80 -0
- package/docs/builder-help/evidence-patterns.json +155 -0
- package/docs/builder-help/golden-examples/crm-company.json +30 -0
- package/docs/builder-help/golden-examples/crm-deal.json +29 -0
- package/docs/builder-help/golden-examples/document-storage-keyed-get.json +85 -0
- package/docs/builder-help/golden-examples/document-storage.json +30 -0
- package/docs/builder-help/golden-examples/meeting-transcript.json +29 -0
- package/docs/builder-help/golden-examples/repository-template.json +29 -0
- package/docs/builder-help/golden-examples/service-ticket.json +29 -0
- package/docs/builder-help/platform-roles.json +98 -0
- package/docs/builder-help/resource-type-catalog.json +402 -0
- package/lib/api/applications.api.js +22 -2
- package/lib/api/bootstrap-snapshot.api.js +115 -0
- package/lib/api/configuration.api.js +131 -0
- package/lib/api/system-secrets.api.js +72 -0
- package/lib/app/deploy.js +14 -5
- package/lib/app/run-docker-fallback.js +6 -1
- package/lib/app/run-env-compose.js +5 -6
- package/lib/app/run-helpers.js +2 -1
- package/lib/app/run-parameter-sync.js +142 -0
- package/lib/app/run.js +6 -4
- package/lib/build/docker-build-args.js +5 -2
- package/lib/build/index.js +3 -2
- package/lib/build/standard-docker-build.js +6 -2
- package/lib/channels/channel-artifact-generator.js +13 -3
- package/lib/cli/infra-guided-footers.js +10 -8
- package/lib/cli/infra-guided.js +30 -10
- package/lib/cli/setup-app.js +5 -0
- package/lib/cli/setup-environment.js +156 -0
- package/lib/cli/setup-infra-up-platform-action.js +14 -1
- package/lib/cli/setup-platform.js +2 -0
- package/lib/commands/auth-config.js +2 -0
- package/lib/commands/datasource-capability-upsert-cli.js +112 -0
- package/lib/commands/datasource-capability.js +4 -2
- package/lib/commands/env-secret-context.js +113 -0
- package/lib/commands/env-secret-list.js +200 -0
- package/lib/commands/env-secret-push-confirm.js +54 -0
- package/lib/commands/env-secret-push-run.js +227 -0
- package/lib/commands/env-secret-push.js +168 -0
- package/lib/commands/login.js +4 -0
- package/lib/commands/repair-datasource-apply.js +5 -1
- package/lib/commands/repair-datasource-keyed-document.js +122 -0
- package/lib/commands/repair-datasource-legacy.js +94 -0
- package/lib/commands/repair-datasource-run.js +1 -0
- package/lib/commands/setup-image-refresh.js +26 -0
- package/lib/commands/setup-modes.js +8 -9
- package/lib/commands/setup-prompts-platform-mode.js +34 -0
- package/lib/commands/setup-prompts.js +2 -180
- package/lib/commands/setup.js +3 -0
- package/lib/commands/up-builder-api.js +24 -8
- package/lib/commands/up-common.js +16 -1
- package/lib/commands/up-dataplane-bootstrap.js +70 -14
- package/lib/commands/up-dataplane-credentials.js +21 -0
- package/lib/commands/up-dataplane.js +37 -18
- package/lib/commands/up-integration-server.js +112 -0
- package/lib/commands/verify-operations-skip-e2e.js +25 -1
- package/lib/commands/verify-operations-steps.js +13 -1
- package/lib/commands/wizard-config-normalizer.js +12 -5
- package/lib/commands/wizard-core.js +5 -157
- package/lib/commands/wizard-file-saving.js +163 -0
- package/lib/core/admin-secrets-env-overlay.js +8 -3
- package/lib/core/env-platform-expand.js +5 -1
- package/lib/core/environment-access-policy.js +121 -0
- package/lib/core/environment-mode-policy.js +177 -0
- package/lib/core/local-env-overrides.js +149 -0
- package/lib/core/secrets-ensure.js +4 -2
- package/lib/core/secrets-env-content.js +17 -10
- package/lib/core/secrets-env-write.js +11 -4
- package/lib/core/secrets-load.js +4 -2
- package/lib/datasource/binary-documents-validator.js +190 -0
- package/lib/datasource/capability/capability-manifest.js +1 -0
- package/lib/datasource/capability/run-capability-upsert.js +202 -0
- package/lib/datasource/capability/upsert-ingredients.js +291 -0
- package/lib/datasource/capability/upsert-operations.js +138 -0
- package/lib/datasource/capability/upsert-test-scaffold.js +189 -0
- package/lib/datasource/validate.js +12 -5
- package/lib/deployment/installation/index.js +14 -1
- package/lib/deployment/installation/infra-catalog.js +3 -0
- package/lib/deployment/installation/local-environment-stage.js +285 -0
- package/lib/deployment/installation/local-installation.js +76 -0
- package/lib/deployment/installation/stage-input.js +5 -1
- package/lib/generator/builders.js +3 -1
- package/lib/generator/index.js +3 -0
- package/lib/generator/split-variables.js +2 -2
- package/lib/lifecycle/product-model.js +4 -3
- package/lib/lifecycle/report-display.js +3 -2
- package/lib/parameters/database-adoption.js +125 -0
- package/lib/parameters/infra-parameter-catalog.js +1 -1
- package/lib/parameters/physical-database-naming.js +136 -0
- package/lib/parameters/physical-secret-name.js +194 -0
- package/lib/parameters/rsa-secret-values.js +165 -0
- package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +1 -1
- package/lib/programmatic/builder-help-governance.js +1 -1
- package/lib/programmatic/builder-help.js +1 -1
- package/lib/programmatic/run-channel-install-artifacts.js +28 -2
- package/lib/programmatic/run-channel-package.js +3 -1
- package/lib/programmatic/workspace-context.js +37 -2
- package/lib/role-assistant/test-runner-workhub-answers.js +4 -1
- package/lib/role-assistant/test-runner-workhub-missing-fields.js +42 -0
- package/lib/role-assistant/test-runner-workhub-wait-stop.js +94 -0
- package/lib/role-assistant/test-runner-workhub.js +28 -19
- package/lib/schema/application-schema.json +14 -2
- package/lib/schema/external-datasource.schema.json +23 -3
- package/lib/schema/infra.parameter.yaml +440 -56
- package/lib/schema/infrastructure-schema.json +213 -120
- package/lib/utils/compose-generate-docker-compose.js +9 -14
- package/lib/utils/compose-generator.js +4 -7
- package/lib/utils/compose-miso-env.js +2 -2
- package/lib/utils/compose-traefik-ingress-base.js +3 -4
- package/lib/utils/datasource-binary-evidence.js +92 -0
- package/lib/utils/datasource-test-run-capability-scope.js +44 -1
- package/lib/utils/datasource-test-run-debug-display.js +2 -0
- package/lib/utils/datasource-test-run-display.js +8 -2
- package/lib/utils/datasource-test-run-issue-guidance.js +176 -0
- package/lib/utils/datasource-test-run-tty-log.js +2 -0
- package/lib/utils/declarative-url-ports.js +3 -0
- package/lib/utils/env-copy.js +11 -10
- package/lib/utils/env-environment-file-paths.js +105 -0
- package/lib/utils/environment-scoped-resources.js +48 -14
- package/lib/utils/external-system-system-test-tty.js +3 -2
- package/lib/utils/image-tags.js +2 -2
- package/lib/utils/paths-system-builder-keys.js +7 -1
- package/lib/utils/paths.js +7 -2
- package/lib/utils/platform-kv-ref.js +1 -1
- package/lib/utils/postgres-platform-bootstrap.js +35 -1
- package/lib/utils/prepare-local-data-mount.js +58 -0
- package/lib/utils/redis-env-scope.js +21 -1
- package/lib/utils/registry-auth-sources.js +154 -0
- package/lib/utils/registry-credentials.js +131 -14
- package/lib/utils/secrets-generator.js +30 -21
- package/lib/utils/secrets-helpers.js +5 -8
- package/lib/utils/secrets-kv-scope.js +127 -28
- package/lib/utils/secrets-materialize-local.js +9 -0
- package/lib/utils/secrets-missing-error.js +35 -1
- package/lib/utils/system-secret-mapping.js +125 -0
- package/lib/utils/test-log-writer.js +2 -1
- package/lib/utils/token-manager.js +14 -8
- package/lib/utils/url-public-path-prefix.js +6 -10
- package/lib/validation/external-manifest-validator.js +5 -0
- package/lib/validation/openapi-contract-surface-validator.js +3 -1
- package/lib/validation/validate-external-file.js +5 -1
- package/package.json +6 -4
- package/templates/agent-kit/agent-kit.yaml +1 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +15 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +3 -2
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +6 -2
- package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +22 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +7 -1
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/testing-playbook.md +117 -0
- package/templates/agent-kit/skills/shared/interaction.md +83 -0
- package/templates/agent-kit/skills/shared/status.md +3 -12
- package/templates/applications/builder-api/application.yaml +1 -1
- package/templates/applications/builder-api/env.template +5 -1
- package/templates/applications/dataplane/application.yaml +2 -2
- package/templates/applications/dataplane/env.template +10 -12
- package/templates/applications/integration-server/application.yaml +91 -0
- package/templates/applications/integration-server/env.template +215 -0
- package/templates/applications/keycloak/application.yaml +6 -1
- package/templates/applications/mirrored-templates.json +52 -0
- package/templates/applications/miso-controller/application.yaml +116 -2
- package/templates/applications/miso-controller/env.template +62 -17
- package/templates/applications/miso-controller/rbac.yaml +17 -0
- package/templates/external-system/external-datasource.yaml.hbs +7 -1
- package/templates/marketplace/createUiDefinition.json +52 -4
- package/templates/marketplace/main.json +88 -10
- package/templates/python/docker-compose.hbs +1 -1
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +0 -41
- /package/{lib/programmatic/help-content → docs/builder-help/content}/channel-onboarding.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/cip-overview.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/connected-system-ui.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/dimensions-guide.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/enterprise-sync-fabrix.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/overview.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/subscription-guide.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/workflow.md +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Structured choices and phase gates
|
|
2
|
+
|
|
3
|
+
This file owns interactive choices for every Agent Kit skill. Use the same behavior in
|
|
4
|
+
Cursor, Claude, and Codex; host-specific tool names do not change the workflow.
|
|
5
|
+
|
|
6
|
+
## Show choices in the host control
|
|
7
|
+
|
|
8
|
+
When the user must choose between discrete actions, invoke the host's native structured
|
|
9
|
+
question control instead of printing a `Choose:` block in chat:
|
|
10
|
+
|
|
11
|
+
| Host | Native control |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Cursor | `AskQuestion` |
|
|
14
|
+
| Claude | `AskUserQuestion` |
|
|
15
|
+
| Codex | `request_user_input` |
|
|
16
|
+
|
|
17
|
+
Give the control a short header, one direct question, and mutually exclusive options.
|
|
18
|
+
Put the recommended option first, label it `(Recommended)`, and add one short description
|
|
19
|
+
of its effect. Keep the stable option ids below as the workflow result even when a host
|
|
20
|
+
returns a label rather than an id.
|
|
21
|
+
|
|
22
|
+
If the host supplies its own free-form **Other** choice, map that response to the matching
|
|
23
|
+
`*-other` id. Otherwise include an explicit **Something else** option. If no structured
|
|
24
|
+
question control is available, show the same choices as a numbered list and wait for one
|
|
25
|
+
answer. Never continue merely because an option was recommended.
|
|
26
|
+
|
|
27
|
+
Do not open a control when the user already made an unambiguous choice in the current
|
|
28
|
+
turn. Treat that choice exactly like the corresponding control result.
|
|
29
|
+
|
|
30
|
+
## Bare-invocation routes
|
|
31
|
+
|
|
32
|
+
Ask once and proceed only on an explicit choice.
|
|
33
|
+
|
|
34
|
+
| Option id | Control label | Means |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `route-normal` | Run normal path (Recommended) | Run the normal path for this skill through to its gate, stopping at each phase gate |
|
|
37
|
+
| `route-check` | Inspect and test only | Run validation, checks, and status with no publish or promotion |
|
|
38
|
+
| `route-other` | Something else | Collect the action in the control's free-form response |
|
|
39
|
+
| `next-stop` | Stop here | End without further action |
|
|
40
|
+
|
|
41
|
+
`route-normal` still stops at every phase gate and still needs `next-yes` to continue. It
|
|
42
|
+
is a route, not permission to run the whole lifecycle unattended.
|
|
43
|
+
|
|
44
|
+
## After success
|
|
45
|
+
|
|
46
|
+
Offer the next eligible phase with the structured question control. Proceed only on
|
|
47
|
+
`next-yes`.
|
|
48
|
+
|
|
49
|
+
Shared option ids: `next-yes` · `next-no` · `next-stop`.
|
|
50
|
+
|
|
51
|
+
| Completed | Next offer |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| aifabrix-plan PLAN_READY | connected-system validate |
|
|
54
|
+
| connected-system READY | connected-system build |
|
|
55
|
+
| connected-system BUILT | connected-system publish |
|
|
56
|
+
| connected-system PASS or PASS_WITH_SKIPS | archive (separate) and/or prove validate |
|
|
57
|
+
| prove READY / BUILT / UPDATED | prove next phase |
|
|
58
|
+
| prove PASS or PASS_WITH_SKIPS | iterate validate/build |
|
|
59
|
+
|
|
60
|
+
Archive is a distinct user decision (`archive-yes` / `archive-no`). Never archive as a
|
|
61
|
+
side effect of PASS.
|
|
62
|
+
|
|
63
|
+
## On gaps
|
|
64
|
+
|
|
65
|
+
- NEEDS_DECISIONS: ask about every challenge row with the structured control. No
|
|
66
|
+
`cust-next`.
|
|
67
|
+
- BLOCKED / FAIL / NEEDS_FIXES / ABORTED: do not offer the next phase as if success.
|
|
68
|
+
|
|
69
|
+
A phase gate is per-gate, not overall. Offer the next phase only when the **Delivery** row
|
|
70
|
+
supports it; a passing package gate beside `Delivery: NEEDS_FIXES` is not success and the
|
|
71
|
+
offer must name what is still open.
|
|
72
|
+
|
|
73
|
+
## Phase detection (connected-system and prove)
|
|
74
|
+
|
|
75
|
+
1. Explicit phase from the user
|
|
76
|
+
2. Ask with the structured control, offering the bare-invocation routes above
|
|
77
|
+
|
|
78
|
+
There is no third step. Package and plan state decide what you *recommend*, never what you
|
|
79
|
+
run: a bare invocation reports status and stops ([status.md](status.md)). Inferring "the
|
|
80
|
+
safe next eligible phase" is what makes a skill start working before the user has said
|
|
81
|
+
what they want.
|
|
82
|
+
|
|
83
|
+
Never silently run the following phase after success.
|
|
@@ -25,18 +25,9 @@ they cannot see coming.
|
|
|
25
25
|
|
|
26
26
|
## Offer the route, do not choose it
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| --- | --- |
|
|
32
|
-
| `route-normal` | Run the normal path for this skill through to its gate, stopping at each phase gate |
|
|
33
|
-
| `route-check` | Inspect and test only — validation, checks and status, no publish or promotion |
|
|
34
|
-
| `route-other` | Something else; ask what |
|
|
35
|
-
| `next-stop` | Stop here |
|
|
36
|
-
|
|
37
|
-
`route-normal` still stops at every phase gate and still needs `next-yes` to continue
|
|
38
|
-
([interaction.md](../aifabrix-plan/references/interaction.md)). It is a route, not a
|
|
39
|
-
licence to run the whole lifecycle unattended.
|
|
28
|
+
Use the host's native selection control and the canonical route options in
|
|
29
|
+
[interaction.md](interaction.md). Proceed only on an explicit choice. Do not print a
|
|
30
|
+
`Choose:` block when a structured question control is available.
|
|
40
31
|
|
|
41
32
|
## Always report the combined matrix
|
|
42
33
|
|
|
@@ -5,7 +5,7 @@ app:
|
|
|
5
5
|
description: 'Business Transformation services — HTTP orchestration for connected-system workspace lifecycle via Dataplane Enterprise MCP and governance APIs.'
|
|
6
6
|
type: webapp
|
|
7
7
|
language: typescript
|
|
8
|
-
version: 2.
|
|
8
|
+
version: 2.62.0
|
|
9
9
|
|
|
10
10
|
# Image Configuration
|
|
11
11
|
image:
|
|
@@ -23,11 +23,15 @@ MAX_UPLOAD_TIMEOUT_MS=300000
|
|
|
23
23
|
# =============================================================================
|
|
24
24
|
# url:// resolves after kv:// at resolve time (see docs/configuration/resolve-running-urls.md)
|
|
25
25
|
|
|
26
|
+
# Governed configuration uses per-application client credentials by default. The SDK loads
|
|
27
|
+
# its bootstrap snapshot and refreshes it automatically within two minutes; consumers decide
|
|
28
|
+
# whether a changed key also requires an internal client or resource to be recreated.
|
|
29
|
+
MISO_AUTH_MODE=client-credentials
|
|
26
30
|
# Registered OAuth client (populated by aifabrix app register / bootstrap — same as dataplane)
|
|
27
31
|
MISO_CLIENTID=kv://builder-api-client-idKeyVault
|
|
28
32
|
MISO_CLIENTSECRET=kv://builder-api-client-secretKeyVault
|
|
29
33
|
|
|
30
|
-
#
|
|
34
|
+
# Private service-to-service controller origin. Public or remote controller origins require HTTPS.
|
|
31
35
|
MISO_CONTROLLER_URL=url://miso-controller-internal
|
|
32
36
|
# Public: OAuth profile and remaining-step links shown to vendors (not Docker DNS)
|
|
33
37
|
MISO_CONTROLLER_PUBLIC_URL=url://miso-controller-public
|
|
@@ -5,7 +5,7 @@ app:
|
|
|
5
5
|
description: "AI Fabrix Dataplane is a secure, in-tenant integration and automation layer that supplies governed, normalized, and explainable enterprise data to AI agents. Using CIP as a declarative standard, it enforces RBAC and ABAC, executes integrations, and exposes trusted data via MCP and OpenAPI."
|
|
6
6
|
type: webapp
|
|
7
7
|
language: python # Explicitly specify Python language
|
|
8
|
-
version: 2.0.
|
|
8
|
+
version: 2.0.82
|
|
9
9
|
# Image Configuration
|
|
10
10
|
# Set tag to match your build (example: aifabrix build dataplane -t 1.0.0).
|
|
11
11
|
# Registry is required so the controller can pull the image (avoids docker-not-found on the controller host).
|
|
@@ -26,7 +26,7 @@ frontDoorRouting:
|
|
|
26
26
|
pattern: /data/*
|
|
27
27
|
enabled: true
|
|
28
28
|
# Docker url://internal full URLs: http://dataplane:PORT only (ingress /data is not on in-container routes).
|
|
29
|
-
internalDockerUseOriginOnly:
|
|
29
|
+
internalDockerUseOriginOnly: true
|
|
30
30
|
host: ${DEV_USERNAME}.${REMOTE_HOST}
|
|
31
31
|
tls: ${TLS_ENABLED}
|
|
32
32
|
# Origin RFC 9728 PRM (outside /data PathPrefix) — Builder Traefik pass-through (plan 171.0).
|
|
@@ -44,7 +44,7 @@ API_KEY_BYPASS_ROLES=full-access
|
|
|
44
44
|
|
|
45
45
|
# API Configuration
|
|
46
46
|
API_V1_STR=/api/v1
|
|
47
|
-
VERSION=2.0.
|
|
47
|
+
VERSION=2.0.82
|
|
48
48
|
# Minimum supported aifabrix-builder CLI semver (advertised on /health and /api/v1/health; empty = no gate)
|
|
49
49
|
# MIN_BUILDER_CLI_VERSION=2.45.0
|
|
50
50
|
MIN_BUILDER_CLI_VERSION=2.45.5
|
|
@@ -137,21 +137,18 @@ ABAC_POLICY_PARSE_CACHE_MAX_ENTRIES=2048
|
|
|
137
137
|
# AUTHENTICATION CONFIGURATION
|
|
138
138
|
# =============================================================================
|
|
139
139
|
|
|
140
|
-
# MISO
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
# Rotation: changed names are reread from the SDK; DB/Redis pools are disposed and
|
|
147
|
-
# the process reports secretRotationRestartRequired until restarted. Invalidation
|
|
148
|
-
# (denial/expiry) stops new secret-dependent work and makes health unhealthy.
|
|
140
|
+
# MISO governed configuration runtime (583.0): client credentials are active by default.
|
|
141
|
+
# The SDK uses the per-application credentials below to load its bootstrap snapshot and
|
|
142
|
+
# refreshes it automatically within two minutes. Changed names invoke application refresh
|
|
143
|
+
# handlers; a handler may still recreate an internal resource such as a DB or Redis client.
|
|
144
|
+
# Override with MISO_AUTH_MODE=local only for an explicit .env/dotenv development flow.
|
|
145
|
+
# Invalidation (denial/expiry) stops new secret-dependent work and makes health unhealthy.
|
|
149
146
|
# Health: /health, /api/v1/health and /api/v1/health/platform return HTTP 503 with
|
|
150
147
|
# reasonCode misoTokenUnavailable | misoTokenRejected | misoControllerUnreachable |
|
|
151
148
|
# misoValidationTimeout whenever the Controller does not accept the live client
|
|
152
149
|
# token — in LOCAL_MODE too. These endpoints measure usable application health,
|
|
153
150
|
# not process liveness.
|
|
154
|
-
MISO_AUTH_MODE=
|
|
151
|
+
MISO_AUTH_MODE=client-credentials
|
|
155
152
|
# MISO Application Client Credentials (per application)
|
|
156
153
|
# Backend-only: never expose MISO_CLIENTSECRET to the Vite frontend (use VITE_* in app-ui).
|
|
157
154
|
MISO_CLIENTID=kv://dataplane-client-idKeyVault
|
|
@@ -167,7 +164,8 @@ KEYCLOAK_REALM=aifabrix
|
|
|
167
164
|
# =============================================================================
|
|
168
165
|
# Public: browser redirects and CORS (includes /controller front-door path from miso-controller application.yaml).
|
|
169
166
|
MISO_WEB_SERVER_URL=url://miso-controller-public
|
|
170
|
-
#
|
|
167
|
+
# Private service-to-service controller origin. The SDK permits HTTP only for a local/private
|
|
168
|
+
# target; public or remote controller origins still require HTTPS.
|
|
171
169
|
MISO_CONTROLLER_URL=url://miso-controller-internal
|
|
172
170
|
# Browser logout page on miso-controller (path relative to MISO_WEB_SERVER_URL; not dataplane /login).
|
|
173
171
|
MISO_LOGOUT_URL=/logout
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# AI Fabrix Builder app config — INTEGRATOR server type.
|
|
2
|
+
#
|
|
3
|
+
# Same code as builder/builder-server/, different installation. One source tree, two
|
|
4
|
+
# manifests: the Dockerfile's `integrator` target and this folder's env.template are the
|
|
5
|
+
# only things that differ, so there is no forked codebase to keep in step.
|
|
6
|
+
#
|
|
7
|
+
# Enterprise is the existing full development box with Docker. Integrator is a single
|
|
8
|
+
# container giving developers SSH-only access, with no Docker execution inside it.
|
|
9
|
+
|
|
10
|
+
app:
|
|
11
|
+
key: integration-server
|
|
12
|
+
displayName: AI Fabrix Integration Server
|
|
13
|
+
description: AI Fabrix Integration Server onboards developers over SSH into one container. It creates their Linux accounts and authorized keys, and gives them SSH-only access without Docker inside that container.
|
|
14
|
+
type: webapp
|
|
15
|
+
version: 2.0.10
|
|
16
|
+
image:
|
|
17
|
+
name: aifabrix/integration-server
|
|
18
|
+
tag: latest
|
|
19
|
+
registry: aifabrixacr.azurecr.io
|
|
20
|
+
registryMode: external
|
|
21
|
+
# Base 3006 keeps it clear of builder-server (3002), dataplane (3001), mori-controller
|
|
22
|
+
# (3004) and builder-api (3005), so both server types can run on one dev host.
|
|
23
|
+
# Builder derives the host port as `port` + developerId * 100 (dev01 -> 3106).
|
|
24
|
+
port: 3006
|
|
25
|
+
webSocketsEnabled: true
|
|
26
|
+
# This container administers its own operating system: it creates the developers'
|
|
27
|
+
# Linux accounts, writes /etc/ssh/authorized_keys.d and runs sshd. Builder otherwise
|
|
28
|
+
# runs containers as the invoking host user, which cannot do any of that.
|
|
29
|
+
runAsRoot: true
|
|
30
|
+
# Developers reach this installation over SSH, so that port has to be published as well
|
|
31
|
+
# as the HTTP one. The base keeps SSH's well-known number and the published port follows
|
|
32
|
+
# the same formula as the main port — 22 + developerId * 100 — so dev01 gets 122 and two
|
|
33
|
+
# developers on one host cannot collide. Bootstrap advertises it via SSH_PUBLIC_PORT.
|
|
34
|
+
additionalPorts:
|
|
35
|
+
- name: ssh
|
|
36
|
+
containerPort: 22
|
|
37
|
+
hostPort: 22
|
|
38
|
+
requires:
|
|
39
|
+
database: false
|
|
40
|
+
redis: false
|
|
41
|
+
storage: true
|
|
42
|
+
build:
|
|
43
|
+
language: typescript
|
|
44
|
+
context: ../..
|
|
45
|
+
dockerfile: builder/builder-server/Dockerfile
|
|
46
|
+
# Selects the Dockerfile's integrator stage. Without it Docker builds the last stage,
|
|
47
|
+
# which is enterprise — the same image under a different name. This is the one build
|
|
48
|
+
# difference between the two installations.
|
|
49
|
+
target: integrator
|
|
50
|
+
# No envOutputPath: this installation only runs in Docker, and Builder treats the
|
|
51
|
+
# value as a directory — pointing it at a file name creates a folder of that name.
|
|
52
|
+
#
|
|
53
|
+
# Reload runs the real entrypoint, not a bare watcher. The generated compose bind-mounts
|
|
54
|
+
# the repository over /app and clears the image ENTRYPOINT, which for this installation
|
|
55
|
+
# meant no sshd, no account-ops worker, and the API running as root — so nothing about
|
|
56
|
+
# SSH, provisioning or privilege separation worked in the mode developers actually use,
|
|
57
|
+
# and a queued account was never created. The entrypoint finds the build itself —
|
|
58
|
+
# /app/dist in the image, /app/builder-server/dist under the bind mount — because the
|
|
59
|
+
# compose template HTML-escapes `=`, so a VAR=value prefix never survives as an
|
|
60
|
+
# assignment.
|
|
61
|
+
#
|
|
62
|
+
# The API therefore starts from the host's build, so a code change is
|
|
63
|
+
# `npm run build --prefix builder-server` and a restart, not an in-container watch. That
|
|
64
|
+
# is deliberate: the watcher ran as root and left root-owned dist/ behind, which then
|
|
65
|
+
# broke the next `pnpm check` on the host.
|
|
66
|
+
reloadStart: exec /docker-entrypoint-integrator.sh
|
|
67
|
+
# Ingress. A distinct prefix from builder-server's /server/*, which is not cosmetic: the
|
|
68
|
+
# two installation types are alternatives in production, but a development host runs both,
|
|
69
|
+
# and two applications declaring the same host and prefix collide. Traefik then routes the
|
|
70
|
+
# prefix to whichever container was created last, so integrator-only routes answer 404
|
|
71
|
+
# from the enterprise container — a failure that looks like a bug in the route rather than
|
|
72
|
+
# a collision in the manifests.
|
|
73
|
+
#
|
|
74
|
+
# The pattern is a PathPrefix, not an allowlist: it forwards every path beneath it, so the
|
|
75
|
+
# application refuses anything else that arrives through the front door. Filtering at the
|
|
76
|
+
# ingress is still required and is tracked as open in 029 V4.
|
|
77
|
+
frontDoorRouting:
|
|
78
|
+
pattern: /integrator/*
|
|
79
|
+
enabled: true
|
|
80
|
+
host: ${DEV_USERNAME}.${REMOTE_HOST}
|
|
81
|
+
tls: ${TLS_ENABLED}
|
|
82
|
+
internalDockerUseOriginOnly: true
|
|
83
|
+
repository:
|
|
84
|
+
enabled: false
|
|
85
|
+
repositoryUrl: ''
|
|
86
|
+
deployment:
|
|
87
|
+
controllerUrl: ''
|
|
88
|
+
environment: dev
|
|
89
|
+
healthCheck:
|
|
90
|
+
path: /health
|
|
91
|
+
interval: 30
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Integration Server — INTEGRATOR installation
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# A single managed container giving developers SSH-only access, with no Docker
|
|
4
|
+
# execution inside it. Identity and configuration are pushed in by Miso; secrets
|
|
5
|
+
# come from the secret store, not from this container's filesystem.
|
|
6
|
+
#
|
|
7
|
+
# The enterprise installation is a different manifest with its own template —
|
|
8
|
+
# builder/builder-server/env.template. Same code, different deployment; each
|
|
9
|
+
# template lists only the variables its own installation reads.
|
|
10
|
+
#
|
|
11
|
+
# Conventions (as used across AI Fabrix apps):
|
|
12
|
+
# kv://name secret resolved from the secret store — never a literal here
|
|
13
|
+
# url://name URL derived by Builder from the manifest
|
|
14
|
+
# ${VAR} value supplied per environment
|
|
15
|
+
|
|
16
|
+
# =============================================================================
|
|
17
|
+
# CORE
|
|
18
|
+
# =============================================================================
|
|
19
|
+
|
|
20
|
+
# HTTP listen port (main.ts). Default: 3006
|
|
21
|
+
PORT=3006
|
|
22
|
+
|
|
23
|
+
# SQLite DB, audit log and managed state.
|
|
24
|
+
#
|
|
25
|
+
# A subdirectory of the mount, not its root: this is a separate installation with its
|
|
26
|
+
# own database, users and identity model. On a dev host running both side by side the
|
|
27
|
+
# bind mount is shared, and pointing both at the root would have each read the other's
|
|
28
|
+
# database — which fails closed, because the recorded server type would not match.
|
|
29
|
+
DATA_DIR=/mnt/data/integrator
|
|
30
|
+
|
|
31
|
+
# Installation type (config/server-type.ts), resolved once at startup and then
|
|
32
|
+
# persisted in builder.db. This installation IS an integrator, so it is set
|
|
33
|
+
# explicitly: unset would mean enterprise. A populated installation cannot switch
|
|
34
|
+
# type on a restart — that needs a migration.
|
|
35
|
+
BUILDER_SERVER_TYPE=integrator
|
|
36
|
+
|
|
37
|
+
# Set false or 0 to disable DATA_DIR/audit.log (audit.service.ts). Default: true
|
|
38
|
+
# AUDIT_LOG_ENABLED=true
|
|
39
|
+
|
|
40
|
+
# =============================================================================
|
|
41
|
+
# SECRETS
|
|
42
|
+
# =============================================================================
|
|
43
|
+
|
|
44
|
+
# AES-GCM key for the secrets API, as a value from the secret store — this
|
|
45
|
+
# installation has no host filesystem to mount a key file from.
|
|
46
|
+
# 64 hex characters or 32 bytes.
|
|
47
|
+
#
|
|
48
|
+
# Generate a NEW key when installing this server. Never point this at the platform's
|
|
49
|
+
# own key — Miso's, or the enterprise Builder Server's ENCRYPTION_KEY_PATH file.
|
|
50
|
+
# Installing a customer's integrator with the platform key would let every developer
|
|
51
|
+
# with a shell in that container decrypt every other installation's secrets, because
|
|
52
|
+
# the same key is handed to each of them in their config.yaml. One installation, one
|
|
53
|
+
# key: the blast radius of a leaked key is then that installation and nothing else.
|
|
54
|
+
#
|
|
55
|
+
# openssl rand -hex 32
|
|
56
|
+
#
|
|
57
|
+
# The name follows the catalog's own `{appKey}-secrets-encryptionKeyVault` convention,
|
|
58
|
+
# so it is this application's app-scoped secret and nothing else's. The earlier name said
|
|
59
|
+
# `builder-server`: that is another application's key, and reading it from here would be
|
|
60
|
+
# a cross-application read that only works by being deliberately shared — which is the
|
|
61
|
+
# hole this avoids. Register it at install:
|
|
62
|
+
#
|
|
63
|
+
# aifabrix secret set integration-server-secrets-encryptionKeyVault "$(openssl rand -hex 32)"
|
|
64
|
+
#
|
|
65
|
+
# The same key is written into every managed developer's config.yaml as
|
|
66
|
+
# `secrets-encryption`, so the CLI can decrypt what this server encrypted. Those two
|
|
67
|
+
# are one value from one source by construction — see account-ops-worker.ts, which
|
|
68
|
+
# resolves it from this variable at the moment it writes the file. Rotating it means
|
|
69
|
+
# re-running configuration sync so the homes are rewritten; values already stored in
|
|
70
|
+
# the secrets table are encrypted with the old key and do not survive a rotation.
|
|
71
|
+
ENCRYPTION_KEY=kv://integration-server-secrets-encryptionKeyVault
|
|
72
|
+
|
|
73
|
+
# =============================================================================
|
|
74
|
+
# MISO
|
|
75
|
+
# =============================================================================
|
|
76
|
+
# Where identity and configuration come from. Builder Server knows Miso only: it
|
|
77
|
+
# never configures or verifies the identity provider — miso-client owns that.
|
|
78
|
+
# /health carries a `miso` check on this installation, and fails without these.
|
|
79
|
+
|
|
80
|
+
# Server-to-controller API calls on the environment network.
|
|
81
|
+
MISO_CONTROLLER_URL=url://miso-controller-internal
|
|
82
|
+
|
|
83
|
+
# Application client credentials, used to obtain an application token and to verify
|
|
84
|
+
# the client tokens on POST /api/integrations/miso/*.
|
|
85
|
+
MISO_CLIENTID=kv://integration-server-client-idKeyVault
|
|
86
|
+
MISO_CLIENTSECRET=kv://integration-server-client-secretKeyVault
|
|
87
|
+
|
|
88
|
+
# Reachable addresses reported to Miso after the HTTP listener starts. Miso uses the
|
|
89
|
+
# internal address for user/configuration delivery and exposes the public address in
|
|
90
|
+
# application status. Keep these derived from the manifest, like Dataplane's status
|
|
91
|
+
# registration; a typed hostname or port drifts in local developer environments.
|
|
92
|
+
INTEGRATION_SERVER_WEB_SERVER_URL=url://public
|
|
93
|
+
INTEGRATION_SERVER_INTERNAL_URL=url://internal
|
|
94
|
+
|
|
95
|
+
# The `environment` value written into each developer's ~/.aifabrix/config.yaml.
|
|
96
|
+
# `controller` and `codingPlatform` are pushed by Miso; this one is the
|
|
97
|
+
# installation's own deployment configuration and is never taken from the request.
|
|
98
|
+
MANAGED_CONFIG_ENVIRONMENT=dev
|
|
99
|
+
MISO_ENVIRONMENT=dev
|
|
100
|
+
|
|
101
|
+
# =============================================================================
|
|
102
|
+
# DEVELOPER ACCESS — SSH
|
|
103
|
+
# =============================================================================
|
|
104
|
+
|
|
105
|
+
# SSH endpoint returned to enrolling developers by POST /api/bootstrap/ssh.
|
|
106
|
+
#
|
|
107
|
+
# This is what the client is told to connect to, so it must be the address that is
|
|
108
|
+
# actually reachable, not the container's own view. Both are derived rather than typed:
|
|
109
|
+
# the host from the front door, and the port from the `ssh` entry in the manifest's
|
|
110
|
+
# `additionalPorts` (Builder publishes it as SSH_PUBLIC_PORT = hostPort + developerId *
|
|
111
|
+
# 100). Typing either by hand drifts from the manifest and advertises an endpoint
|
|
112
|
+
# nothing is listening on.
|
|
113
|
+
INTEGRATOR_SSH_HOST=url://public
|
|
114
|
+
INTEGRATOR_SSH_PORT=${SSH_PUBLIC_PORT}
|
|
115
|
+
|
|
116
|
+
# Where sshd reads each developer's authorized keys from.
|
|
117
|
+
#
|
|
118
|
+
# State, not configuration: it records which key each developer enrolled. Kept in the
|
|
119
|
+
# image it was destroyed by every redeploy, and although reconciliation rebuilds it from
|
|
120
|
+
# the database at startup, a developer reconnecting before that finishes is refused.
|
|
121
|
+
# On the volume the file is already correct when sshd starts.
|
|
122
|
+
#
|
|
123
|
+
# Root-owned, inside a directory developers cannot write to.
|
|
124
|
+
# Default: ${DATA_DIR}/authorized_keys.d
|
|
125
|
+
# AUTHORIZED_KEYS_DIR=/mnt/data/integrator/authorized_keys.d
|
|
126
|
+
|
|
127
|
+
# Root of the managed developer home directories.
|
|
128
|
+
#
|
|
129
|
+
# Must be on the persistent volume. A managed home is not scratch space: it holds the
|
|
130
|
+
# developer's cloned repositories and build trees, the credentials their agent uses, the
|
|
131
|
+
# managed config.yaml and the client certificate this server issued. An agent run takes
|
|
132
|
+
# hours and outlives any single connection, so the work has to survive a redeploy.
|
|
133
|
+
#
|
|
134
|
+
# Inside the image it did not. Every redeploy destroyed the homes, which silently revoked
|
|
135
|
+
# access as well as losing the work: the Linux accounts and their authorized_keys went
|
|
136
|
+
# with them, while the projection in builder.db still said the developer was entitled.
|
|
137
|
+
#
|
|
138
|
+
# The entrypoint creates this root 755 and grants traverse on the path leading to it;
|
|
139
|
+
# each developer's own home inside is 700 and owned by them.
|
|
140
|
+
# Default: ${DATA_DIR}/home
|
|
141
|
+
# DEVELOPER_HOME_ROOT=/mnt/data/integrator/home
|
|
142
|
+
|
|
143
|
+
# Restores keys even though the projection has gone backwards.
|
|
144
|
+
#
|
|
145
|
+
# This installation records the highest Miso revision it has ever seen, outside the
|
|
146
|
+
# database, so restoring builder.db from before a revocation is detectable: the mark is
|
|
147
|
+
# higher than anything the projection now holds. When that happens the installation fails
|
|
148
|
+
# closed — every developer is reconciled to no keys until Miso re-synchronises a revision
|
|
149
|
+
# at least as high as the one already seen. Homes are retained and the server still boots,
|
|
150
|
+
# so it can be repaired.
|
|
151
|
+
#
|
|
152
|
+
# A database rebuilt deliberately looks identical to one restored from before a
|
|
153
|
+
# revocation, so this is the way past it. Set it only when you know the rebuild was
|
|
154
|
+
# intended; it is logged when used. Only the exact value `true` is accepted.
|
|
155
|
+
# ONBOARDING_ALLOW_BACKWARDS_PROJECTION=true
|
|
156
|
+
|
|
157
|
+
# =============================================================================
|
|
158
|
+
# CLIENT DOWNLOAD
|
|
159
|
+
# =============================================================================
|
|
160
|
+
# What GET /client/<target>.zip writes into the aifabrix.json beside the executable.
|
|
161
|
+
#
|
|
162
|
+
# The executable itself is identical for every installation — SmartScreen builds
|
|
163
|
+
# reputation against a file hash, so a per-customer binary would never accumulate any.
|
|
164
|
+
# The customer scope travels in this small file instead.
|
|
165
|
+
|
|
166
|
+
# Platform origin the client posts its SSH key to. Only the origin is used; the client
|
|
167
|
+
# appends its own path, so a value carrying /server would double it.
|
|
168
|
+
CLIENT_PLATFORM_URL=url://public
|
|
169
|
+
|
|
170
|
+
# Controller the client signs in against, as a browser reaches it.
|
|
171
|
+
CLIENT_CONTROLLER_URL=url://miso-controller-public
|
|
172
|
+
|
|
173
|
+
# Shown while onboarding, e.g. "Acme Corp". Optional.
|
|
174
|
+
# CLIENT_DISPLAY_NAME=
|
|
175
|
+
|
|
176
|
+
# How this installation is reached: `ssh` or `wss`. Exactly one is served.
|
|
177
|
+
#
|
|
178
|
+
# ssh Developers reach sshd over a private network overlay, which is the only route to
|
|
179
|
+
# the port — this installation must not publish 22 publicly. Deactivating a person
|
|
180
|
+
# in the overlay removes their route, and that is what ends access, including for
|
|
181
|
+
# sessions already open. The tunnel endpoint does not exist.
|
|
182
|
+
#
|
|
183
|
+
# wss There is no overlay: the session travels inside a WebSocket on the published
|
|
184
|
+
# HTTPS port, and sshd listens on loopback only, so the tunnel is the only way in.
|
|
185
|
+
# This server does the authorizing — a short-lived token at the open, refreshed
|
|
186
|
+
# over the tunnel while the developer works, and dropped on idle or revocation.
|
|
187
|
+
#
|
|
188
|
+
# Not both. Publishing 22 alongside the tunnel would make the overlay stop being a
|
|
189
|
+
# control, and running both against one sshd means "does this person still have access?"
|
|
190
|
+
# depends on which door they used — with the door that fails open deciding.
|
|
191
|
+
#
|
|
192
|
+
# Stated by the server because the server knows how it is published; the client reads it
|
|
193
|
+
# from aifabrix.json and never has to guess. Guessing wrong fails as a timeout, which is
|
|
194
|
+
# the least diagnosable failure there is.
|
|
195
|
+
CLIENT_TRANSPORT=wss
|
|
196
|
+
|
|
197
|
+
# =============================================================================
|
|
198
|
+
# FRONT DOOR
|
|
199
|
+
# =============================================================================
|
|
200
|
+
# The application is published whole at its virtual directory, the same way
|
|
201
|
+
# miso-controller serves /miso and dataplane serves /data. What is reachable from
|
|
202
|
+
# outside is decided by `frontDoorRouting` in application.yaml and by the ingress.
|
|
203
|
+
|
|
204
|
+
# Injected by Builder from `frontDoorRouting.pattern` in application.yaml; listed
|
|
205
|
+
# because the app reads it. Routes are served unprefixed — the ingress strips the
|
|
206
|
+
# prefix before the request arrives — so this only builds URLs handed to clients.
|
|
207
|
+
# BASE_PATH=/integrator
|
|
208
|
+
# X_FORWARDED_PREFIX=/integrator
|
|
209
|
+
|
|
210
|
+
# =============================================================================
|
|
211
|
+
# TESTING
|
|
212
|
+
# =============================================================================
|
|
213
|
+
|
|
214
|
+
# Enables POST /api/dev/e2e-reset. Never set in production.
|
|
215
|
+
# E2E_RESET_SECRET=
|
|
@@ -9,7 +9,12 @@ app:
|
|
|
9
9
|
# Image Configuration
|
|
10
10
|
image:
|
|
11
11
|
name: aifabrix/keycloak
|
|
12
|
-
|
|
12
|
+
# `latest`, like every other app here. The Keycloak version lives in app.version above,
|
|
13
|
+
# which is what `aifabrix push --tag 'latest,{version}'` expands, so nothing is lost by
|
|
14
|
+
# not repeating it here. Pinning it made `aifabrix run` look for keycloak-dev1:<version>
|
|
15
|
+
# while `aifabrix build` only ever produces :latest, so dev-build-kc failed with
|
|
16
|
+
# "Docker image not found" on an image it had just built.
|
|
17
|
+
tag: latest
|
|
13
18
|
registry: aifabrixacr.azurecr.io
|
|
14
19
|
registryMode: external
|
|
15
20
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mirrors": [
|
|
3
|
+
{
|
|
4
|
+
"path": "templates/applications/miso-controller/env.template",
|
|
5
|
+
"master": {
|
|
6
|
+
"repo": "aifabrix-miso",
|
|
7
|
+
"path": "builder/miso-controller/env.template"
|
|
8
|
+
},
|
|
9
|
+
"sha256": "9b74b94d5d6e7457d22cfe213f2ec9c3dceb75c540df3953aba3b51c35df05c7"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"path": "templates/applications/builder-api/env.template",
|
|
13
|
+
"master": {
|
|
14
|
+
"repo": "aifabrix-miso",
|
|
15
|
+
"path": "builder/builder-api/env.template"
|
|
16
|
+
},
|
|
17
|
+
"sha256": "1a6b013aa0a34b72c5a0be3dd714bd718a8adb981bcbb9de3d5370e2dd33786c"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "templates/applications/keycloak/env.template",
|
|
21
|
+
"master": {
|
|
22
|
+
"repo": "aifabrix-miso",
|
|
23
|
+
"path": "builder/keycloak/env.template"
|
|
24
|
+
},
|
|
25
|
+
"sha256": "72de7dc5345b842bc20566f8d5105b6541e8185dff157e9af2d37db9590b01fb"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": "templates/applications/dataplane/env.template",
|
|
29
|
+
"master": {
|
|
30
|
+
"repo": "aifabrix-dataplane",
|
|
31
|
+
"path": "builder/dataplane/env.template"
|
|
32
|
+
},
|
|
33
|
+
"sha256": "d35eda839464a65ebd018064ea7c2d292654891b41d1f56862b052720a78a3cc"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"path": "templates/applications/integration-server/env.template",
|
|
37
|
+
"master": {
|
|
38
|
+
"repo": "aifabrix-setup",
|
|
39
|
+
"path": "builder/integration-server/env.template"
|
|
40
|
+
},
|
|
41
|
+
"sha256": "a80584bcf6880937c43557a71ca1c423104ab4e15badf4bb14a0a9a9dcaa01d6"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "templates/applications/integration-server/application.yaml",
|
|
45
|
+
"master": {
|
|
46
|
+
"repo": "aifabrix-setup",
|
|
47
|
+
"path": "builder/integration-server/application.yaml"
|
|
48
|
+
},
|
|
49
|
+
"sha256": "04cbfdb9a012393a5e97a1dda1b8f304e97c9532339f045e5912cd250a26a179"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|