Per-Repo Overrides (vartrack.json)¶
Individual repositories can override a subset of their central rule configuration without touching config.cue. Place a vartrack.json file in the repository and varTrack will apply its settings on top of the matching rule whenever a webhook is received — the third of the layers a rule is built from, after config.cue and the tenant's bundle.json.
Check it in CI
vt validate-config finds the repository's vartrack.json and checks it the way a sync reads it; it exits 1 on errors or warnings. See CI/CD integration.
Where the file lives¶
varTrack reads the first of these it finds at the pushed ref:
vartrack.json.github/vartrack.json.gitea/vartrack.json.gitlab/vartrack.json
The file is read at the pushed commit, so each branch can carry its own — main and develop can override differently.
How it works¶
When a push webhook arrives, the ETL pipeline:
- Resolves the rule: the one in
config.cue, with the tenant'sbundle.jsonrule laid over it (Stage 1 — Payload) - Fetches
vartrack.jsonfrom the repository at the pushed commit ref, and resolves the presets itextends - Merges the overridable keys from
vartrack.jsoninto the rule:branch_map,file_path_map,variables_mapandprunekey by key, the others replaced - Applies the
config.cuerule'sforcekeys, which win overvartrack.json - Runs ETL and Sync with the merged settings (Stages 2 and 3)
A vartrack.json can change which file a rule reads or where its environments come from, but cannot be the only place that names them: a rule whose config.cue and tenant bundle.json give no file_name or file_path_map (or no environment strategy) is refused when it is loaded, before any repository's file is read.
If vartrack.json is absent or empty, the central rule is used unchanged. If it is there but cannot be used — not valid JSON, not a JSON object, extending a preset that cannot be read, or setting a sync_mode that is not a mode — the sync fails with that error: it does not go ahead without settings the repository asked for, such as a branch_map. The schema registry is never affected by per-repo overrides.
Example¶
{
"root_key": "app_config",
"branch_map": {
"main": "production",
"staging": "staging",
"develop": "develop"
},
"prune": true,
"sync_mode": "GIT_UPSERT_ALL"
}
Shared settings can come from presets — here a preset in the org's presets repository, then a key of the repository's own:
Place this file at the root of the repository (next to your config file):
my-repo/
├── vartrack.json ← per-repo overrides
└── configs/
└── app.yaml ← your config file (watched by the central rule)
Overridable keys¶
These keys can be set in vartrack.json; what each does, its type, and how it combines with the other layers is in Rule options:
branch_as_envbranch_mapfile_namefile_path_mappr_as_envpruneroot_keystrict_validationsync_modetag_as_envvariables_map
branch_map, file_path_map, variables_map and prune are merged with the rule's key by key — a branch set here is added, and prune.protection patterns are added to the rule's, never replace them. The others replace the rule's value.
Security model¶
Infrastructure and security-critical keys are always taken from the central bundle and cannot be changed by the repository:
platform,datasource,repo_urltoken,secret_manager,secret_managersrepositories,exclude_repositoriesself_healand all Celery wiring keys
Any key in vartrack.json that is not in the overridable list above is silently ignored and logged at INFO level.
The tenant is not a setting at all: it is the tenant that owns the pushed repository, and no key in vartrack.json names it (vt validate-config reports one as an error).
A key the config.cue rule lists under force cannot be overridden either: force is applied after vartrack.json. For example, force: {prune: {enabled: false}} keeps a production rule from pruning whatever a repository asks for.
Interaction with the schema registry¶
vartrack.json has no effect on CUE schema validation. The schema used to validate your config file is always sourced from the tenant's schema registry (configured in config.cue under schema_registry). Per-repo overrides cannot change which schema is applied or bypass validation.
Troubleshooting¶
Override not applied — Check the orchestrator logs for:
This means the file was not found at the repo root for that commit ref.Keys ignored — If you see:
Those keys are infrastructure-level and cannot be overridden from the repo.Preset not found — A preset in extends that cannot be read fails the sync with:
vartrack.json in https://...: preset local>my-org/presets:nope: no nope.json at main in my-org/presets
Invalid JSON — A parse error fails the sync with:
Fix the file and push again; the sync runs with it.Unknown sync mode — A sync_mode that is not AUTO, GIT_UPSERT_ALL or GIT_SMART_REPAIR (by short name or SYNC_MODE_ name) fails the sync with:
vartrack.json in https://...: sync_mode "FAST" is not a mode: use AUTO, GIT_UPSERT_ALL or GIT_SMART_REPAIR
AUTO. vt validate-config reports the same sentence.