Skip to content

Generate Env Cutover

generate_env is scheduled for removal.

FractalOps will not keep a compatibility layer for:

  • generated .env bundles
  • overlay-driven env mutation
  • fallback alias chains such as pick(...)
  • duplicated FRACTALOPS_* vs legacy connector env names

The replacement strategy is a hard cutover to structured configuration.

The current env rendering path mixes:

  • topology intent
  • runtime secret references
  • host bootstrap details
  • application settings
  • IdP flow policy

into one flat string map.

That shape caused real drift in auth-plane behavior:

  • broker flow requirements lived in topology, env overlays, script defaults, and live runtime
  • fixing live Keycloak did not guarantee repo SSOT correctness
  • fallback env lookups allowed stale values to survive silently

For FractalOps, this is the wrong abstraction. Portal, auth, runtime, and operations contracts are structured systems and should be expressed as structured systems.

Use:

  • Argo CD
  • Helm values or Kustomize overlays
  • External Secrets Operator

Do not pass large application contracts through a generated .env.

Use:

  • OpenBao as secret authority
  • External Secrets Operator for cluster materialization
  • secret refs in manifests, not rendered plaintext env blobs

Use:

  • Ansible inventory
  • Ansible roles
  • explicit systemd unit/drop-in templates

Do not route host bootstrap through a repo-generated shared env file.

Application code should consume:

  • typed config files
  • mounted secrets
  • explicit manifest fields

and fail fast when required fields are missing.

Do not keep env alias fallback chains.

Use a typed schema layer for runtime intent.

Recommended:

  • CUE for topology and deployment contracts

Minimum acceptable alternative:

  • typed YAML plus strict Pydantic validation without env fallback compatibility
  • bootstrap scripts in platform/k8s/ that currently read FRACTALOPS_* env
  • platform/k8s/bootstrap_fractalops_apps.sh
  • platform/k8s/bootstrap_argocd_identity_gitops.sh
  • platform/k8s/bootstrap_daytona_penpot_argocd.sh
  • platform/k8s/bootstrap_datahub.sh
  • platform/k8s/bootstrap_headlamp.sh
  • platform/k8s/reconcile_k3s_oidc.sh

These should read from:

  • Helm values
  • Kustomize config
  • mounted secret refs

These should move to:

  • Ansible variables
  • role templates
  • explicit per-service manifests

These must stop using:

  • fallback env aliases
  • pick(...)
  • runtime string defaults for policy

These were already proven to be operationally dangerous:

  • IdP broker first-login flow requirements
  • Keycloak admin/public/base URL fallbacks
  • secret-ref promotion from one env name to another
  • host bootstrap scripts that reinterpret app config
  • bootstrap scripts that reconstruct issuer URLs from partial env state
  1. No compatibility env aliases.
  2. No dual write between manifest and rendered env.
  3. No overlay-based secret mutation for steady-state runtime.
  4. No fallback from new keys to old keys.
  5. Missing required config must fail startup.
  6. Drift checks must compare structured sources, not derived env text.
  • Stop adding new keys to render_env.py
  • Stop adding new tests to test_generate_env.py
  • Keep only safety fixes until removal

Phase 2. Move auth and secret contracts first

Section titled “Phase 2. Move auth and secret contracts first”
  • Move Keycloak, Pomerium, and OpenBao contracts to structured manifests
  • Remove broker flow policy from env rendering
  • Make secret refs first-class in deployment manifests
  • Port platform/k8s/* bootstrap scripts to Helm/Kustomize inputs
  • Remove shared env generation from cluster deployment steps
  • Replace ops/lxc/* env-driven reconciliation with Ansible variables and roles
  • Keep repo topology as source input, but render directly to host-specific config files
  • Replace env alias reads in app/runtime code with typed config inputs only
  • Delete pick(...)-style compatibility resolution in runtime support paths
  • delete render_env.py
  • delete runtime_contract_render_env CLI entry
  • delete test_generate_env.py
  • delete env overlay docs and samples that only exist for generated runtime contracts
  • ops/infra/apply_ssot_profile.py must stop invoking runtime env rendering
  • Makefile targets that depend on ops/infra/env/lab.secrets.env must change
  • ops/lxc/deploy_to_ct.sh and ops/lxc/remediate_from_topology.sh will no longer accept generated env overlays as the primary control path
  • app startup will reject missing structured config instead of silently falling back

The cutover is complete only when all of the following are true:

  • no deployment path requires render_env.py
  • no bootstrap path requires ops/infra/env/*.env
  • no runtime path depends on env fallback aliases
  • secrets are materialized through OpenBao refs and target-native delivery
  • Kubernetes config is expressed in Helm/Kustomize inputs
  • host/LXC config is expressed in Ansible vars/templates
  • test_generate_env.py is deleted
  1. Remove apply_ssot_profile -> runtime_contract_render_env from the deployment path.
  2. Move IdP and OpenBao settings into a structured deployment contract.
  3. Replace ops/lxc/remediate_from_topology.sh env reads with manifest or Ansible vars.
  4. Delete fallback alias logic in native_ops_runtime_support.py after consumers switch.