Known Issues

Rough edges you will run into sooner or later. This page is intentionally short; ongoing work goes into the project’s issue tracker, not here.

TTL cleanup is not automatic

Cleanup-Environments must be triggered manually or wired to a Jenkins cron trigger. The library does not schedule it. If no one runs it, envs with expired TTL stay on disk and continue consuming runner capacity.

Workaround: add a time-based trigger (triggers { cron('H 4 * * *') }) to the Cleanup-Environments job, or schedule it via the multibranch / organisation folder pipeline that owns it.

Cycle detection warns but does not block

createEnvStep runs DFS cycle detection over the effective depends_on graph. On a cycle it prints a warning and continues; Compose itself refuses to start on circular depends_on.

Workaround: treat the warning as a build error. The small window where a cycle is desirable (because service_healthy breaks it) is rare — inspect the warning explicitly when it fires.

Agent capabilities not validated

deployEnvStep assumes every online non-master agent has:

  • Docker Engine reachable by the jenkins user.

  • Docker Compose V2 (docker compose, not docker-compose).

  • /opt/qa-envs/ (or the value of QA_AGENT_ENVS_DIR) writable by jenkins.

  • yq, ss, rsync installed.

There is no pre-flight check. A missing tool produces a failure deep inside docker compose up -d or the port-scan step.

Workaround: include a one-liner check in agent provisioning (yq --version && docker compose version).

Active Choices fallback hides approval errors

Scripts that are not yet approved in Manage Jenkins → In-process Script Approval render the fallback HTML silently. There is no banner, no console message, no System Log line unless you filter on ScriptApproval.

Workaround: always check approval first when a panel suddenly shows the fallback.

Re-running a failed create leaves artifacts

If createEnvStep fails after meta.json is written (rare, but possible during a docker compose build crash), the env directory stays behind in state configured with status: failed. The name is then reserved and utils.validateEnvName(…​, checkExists=true) rejects it.

Workaround: Manage-Environment → delete on the failed env, or remove ${MASTER_ENVS_DIR}/<env> manually.

DATA_FOLDER must be a relative path

Compose bind mounts expand ${DATA_FOLDER:-.} relative to the docker-compose.yml. Setting DATA_FOLDER=/opt/qa-envs/foo via the Active Choices form works but silently duplicates the absolute path for every bind mount and breaks on the runner if the master ever renders a path that does not exist there.

Workaround: leave DATA_FOLDER unset unless you have a specific reason. The default (the env’s own directory) is almost always right.

Concurrent manage-owners races are possible

atomicWriteMeta protects against torn reads, not against two admins submitting manage-owners at the same second. The last submission wins.

Workaround: manage-owners is low-frequency by nature; if it matters, coordinate on Slack or gate the action behind a Jenkins lock.

SERVICE_VARIABLES values are visible on the build’s Parameters page

SERVICE_VARIABLES is a real build parameter, so the submitted JSON is stored in the build’s ParametersAction and rendered in plain text on the Parameters page. utils.maskSensitiveValues protects the console and .qa-build.log, not that page. This affects every service variable routed through the form, keystore passwords included.

Workaround: treat anything entered there as visible to everyone who can read the job. Use QA fixtures, never a production secret, and rotate the value afterwards if it ever mattered.

A per-service .env fix never reaches an existing environment

updateEnvStep bootstraps <env>/<svc>/.env from the shared-lib template only when the file is absent, and Update-Environment regenerates docker-compose.yml but not the per-service .env files. A corrected template — for example the DEV-2849 change of HTTP_PORT to 8080 and SERVER_SSL_ENABLED to SSL_ENABLED in ft-qoe-web — therefore applies to newly created environments only. Existing ones keep the old values indefinitely, through any number of Update and Deploy runs.

Workaround: edit <env>/ft-qoe-web/.env on the master by hand, or delete that file and run Update-Environment so the template is laid down again (this discards the env’s other customisations in that file), or re-create the environment.

An environment created before DEV-2849 still carries SERVER_SSL_ENABLED in <env>/ft-qoe-web/.env. That key turns TLS on, but the session cookie’s Secure flag is bound to SSL_ENABLED alone — so with SSL enabled the cookie is issued without it and can travel over the published plain-HTTP fallback port.

Workaround: rename the key to SSL_ENABLED in that file (see the previous entry for how a per-service .env is updated). New environments are unaffected.

Empty debug-port mappings publish on a random host port

ftacs and ui-backend carry - "${DEBUG_PORT_FTACS:-}:5005" / - "${DEBUG_PORT_UI_BACKEND:-}:5005". With the variable unset the entry renders as ":5005", whose empty host part Compose reads as "publish on an ephemeral host port" rather than as an error. Nothing listens on 5005 today because no image in the stack starts a JDWP agent by default, so the mapping forwards to a closed port — but DEBUG_PORT is operator-editable through the service-variables form, and the images' debug behaviour is not verified from this repository.

Workaround: leave the debug variables unset unless you are actively debugging; when you are, set DEBUG_PORT_FTACS / DEBUG_PORT_UI_BACKEND explicitly so the binding is known, and clear them again afterwards.

Portals /nginx_status is world-readable by default

The portals image’s own nginx.conf hardcodes allow 127.0.0.1, allow 10.0.0.0/8 and allow 172.16.0.0/12, then allow ${METRICS_ALLOW_IP}; deny all;. resources/services/portals/.env sets METRICS_ALLOW_IP=0.0.0.0/0, which makes /nginx_status world-readable on the published portals HTTP and HTTPS ports — including over IPv6 DNAT on an IPv6-enabled agent, where a host firewall covering IPv4 only does not apply. This is the behaviour QA environments had before DEV-3218; the key was previously unset and the image’s own default is the same 0.0.0.0/0, so the entry now states it explicitly rather than changing it.

Workaround: set METRICS_ALLOW_IP=127.0.0.1 in <env>/portals/.env (any value other than 0.0.0.0/0 closes it) and redeploy. Prometheus scraping from another agent then needs that agent’s CIDR instead.

The DEV-3218 portals .env fix reaches new environments only

resources/services/portals/.env gained FT_UI_BACKEND_URL, FT_AI_AGENT_URL, FT_GRAFANA_API_URL, METRICS_ALLOW_IP, FT_BRANDING_DIR and FT_COMPANY_NAME, and lost the dead FT_UI_HOST plus the two inert host-port keys. Like every per-service .env change it lands at create time only — see the entry above on why Update and Deploy never overwrite an existing file.

Workaround: copy resources/services/portals/.env into <env>/portals/ on the master, then run Deploy-Environment with RESET_CONFIGS so the agent copy is replaced rather than skipped by the rsync --ignore-existing. Re-apply any per-env customisation afterwards.

Operator pre-sync step before syncSharedLibStep

The Jenkins master’s shared-lib copy at /var/jenkins_home/qa-data/shared-lib/resources/services/portals/.env carries an uncommitted hand edit (it already had FT_COMPANY_NAME and FT_BRANDING_DIR in portals/.env, which no git object in this repository contains). Syncing the repository over it would silently drop whatever else that edit added.

Diff the master copy against the new repository file first, fold anything genuinely needed into git, and only then run syncSharedLibStep.