Vetrix Docs

Pipeline variables (environment-configuration)

Audience: operators configuring per-branch CI/CD variables for a repo via Pipelines → Environment configuration (/<owner>/<repo>/pipelines/environment-configuration).

Per-branch pipeline variables let you inject values into pipeline jobs without hardcoding them in the committed vetrix-ci.yml — e.g. an environment-specific base URL, a token, or any value that must differ between branches/stacks. Values are stored encrypted (AES-256-GCM) in the branch-tier secrets store and are masked from job logs.


Prerequisite: the worker must be able to inject them

A worker only injects these variables when it is wired with the branch-variable resolver AND has the decryption key. Until both are true, variables saved on the environment-configuration page are stored correctly but never reach jobs — jobs run with the committed vetrix-ci.yml values only.

Two requirements on every worker that should inject pipeline variables:

  1. Resolver wiring — the worker process resolves and overlays per-branch variables onto each job. (Tracked under Epic Pipeline variables via environment-configuration; verify your worker build includes it.)
  2. SECRET_ENC_KEY — see below.

A worker missing SECRET_ENC_KEY logs a clear line at startup (branch pipeline variables disabled: SECRET_ENC_KEY not set) and runs normally with committed-YAML values only. This is intentional fail-open behaviour: a missing key must never stop the worker from running jobs.

SECRET_ENC_KEY on the worker

The worker decrypts pipeline variables itself, so it needs the same SECRET_ENC_KEY the server uses to seal them (a 64-character hex string = 32 bytes). It must match the server's key, or decryption fails.

# worker service (e.g. appmerc_vetrixworker) in the deployment compose
environment:
  - SECRET_ENC_KEY=${SECRET_ENC_KEY}     # same value as the server; env-only
  • Env-only. Never put SECRET_ENC_KEY (or DATABASE_URL, JWT_SECRET) in a committed config file.
  • Trust implication. Giving the worker this key lets it decrypt any secret sealed with it, not just pipeline-variable values. The worker is already a trusted node (it holds JWT_SECRET and drives the host Docker socket), so this is consistent — but treat the worker host as in-scope for secret material and restrict access accordingly.

Setting a variable

Web UI

Pipelines → Environment configuration → Add variable. Provide the branch, the name (POSIX env-var shape: a leading letter/underscore, then letters/digits/underscores), and the value. Values are write-only — the UI never displays a stored value, ciphertext, or nonce again; rotate to change it.

API

# Create (ci:write). Body carries `value`; no response ever echoes it back.
curl -X POST "https://api.gitvetrix.com/api/v1/repos/<owner>/<repo>/pipelines/variables" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -H "X-Vetrix-Scope: api.write" \
  -d '{"branch":"develop","name":"E2E_BASE_URL","value":"https://www.gitvetrix.com"}'

# List metadata for a branch (ci:read) — names only, never values.
curl "https://api.gitvetrix.com/api/v1/repos/<owner>/<repo>/pipelines/variables?branch=develop" \
  -H "Authorization: Bearer <token>"

PUT /pipelines/variables/{id} rotates a value; DELETE /pipelines/variables/{id} removes one. Values are capped at 64 KiB; names must match the env-var pattern or the request is rejected with 400.

Referencing the variable from vetrix-ci.yml

Reference it as a shell-style $NAME in a job's variables: block. A per-branch variable overrides a committed-YAML value of the same name:

a11y-gate:
  variables:
    E2E_BASE_URL: "$E2E_BASE_URL"     # resolved from the env-config value for the branch

Resolution precedence (lowest → highest): worker-host process env → committed vetrix-ci.yml job variables → per-branch environment-configuration variable. So a branch variable wins on a name clash.


Security behaviour

  • Fork-PR exclusion. Per-branch (and environment) variables are never materialised for fork-originated PR runs. A fork PR sees only the committed YAML.
  • Always masked in logs. Every per-branch variable value is redacted from job logs, regardless of any secret: flag. This covers genuine secrets — but note it also masks non-secret values: e.g. an E2E_BASE_URL will appear as *** in the job log (waiting for stack at ***/privacy). That is expected.
  • Audited. Each successful decrypt during a job emits a secret.accessed audit event scoped to the variable, so you can answer "which runs read variable X".
  • Encrypted at rest. Values are sealed with AES-256-GCM under SECRET_ENC_KEY; the store never returns plaintext, ciphertext, or nonce over the API.

Worked example: per-environment base URL for the e2e/a11y jobs

The live-stack e2e/a11y jobs (a11y-gate, web-a11y-e2e, repositories-landing-responsive, security-scannerfix-cross-browser, slow-chromium-e2e) must target a different stack per environment. Instead of hardcoding https://www.gitvetrix.test in vetrix-ci.yml, reference $E2E_BASE_URL/$A11Y_BASE_URL and set the value per branch:

Stack Branch(es) E2E_BASE_URL
prod develop/master/staging https://www.gitvetrix.com
dev develop/master/staging https://www.gitvetrix.test

Set these on the worker/instance that serves each stack. A prod worker reads the prod repo's env-config values; a dev worker reads the dev repo's.

Reachability caveat: the job container must be able to reach the URL. The dev .test host only routes inside the dev bridge network; gitvetrix.com is public. Confirm a prod job container can reach https://www.gitvetrix.com/privacy (the bootstrap health path) before relying on it — if it cannot, the job-container egress needs network work independent of this variable.


Verification

# 1. Worker has the key and wired the resolver:
docker compose logs appmerc_vetrixworker | grep -i "branch pipeline variables"
#    (absence of the "disabled: SECRET_ENC_KEY not set" line + a normal boot = wired)

# 2. Set a branch variable, then trigger a pipeline on that branch and confirm the
#    job behaves as if the value were present (the value itself is masked as *** in logs).

See also: runners.md (runner deployment) and worker-docker-socket.md (worker Docker-socket access).