Project variables
Project variables are named values — plain variables or encrypted secrets — that ActionSet commands and scripts reference via ${{ VAR_NAME }} placeholders. They keep environment-specific values (service names, paths, passphrases) out of the ActionSets themselves, so one ActionSet works across projects. Managed at Settings → Variables (project-scoped; requires the project selector).
What they are
| Property | Behaviour |
|---|---|
| Name | A–Z, 0–9, _; must start with a letter or underscore; max 128 chars. The form auto-uppercases input. Immutable after creation. |
| Value | Free text. For secrets, the value is write-only — editing shows an empty field; leave it empty to keep the current value. |
| Secret flag | Set at creation, cannot be changed afterwards. Secret values are envelope-encrypted (AES-256-GCM DEK wrapped by the KEK, kek_version tracked) and are never returned by the API — the list shows ••••••. Plain variable values are stored and displayed in cleartext. |
| Scope | Per project. Variables belong to exactly one project and resolve only for distributions in that project. |
| Description | Optional, max 1024 chars. |
Roles: anyone with project access can list variables (secret values excluded); create, update, and delete require project admin.
Placeholder syntax
Reference a variable anywhere in an ActionSet's commands or inline script:
systemctl restart ${{ SERVICE_NAME }}
openssl pkcs12 -export -passout pass:${{ P12_PASSPHRASE }} ...
- The copy button next to each variable name on the page copies the ready-to-paste
${{ NAME }}placeholder. - To emit a literal
${{ ... }}(not substituted), escape it with a backslash:\${{ NAME }}. An odd number of backslashes before${escapes the placeholder; an even number substitutes. - A placeholder that doesn't resolve to an existing variable fails the distribution with
unresolved variable placeholders: NAME1, NAME2, ...— all missing names are reported at once.
How values are injected
Resolution happens at distribution time, on the server, per project:
- All project variables are loaded; secret values are decrypted in memory.
- Every value is escaped for the target shell before substitution:
- SSH (Linux) — single-quoted for bash; embedded quotes are escaped. Values are inert strings: a value like
$(rm -rf /)is passed literally, never expanded or executed. - WinRM (Windows) — PowerShell single-quoted (
'doubled). Same guarantee: no variable expansion, sub-expressions, or backtick processing.
- SSH (Linux) — single-quoted for bash; embedded quotes are escaped. Values are inert strings: a value like
- The escaped value replaces the placeholder in each command / script line.
Because escaping wraps the value in quotes for you, write placeholders bare — pass:${{ P12_PASSPHRASE }}, not pass:'${{ P12_PASSPHRASE }}'.
Logs record only that substitution happened and in how many commands — never the variable names or values.
Linting ActionSets
Before running a distribution you can check that every placeholder resolves:
GET /projects/:projectId/action-sets/:id/variables— lint a saved ActionSet.POST /projects/:projectId/action-sets/variables/lint— lint an ActionSet body before saving (used by the ActionSet editor).
Both return referenced (all placeholders found), missing (referenced but not defined in the project), and available (defined variables with their is_secret flag). Fix missing entries before executing — they fail at runtime.
Examples
| Variable | Type | Used as |
|---|---|---|
SERVICE_NAME | variable | systemctl reload ${{ SERVICE_NAME }} in a Linux ActionSet |
P12_PASSPHRASE | secret | -passout pass:${{ P12_PASSPHRASE }} when re-exporting PKCS#12 |
JKS_STOREPASS | secret | keytool -importkeystore ... -deststorepass ${{ JKS_STOREPASS }} in a WinRM ActionSet |
APP_CONFIG_DIR | variable | Copy-Item ${{ APP_CONFIG_DIR }}\cert.pem ... |
Security notes
- Plain (non-secret) variable values are visible to every user with project access — use the secret flag for anything sensitive. The flag cannot be added later; recreate the variable if in doubt.
- Secrets are decrypted only during distribution execution and only on the server; they still end up in the remote command line on the target host. Anything a target host can log (e.g. shell history, process listings) can expose them there — treat target hosts accordingly.
- Deleting a variable that ActionSets still reference does not warn at delete time; the next distribution run fails with an unresolved-placeholder error. Lint after cleanup.