@aifabrix/builder 2.42.1 → 2.44.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/.cursor/rules/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +19 -8
- package/lib/app/rotate-secret.js +17 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +10 -14
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +16 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +162 -15
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1201 -433
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +29 -7
- package/lib/utils/paths.js +136 -48
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +37 -5
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +55 -14
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared output for `aifabrix status`: title + configuration block.
|
|
3
|
+
* TLS/SSL (`infraTlsSslCell`) and `devNN` title match `dev-show-display.js`; environment, Traefik,
|
|
4
|
+
* and scoped-resources lines use uppercase ON/OFF-style labels for status output.
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Infra status CLI display helpers
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const config = require('../core/config');
|
|
14
|
+
const logger = require('./logger');
|
|
15
|
+
|
|
16
|
+
/** En dash for unset / empty values (same as dev-show-display). */
|
|
17
|
+
const EM = '\u2013';
|
|
18
|
+
const LABEL_W = 18;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {unknown} v
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
function isUnset(v) {
|
|
25
|
+
return v === null || v === undefined || v === '';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {unknown} v
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
function cell(v) {
|
|
33
|
+
return isUnset(v) ? EM : String(v);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} label
|
|
38
|
+
* @param {unknown} value
|
|
39
|
+
*/
|
|
40
|
+
function logPaddedFieldRow(label, value) {
|
|
41
|
+
logger.log(` ${label.padEnd(LABEL_W)} ${cell(value)}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {string|null|undefined} remoteUrl
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
function hostFromRemoteUrl(remoteUrl) {
|
|
49
|
+
if (!remoteUrl || typeof remoteUrl !== 'string') {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const u = new URL(remoteUrl.trim());
|
|
54
|
+
return u.hostname || '';
|
|
55
|
+
} catch {
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} devIdStr
|
|
62
|
+
* @returns {string} e.g. dev02
|
|
63
|
+
*/
|
|
64
|
+
function devProfileHandle(devIdStr) {
|
|
65
|
+
const s = String(devIdStr);
|
|
66
|
+
if (/^[0-9]+$/.test(s)) {
|
|
67
|
+
return `dev${s.padStart(2, '0')}`;
|
|
68
|
+
}
|
|
69
|
+
return `dev${s}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Infra / compose TLS mode from ~/.aifabrix `tlsEnabled` (not Docker TLS verify).
|
|
74
|
+
* @param {boolean} tlsEnabled
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function infraTlsSslCell(tlsEnabled) {
|
|
78
|
+
return tlsEnabled ? 'ON 🔒' : 'OFF 🕐';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Traefik proxy row (`traefik: true` in config). Icons only (no ANSI color).
|
|
83
|
+
* @param {boolean} traefikEnabled
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
function statusTraefikProxyCell(traefikEnabled) {
|
|
87
|
+
return traefikEnabled ? 'ON 🟢' : 'OFF 🟡';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Environment for status (uppercase).
|
|
92
|
+
* @param {unknown} environment
|
|
93
|
+
* @returns {string}
|
|
94
|
+
*/
|
|
95
|
+
function formatStatusEnvironment(environment) {
|
|
96
|
+
if (isUnset(environment)) {
|
|
97
|
+
return EM;
|
|
98
|
+
}
|
|
99
|
+
return String(environment).trim().toUpperCase();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Scoped resources for status: ON vs OFF (DEFAULT).
|
|
104
|
+
* @param {boolean} useScoped
|
|
105
|
+
* @returns {string}
|
|
106
|
+
*/
|
|
107
|
+
function statusScopedResourcesCell(useScoped) {
|
|
108
|
+
return useScoped ? 'ON' : 'OFF (DEFAULT)';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Single-line title for `aifabrix status` (same dev profile + remote host pattern as dev show).
|
|
113
|
+
* @param {string} devIdStr
|
|
114
|
+
* @param {string|null|undefined} remoteServer
|
|
115
|
+
* @returns {string}
|
|
116
|
+
*/
|
|
117
|
+
function formatInfraStatusTitleLine(devIdStr, remoteServer) {
|
|
118
|
+
const who = devProfileHandle(devIdStr);
|
|
119
|
+
const host = hostFromRemoteUrl(remoteServer);
|
|
120
|
+
if (host) {
|
|
121
|
+
return `📊 Infrastructure Status (${who} @ ${host})`;
|
|
122
|
+
}
|
|
123
|
+
return `📊 Infrastructure Status (${who})`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {{ remoteServer: string|null|undefined, tlsEnabled: boolean, environment: unknown, useScoped: boolean, traefikEnabled: boolean }} p
|
|
128
|
+
*/
|
|
129
|
+
function logInfraStatusConfigurationSummary(p) {
|
|
130
|
+
logger.log('⚙️ Configuration');
|
|
131
|
+
logPaddedFieldRow('Server', p.remoteServer);
|
|
132
|
+
logPaddedFieldRow('TLS/SSL', infraTlsSslCell(p.tlsEnabled));
|
|
133
|
+
logPaddedFieldRow('Traefik proxy', statusTraefikProxyCell(p.traefikEnabled));
|
|
134
|
+
logPaddedFieldRow('Environment', formatStatusEnvironment(p.environment));
|
|
135
|
+
logPaddedFieldRow('Scoped resources', statusScopedResourcesCell(p.useScoped));
|
|
136
|
+
logger.log('');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @returns {Promise<{ devIdStr: string, remoteServer: string|null|undefined, tlsEnabled: boolean, environment: unknown, useScoped: boolean, traefikEnabled: boolean }>}
|
|
141
|
+
*/
|
|
142
|
+
async function loadInfraStatusSummary() {
|
|
143
|
+
const [rawDevId, environment, tlsEnabled, remoteServer, useScoped, traefikEnabled] = await Promise.all([
|
|
144
|
+
config.getDeveloperId(),
|
|
145
|
+
config.getCurrentEnvironment(),
|
|
146
|
+
config.getTlsEnabled(),
|
|
147
|
+
config.getRemoteServer(),
|
|
148
|
+
config.getUseEnvironmentScopedResources(),
|
|
149
|
+
config.getTraefikEnabled()
|
|
150
|
+
]);
|
|
151
|
+
const devIdStr = rawDevId === null || rawDevId === undefined ? '0' : String(rawDevId);
|
|
152
|
+
return {
|
|
153
|
+
devIdStr,
|
|
154
|
+
environment,
|
|
155
|
+
tlsEnabled,
|
|
156
|
+
remoteServer,
|
|
157
|
+
useScoped,
|
|
158
|
+
traefikEnabled
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = {
|
|
163
|
+
loadInfraStatusSummary,
|
|
164
|
+
formatInfraStatusTitleLine,
|
|
165
|
+
logInfraStatusConfigurationSummary,
|
|
166
|
+
logPaddedFieldRow
|
|
167
|
+
};
|
|
@@ -9,13 +9,10 @@
|
|
|
9
9
|
* @version 2.0.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const { exec } = require('child_process');
|
|
13
|
-
const { promisify } = require('util');
|
|
14
12
|
const config = require('../core/config');
|
|
15
13
|
const devConfig = require('./dev-config');
|
|
16
14
|
const containerUtils = require('./infra-containers');
|
|
17
|
-
|
|
18
|
-
const execAsync = promisify(exec);
|
|
15
|
+
const { execWithDockerEnv } = require('./docker-exec');
|
|
19
16
|
|
|
20
17
|
/**
|
|
21
18
|
* Builds services config map from ports and config flags.
|
|
@@ -52,7 +49,7 @@ async function getServiceStatus(serviceName, serviceConfig, devId) {
|
|
|
52
49
|
try {
|
|
53
50
|
const containerName = await containerUtils.findContainer(serviceName, devId, { strict: true });
|
|
54
51
|
const rawStatus = containerName
|
|
55
|
-
? (await
|
|
52
|
+
? (await execWithDockerEnv(`docker inspect --format='{{.State.Status}}' ${containerName}`)).stdout.trim().replace(/['"]/g, '')
|
|
56
53
|
: 'not running';
|
|
57
54
|
return { status: rawStatus, port: serviceConfig.port, url: serviceConfig.url };
|
|
58
55
|
} catch {
|
|
@@ -107,6 +104,9 @@ function getInfraContainerNames(devIdNum, devId) {
|
|
|
107
104
|
/** Suffixes for init/helper containers to exclude from "Running Applications" (e.g. keycloak-db-init) */
|
|
108
105
|
const INIT_CONTAINER_SUFFIXES = ['-db-init', '-init'];
|
|
109
106
|
|
|
107
|
+
/** Names like aifabrix-dev02-postgres belong to isolated developer stacks, not legacy dev-0 mode */
|
|
108
|
+
const DEV_PREFIXED_CONTAINER = /^aifabrix-dev\d+-/;
|
|
109
|
+
|
|
110
110
|
/**
|
|
111
111
|
* Extracts app name from container name
|
|
112
112
|
* @param {string} containerName - Container name
|
|
@@ -115,6 +115,9 @@ const INIT_CONTAINER_SUFFIXES = ['-db-init', '-init'];
|
|
|
115
115
|
* @returns {string|null} App name or null if not matched
|
|
116
116
|
*/
|
|
117
117
|
function extractAppName(containerName, devIdNum, devId) {
|
|
118
|
+
if (devIdNum === 0 && DEV_PREFIXED_CONTAINER.test(containerName)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
118
121
|
const pattern = devIdNum === 0 ? /^aifabrix-(.+)$/ : new RegExp(`^aifabrix-dev${devId}-(.+)$`);
|
|
119
122
|
const match = containerName.match(pattern);
|
|
120
123
|
if (!match) return null;
|
|
@@ -176,7 +179,7 @@ async function getAppStatus() {
|
|
|
176
179
|
try {
|
|
177
180
|
const devIdNum = parseInt(devId, 10);
|
|
178
181
|
const filterPattern = devIdNum === 0 ? 'aifabrix-' : `aifabrix-dev${devId}-`;
|
|
179
|
-
const { stdout } = await
|
|
182
|
+
const { stdout } = await execWithDockerEnv(`docker ps --filter "name=${filterPattern}" --format "{{.Names}}\t{{.Ports}}\t{{.Status}}"`);
|
|
180
183
|
const lines = stdout.trim().split('\n').filter(line => line.trim() !== '');
|
|
181
184
|
const infraContainers = getInfraContainerNames(devIdNum, devId);
|
|
182
185
|
for (const line of lines) {
|
|
@@ -211,9 +214,14 @@ async function listAppContainerNamesForDeveloper(devId, options = {}) {
|
|
|
211
214
|
const includeExited = !!options.includeExited;
|
|
212
215
|
try {
|
|
213
216
|
const allFlag = includeExited ? ' -a' : '';
|
|
214
|
-
const { stdout } = await
|
|
217
|
+
const { stdout } = await execWithDockerEnv(`docker ps${allFlag} --filter "name=${filterPattern}" --format "{{.Names}}"`);
|
|
215
218
|
const names = (stdout || '').trim().split('\n').filter(Boolean);
|
|
216
|
-
return names.filter(n =>
|
|
219
|
+
return names.filter(n => {
|
|
220
|
+
if (devIdNum === 0 && DEV_PREFIXED_CONTAINER.test(n)) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
return !infraContainers.includes(n);
|
|
224
|
+
});
|
|
217
225
|
} catch {
|
|
218
226
|
return [];
|
|
219
227
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Local Secrets Management Utilities
|
|
3
3
|
*
|
|
4
|
-
* Helper functions for managing local secrets in
|
|
4
|
+
* Helper functions for managing local secrets in getPrimaryUserSecretsLocalPath() (config dir)
|
|
5
5
|
*
|
|
6
6
|
* @fileoverview Local secrets management utilities
|
|
7
7
|
* @author AI Fabrix Team
|
|
@@ -15,10 +15,30 @@ const logger = require('../utils/logger');
|
|
|
15
15
|
const pathsUtil = require('./paths');
|
|
16
16
|
const { mergeSecretsIntoFile } = require('./secrets-generator');
|
|
17
17
|
|
|
18
|
+
/** Bootstrap key name; never encrypt this key's value when writing (key is stored in config). */
|
|
19
|
+
const ENCRYPTION_KEY_VAULT = 'secrets-encryptionKeyVault';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolves value to write: encrypted (secure://) when encryption key is set and key is not the bootstrap key.
|
|
23
|
+
* @async
|
|
24
|
+
* @param {string} key - Secret key name
|
|
25
|
+
* @param {string} value - Secret value
|
|
26
|
+
* @returns {Promise<string>} Value to write (plaintext or secure://...)
|
|
27
|
+
*/
|
|
28
|
+
async function resolveValueForWrite(key, value) {
|
|
29
|
+
const config = require('../core/config');
|
|
30
|
+
const encryptionKey = await config.getSecretsEncryptionKey();
|
|
31
|
+
if (!encryptionKey || key === ENCRYPTION_KEY_VAULT) {
|
|
32
|
+
return typeof value === 'string' ? value : String(value);
|
|
33
|
+
}
|
|
34
|
+
const { encryptSecret } = require('./secrets-encryption');
|
|
35
|
+
return encryptSecret(typeof value === 'string' ? value : String(value), encryptionKey);
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
/**
|
|
19
|
-
* Saves a secret to
|
|
20
|
-
*
|
|
21
|
-
*
|
|
39
|
+
* Saves a secret to the primary user secrets file (getPrimaryUserSecretsLocalPath)
|
|
40
|
+
* Merges the key into the file (updates in place if key already exists, e.g. after rotate-secret).
|
|
41
|
+
* Encrypts the value when a secrets-encryption key is configured (except for the bootstrap key).
|
|
22
42
|
*
|
|
23
43
|
* @async
|
|
24
44
|
* @function saveLocalSecret
|
|
@@ -39,8 +59,9 @@ async function saveLocalSecret(key, value) {
|
|
|
39
59
|
throw new Error('Secret value is required');
|
|
40
60
|
}
|
|
41
61
|
|
|
42
|
-
const
|
|
43
|
-
|
|
62
|
+
const valueToWrite = await resolveValueForWrite(key, value);
|
|
63
|
+
const secretsPath = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
64
|
+
mergeSecretsIntoFile(secretsPath, { [key]: valueToWrite });
|
|
44
65
|
}
|
|
45
66
|
|
|
46
67
|
/**
|
|
@@ -121,8 +142,9 @@ function _loadExistingSecrets(resolvedPath) {
|
|
|
121
142
|
async function saveSecret(key, value, secretsPath) {
|
|
122
143
|
validateSaveSecretParams(key, value, secretsPath);
|
|
123
144
|
|
|
145
|
+
const valueToWrite = await resolveValueForWrite(key, value);
|
|
124
146
|
const resolvedPath = resolveAndPrepareSecretsPath(secretsPath);
|
|
125
|
-
mergeSecretsIntoFile(resolvedPath, { [key]:
|
|
147
|
+
mergeSecretsIntoFile(resolvedPath, { [key]: valueToWrite });
|
|
126
148
|
}
|
|
127
149
|
|
|
128
150
|
/**
|
package/lib/utils/paths.js
CHANGED
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const yaml = require('js-yaml');
|
|
15
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
16
|
+
const {
|
|
17
|
+
getAifabrixRuntimeConfigDir,
|
|
18
|
+
resolveAifabrixHomeLikePath
|
|
19
|
+
} = require('./aifabrix-runtime-config-dir');
|
|
15
20
|
|
|
16
21
|
function safeHomedir() {
|
|
17
22
|
try {
|
|
@@ -29,30 +34,46 @@ function safeHomedir() {
|
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
|
-
* Returns the path to the config directory (same
|
|
33
|
-
*
|
|
37
|
+
* Returns the path to the config directory (same as {@link getAifabrixRuntimeConfigDir} / config.js).
|
|
38
|
+
* When `AIFABRIX_HOME` is `$HOME` but `config.yaml` is only under `$HOME/.aifabrix/`, returns the latter.
|
|
34
39
|
* @returns {string} Absolute path to config directory
|
|
35
40
|
*/
|
|
36
41
|
function getConfigDirForPaths() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
return getAifabrixRuntimeConfigDir();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* User-owned `secrets.local.yaml` beside effective `config.yaml` (see {@link getConfigDirForPaths}).
|
|
47
|
+
* When `AIFABRIX_HOME` is `$HOME` but config is only at `$HOME/.aifabrix/config.yaml`, uses that folder.
|
|
48
|
+
* Keeps `secret list` / `secret set` aligned with resolve merge (`loadPrimaryUserSecrets`).
|
|
49
|
+
*
|
|
50
|
+
* @returns {string} Absolute path to secrets.local.yaml
|
|
51
|
+
*/
|
|
52
|
+
function getPrimaryUserSecretsLocalPath() {
|
|
53
|
+
return path.join(getConfigDirForPaths(), 'secrets.local.yaml');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Directory for CLI system state next to `config.yaml`: `admin-secrets.env`, `infra/` or `infra-dev{id}/`,
|
|
58
|
+
* `audit.log`, etc. Unlike {@link getAifabrixHome}, this follows the resolved config directory (e.g.
|
|
59
|
+
* `~/.aifabrix` when config lives there even if `aifabrix-home` / `AIFABRIX_HOME` is `$HOME`).
|
|
60
|
+
*
|
|
61
|
+
* @returns {string} Absolute path (same as {@link getConfigDirForPaths})
|
|
62
|
+
*/
|
|
63
|
+
function getAifabrixSystemDir() {
|
|
64
|
+
return getConfigDirForPaths();
|
|
45
65
|
}
|
|
46
66
|
|
|
47
67
|
/**
|
|
48
68
|
* Returns the base AI Fabrix directory.
|
|
49
|
-
* Priority: AIFABRIX_HOME env → config.yaml `aifabrix-home`
|
|
69
|
+
* Priority: AIFABRIX_HOME env → config.yaml `aifabrix-home` → ~/.aifabrix.
|
|
70
|
+
* Builder-server SSH provisioning sets `aifabrix-home` to the user POSIX home; dev `.bashrc` exports AIFABRIX_HOME from that key (default $HOME).
|
|
50
71
|
*
|
|
51
72
|
* @returns {string} Absolute path to the AI Fabrix home directory
|
|
52
73
|
*/
|
|
53
74
|
function getAifabrixHome() {
|
|
54
75
|
if (process.env.AIFABRIX_HOME && typeof process.env.AIFABRIX_HOME === 'string') {
|
|
55
|
-
return
|
|
76
|
+
return resolveAifabrixHomeLikePath(process.env.AIFABRIX_HOME.trim());
|
|
56
77
|
}
|
|
57
78
|
const isTestEnv = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined;
|
|
58
79
|
if (!isTestEnv) {
|
|
@@ -64,7 +85,7 @@ function getAifabrixHome() {
|
|
|
64
85
|
const config = yaml.load(content) || {};
|
|
65
86
|
const homeOverride = config && typeof config['aifabrix-home'] === 'string' ? config['aifabrix-home'].trim() : '';
|
|
66
87
|
if (homeOverride) {
|
|
67
|
-
return
|
|
88
|
+
return resolveAifabrixHomeLikePath(homeOverride);
|
|
68
89
|
}
|
|
69
90
|
}
|
|
70
91
|
} catch {
|
|
@@ -74,6 +95,40 @@ function getAifabrixHome() {
|
|
|
74
95
|
return path.join(safeHomedir(), '.aifabrix');
|
|
75
96
|
}
|
|
76
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Default git / workspace root from env or config (optional; no fallback to aifabrix-home).
|
|
100
|
+
* Priority: AIFABRIX_WORK env (trim, resolve) → config.yaml `aifabrix-work` → null.
|
|
101
|
+
*
|
|
102
|
+
* @returns {string|null} Absolute path or null when unset
|
|
103
|
+
*/
|
|
104
|
+
function getAifabrixWork() {
|
|
105
|
+
if (process.env.AIFABRIX_WORK && typeof process.env.AIFABRIX_WORK === 'string') {
|
|
106
|
+
const t = process.env.AIFABRIX_WORK.trim();
|
|
107
|
+
if (t) {
|
|
108
|
+
return resolveAifabrixHomeLikePath(t);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const isTestEnv = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined;
|
|
112
|
+
if (!isTestEnv) {
|
|
113
|
+
try {
|
|
114
|
+
const configDir = getConfigDirForPaths();
|
|
115
|
+
const configPath = path.join(configDir, 'config.yaml');
|
|
116
|
+
if (fs.existsSync(configPath)) {
|
|
117
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
118
|
+
const config = yaml.load(content) || {};
|
|
119
|
+
const workOverride =
|
|
120
|
+
config && typeof config['aifabrix-work'] === 'string' ? config['aifabrix-work'].trim() : '';
|
|
121
|
+
if (workOverride) {
|
|
122
|
+
return resolveAifabrixHomeLikePath(workOverride);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
// ignore
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
77
132
|
// Cache project root to avoid repeated filesystem lookups
|
|
78
133
|
let cachedProjectRoot = null;
|
|
79
134
|
|
|
@@ -92,7 +147,8 @@ function clearProjectRootCache() {
|
|
|
92
147
|
*/
|
|
93
148
|
function hasPackageJson(dirPath) {
|
|
94
149
|
const packageJsonPath = path.join(dirPath, 'package.json');
|
|
95
|
-
|
|
150
|
+
// Real disk: Jest workers may retain jest.mock('fs') from other suites; project root must stay truthful.
|
|
151
|
+
return nodeFs().existsSync(packageJsonPath);
|
|
96
152
|
}
|
|
97
153
|
|
|
98
154
|
/**
|
|
@@ -215,22 +271,31 @@ function tryFindProjectRoot() {
|
|
|
215
271
|
}
|
|
216
272
|
|
|
217
273
|
function getProjectRoot() {
|
|
218
|
-
//
|
|
274
|
+
// Prefer global.PROJECT_ROOT whenever it is valid so tests that override it (or restore it)
|
|
275
|
+
// are not defeated by a stale cachedProjectRoot from an earlier call in the same Jest worker.
|
|
276
|
+
const globalRoot = checkGlobalProjectRoot();
|
|
277
|
+
if (globalRoot) {
|
|
278
|
+
cachedProjectRoot = globalRoot;
|
|
279
|
+
return globalRoot;
|
|
280
|
+
}
|
|
219
281
|
if (cachedProjectRoot && hasPackageJson(cachedProjectRoot)) {
|
|
220
282
|
return cachedProjectRoot;
|
|
221
283
|
}
|
|
222
|
-
|
|
223
284
|
return tryFindProjectRoot();
|
|
224
285
|
}
|
|
225
286
|
|
|
226
287
|
/**
|
|
227
|
-
* Returns the applications base directory.
|
|
288
|
+
* Returns the applications base directory next to effective `config.yaml` (same root as infra, secrets, audit).
|
|
289
|
+
* Dev 0: `<configDir>/applications`; non-zero dev: `<configDir>/applications-dev-{id}`.
|
|
290
|
+
* Uses {@link getAifabrixSystemDir}, not raw {@link getAifabrixHome}, so builder-server layouts with
|
|
291
|
+
* `AIFABRIX_HOME=$HOME` and config under `~/.aifabrix/` keep apps under `.aifabrix` (not `$HOME/applications-dev-*`).
|
|
292
|
+
*
|
|
228
293
|
* @param {number|string} developerId - Developer ID
|
|
229
294
|
* @returns {string} Absolute path to applications base directory
|
|
230
295
|
*/
|
|
231
296
|
function getApplicationsBaseDir(developerId) {
|
|
232
297
|
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
233
|
-
const base =
|
|
298
|
+
const base = getAifabrixSystemDir();
|
|
234
299
|
if (idNum === 0) {
|
|
235
300
|
return path.join(base, 'applications');
|
|
236
301
|
}
|
|
@@ -249,7 +314,8 @@ function getDevDirectory(appName, developerId) {
|
|
|
249
314
|
}
|
|
250
315
|
|
|
251
316
|
/**
|
|
252
|
-
* Gets the application path (builder or integration folder)
|
|
317
|
+
* Gets the application path (builder or integration folder).
|
|
318
|
+
* Matches getBuilderPath / getIntegrationPath: respects AIFABRIX_BUILDER_DIR and project-root vs cwd base.
|
|
253
319
|
* @param {string} appName - Application name
|
|
254
320
|
* @param {string} [appType] - Application type ('external' or other)
|
|
255
321
|
* @returns {string} Absolute path to application directory
|
|
@@ -258,9 +324,10 @@ function getAppPath(appName, appType) {
|
|
|
258
324
|
if (!appName || typeof appName !== 'string') {
|
|
259
325
|
throw new Error('App name is required and must be a string');
|
|
260
326
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
327
|
+
if (appType === 'external') {
|
|
328
|
+
return getIntegrationPath(appName);
|
|
329
|
+
}
|
|
330
|
+
return path.join(getBuilderRoot(), appName);
|
|
264
331
|
}
|
|
265
332
|
|
|
266
333
|
/**
|
|
@@ -299,28 +366,45 @@ function getBuilderRoot() {
|
|
|
299
366
|
return path.join(getIntegrationBuilderBaseDir(), 'builder');
|
|
300
367
|
}
|
|
301
368
|
|
|
369
|
+
/**
|
|
370
|
+
* True when name under root is a real directory (follows symlinks). False for broken symlinks, files, ENOENT.
|
|
371
|
+
* @param {string} root - Parent directory (must exist)
|
|
372
|
+
* @param {string} name - Entry from readdir
|
|
373
|
+
* @returns {boolean}
|
|
374
|
+
*/
|
|
375
|
+
function isAppSubdirSync(root, name) {
|
|
376
|
+
if (!name || name.startsWith('.')) return false;
|
|
377
|
+
const fullPath = path.join(root, name);
|
|
378
|
+
try {
|
|
379
|
+
const st = nodeFs().statSync(fullPath);
|
|
380
|
+
return Boolean(st && typeof st.isDirectory === 'function' && st.isDirectory());
|
|
381
|
+
} catch {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
302
386
|
/**
|
|
303
387
|
* Lists app names (directories) under integration root. Excludes dot-prefixed entries.
|
|
304
388
|
* Returns [] if root does not exist.
|
|
305
389
|
* @returns {string[]} Sorted list of app directory names
|
|
306
390
|
*/
|
|
307
391
|
function listIntegrationAppNames() {
|
|
392
|
+
const disk = nodeFs();
|
|
308
393
|
const root = getIntegrationRoot();
|
|
309
|
-
if (!
|
|
394
|
+
if (!disk.existsSync(root)) {
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
397
|
+
let rootStat;
|
|
398
|
+
try {
|
|
399
|
+
rootStat = disk.statSync(root);
|
|
400
|
+
} catch {
|
|
310
401
|
return [];
|
|
311
402
|
}
|
|
312
|
-
|
|
313
|
-
if (!stat || typeof stat.isDirectory !== 'function' || !stat.isDirectory()) {
|
|
403
|
+
if (!rootStat || typeof rootStat.isDirectory !== 'function' || !rootStat.isDirectory()) {
|
|
314
404
|
return [];
|
|
315
405
|
}
|
|
316
|
-
const entries =
|
|
317
|
-
return entries
|
|
318
|
-
.filter(name => !name.startsWith('.'))
|
|
319
|
-
.filter(name => {
|
|
320
|
-
const fullPath = path.join(root, name);
|
|
321
|
-
return fs.statSync(fullPath).isDirectory();
|
|
322
|
-
})
|
|
323
|
-
.sort();
|
|
406
|
+
const entries = disk.readdirSync(root);
|
|
407
|
+
return entries.filter((name) => isAppSubdirSync(root, name)).sort();
|
|
324
408
|
}
|
|
325
409
|
|
|
326
410
|
/**
|
|
@@ -329,22 +413,22 @@ function listIntegrationAppNames() {
|
|
|
329
413
|
* @returns {string[]} Sorted list of app directory names
|
|
330
414
|
*/
|
|
331
415
|
function listBuilderAppNames() {
|
|
416
|
+
const disk = nodeFs();
|
|
332
417
|
const root = getBuilderRoot();
|
|
333
|
-
if (!
|
|
418
|
+
if (!disk.existsSync(root)) {
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
let rootStat;
|
|
422
|
+
try {
|
|
423
|
+
rootStat = disk.statSync(root);
|
|
424
|
+
} catch {
|
|
334
425
|
return [];
|
|
335
426
|
}
|
|
336
|
-
|
|
337
|
-
if (!stat || typeof stat.isDirectory !== 'function' || !stat.isDirectory()) {
|
|
427
|
+
if (!rootStat || typeof rootStat.isDirectory !== 'function' || !rootStat.isDirectory()) {
|
|
338
428
|
return [];
|
|
339
429
|
}
|
|
340
|
-
const entries =
|
|
341
|
-
return entries
|
|
342
|
-
.filter(name => !name.startsWith('.'))
|
|
343
|
-
.filter(name => {
|
|
344
|
-
const fullPath = path.join(root, name);
|
|
345
|
-
return fs.statSync(fullPath).isDirectory();
|
|
346
|
-
})
|
|
347
|
-
.sort();
|
|
430
|
+
const entries = disk.readdirSync(root);
|
|
431
|
+
return entries.filter((name) => isAppSubdirSync(root, name)).sort();
|
|
348
432
|
}
|
|
349
433
|
|
|
350
434
|
/**
|
|
@@ -387,7 +471,7 @@ function getBuilderPath(appName) {
|
|
|
387
471
|
? process.env.AIFABRIX_BUILDER_DIR.trim()
|
|
388
472
|
: null;
|
|
389
473
|
if (builderRoot) {
|
|
390
|
-
return path.join(builderRoot, appName);
|
|
474
|
+
return path.join(path.resolve(builderRoot), appName);
|
|
391
475
|
}
|
|
392
476
|
const base = getIntegrationBuilderBaseDir();
|
|
393
477
|
return path.join(base, 'builder', appName);
|
|
@@ -430,7 +514,7 @@ function getDeployJsonPath(appName, appType, preferNew = false) {
|
|
|
430
514
|
// If neither exists, return new naming (for generation)
|
|
431
515
|
return newPath;
|
|
432
516
|
}
|
|
433
|
-
const { resolveApplicationConfigPath } = require('./app-config-resolver');
|
|
517
|
+
const { resolveApplicationConfigPath, resolveRbacPath } = require('./app-config-resolver');
|
|
434
518
|
const { loadConfigFile } = require('./config-format');
|
|
435
519
|
/**
|
|
436
520
|
* Checks if app type is external from variables object
|
|
@@ -518,7 +602,7 @@ async function detectAppType(appName, _options = {}) {
|
|
|
518
602
|
|
|
519
603
|
/**
|
|
520
604
|
* Resolve-specific app path: prefer integration + env.template only (env-only mode).
|
|
521
|
-
* If integration/<
|
|
605
|
+
* If integration/<systemKey>/env.template exists, use that directory without requiring application.yaml.
|
|
522
606
|
* Otherwise fall back to detectAppType (integration or builder with full config).
|
|
523
607
|
*
|
|
524
608
|
* @param {string} appName - Application name
|
|
@@ -538,7 +622,7 @@ async function getResolveAppPath(appName) {
|
|
|
538
622
|
return { appPath: result.appPath, envOnly: false };
|
|
539
623
|
}
|
|
540
624
|
|
|
541
|
-
/** Resolve
|
|
625
|
+
/** Resolve app folder name when cwd is inside integration/<systemKey>/. */
|
|
542
626
|
function resolveIntegrationAppKeyFromCwd() {
|
|
543
627
|
const integrationNorm = path.resolve(path.join(getIntegrationBuilderBaseDir(), 'integration'));
|
|
544
628
|
const cwd = path.resolve(process.cwd());
|
|
@@ -548,7 +632,10 @@ function resolveIntegrationAppKeyFromCwd() {
|
|
|
548
632
|
|
|
549
633
|
module.exports = {
|
|
550
634
|
getAifabrixHome,
|
|
635
|
+
getAifabrixWork,
|
|
551
636
|
getConfigDirForPaths,
|
|
637
|
+
getAifabrixSystemDir,
|
|
638
|
+
getPrimaryUserSecretsLocalPath,
|
|
552
639
|
getApplicationsBaseDir,
|
|
553
640
|
getDevDirectory,
|
|
554
641
|
getAppPath,
|
|
@@ -562,6 +649,7 @@ module.exports = {
|
|
|
562
649
|
resolveBuildContext,
|
|
563
650
|
getDeployJsonPath,
|
|
564
651
|
resolveApplicationConfigPath,
|
|
652
|
+
resolveRbacPath,
|
|
565
653
|
detectAppType,
|
|
566
654
|
getResolveAppPath,
|
|
567
655
|
resolveIntegrationAppKeyFromCwd,
|