Skip to content

[Feature] Environment variables and promotion (dev/staging/prod) #126

Description

@michaelmcnees

Problem

Workflows need a way to parameterize configuration across environments (dev/staging/prod) without duplicating the workflow definition. Currently, the same workflow targeting different environments requires either:

  • Separate workflow files with duplicated step logic, or
  • Manual --input overrides on every mantle run invocation

Actual behavior: Each environment needs manual input overrides at run time or separate workflow files.

Expected behavior: A values file (or named environment) can be associated with a workflow run, supplying environment-specific inputs and env overrides — similar to Helm --values or Terraform .tfvars files.

Root Cause Analysis

The engine already supports a complete parameterization model via workflow inputs and env variables, both accessible in CEL expressions. What's missing is:

  1. A values-file loader — a mechanism to supply input overrides from a YAML file at run/plan time, rather than requiring every key to be passed as individual --input flags.
  2. Named stored environments — a first-class resource (stored in the database like credentials) that associates a name (e.g. production) with a set of input defaults and env overrides, enabling mantle run workflow --env production without a file on disk.
  3. CLI integration--values <file> and --env <name> flags on mantle run, mantle plan, and mantle apply.

The layered override order that needs to be enforced is:
named environment < values file < inline --input flags

TDD Fix Plan

Phase 1 — Values file (--values)

  1. RED: Write a test that loading a well-formed values YAML file returns a Values struct with the declared inputs and env overrides.
    GREEN: Add a Values type with Inputs map[string]any and Env map[string]string fields and a LoadValues(path string) (*Values, error) function in the workflow package.

  2. RED: Write a test that LoadValues returns a descriptive error when the file is missing, malformed YAML, or contains unknown top-level keys.
    GREEN: Add validation in LoadValues that checks for unknown keys and wraps file/YAML errors with context.

  3. RED: Write a test that merging a values file with inline --input flags applies the correct precedence: inline flags override values-file inputs; values-file inputs override workflow-level default values.
    GREEN: Add a MergeInputs(workflowDefaults, valuesInputs, inlineInputs map[string]any) map[string]any helper and wire it into the run command's input-assembly path.

  4. RED: Write a test that env overrides from a values file are surfaced in the CEL env variable during step execution.
    GREEN: Extend the Evaluator.SetConfigEnv call path (or add SetValuesEnv) to layer values-file env overrides on top of config env but below MANTLE_ENV_* OS vars.

  5. RED: Write an integration test (testcontainers) that mantle run <workflow> --values prod.values.yaml executes steps with input and env values from the file.
    GREEN: Wire --values flag into the run CLI command, load the values file, merge inputs and env, and pass them through to the engine.

Phase 2 — Named stored environments (--env)

  1. RED: Write a test that creating an environment stores its name, inputs, and env overrides in the database scoped to a team, and that loading it by name retrieves the same data.
    GREEN: Add an environments table (migration), an EnvironmentStore with Create, Get, List, and Delete, and a mantle env create subcommand that reads from a values file.

  2. RED: Write a test that mantle run <workflow> --env staging resolves the staging environment from the store and applies its inputs/env with the same override precedence as a values file.
    GREEN: Wire --env <name> into the run command, resolve the environment from the store, and reuse the same merge helper from Phase 1.

  3. RED: Write a test that mantle plan <workflow> --env production reports the diff between the workflow's current applied state and what would be executed with the given environment's overrides.
    GREEN: Thread the environment/values resolution through the plan command using the same merge helper.

REFACTOR: Extract the input-merge and env-layer logic into a shared resolution package so run, plan, and future commands share a single, tested override stack.

Acceptance Criteria

  • mantle run <workflow> --values <file> accepts a YAML values file with inputs: and env: keys
  • mantle env create <name> --from <file> stores a named environment
  • mantle run <workflow> --env <name> resolves a stored environment
  • Override precedence: MANTLE_ENV_* OS vars > --input flags > values file / named env > workflow default values > config env
  • Errors on missing/malformed values files are descriptive and actionable
  • All new behavior covered by unit tests and at least one integration test
  • Existing tests still pass

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions